Fix vconf timing issue
[platform/core/connectivity/net-config.git] / src / wifi-state.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2012-2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
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
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18  */
19
20 #include <vconf.h>
21 #include <vconf-keys.h>
22
23 #include "log.h"
24 #include "util.h"
25 #include "netdbus.h"
26 #include "network-state.h"
27 #include "network-statistics.h"
28 #include "wifi-state.h"
29 #include "wifi-indicator.h"
30 #include "wifi-background-scan.h"
31
32 static int profiles_count = 0;
33
34 static enum netconfig_wifi_service_state
35         wifi_service_state = NETCONFIG_WIFI_UNKNOWN;
36
37 static GSList *notifier_list = NULL;
38
39
40 static void __netconfig_wifi_set_profiles_count(const int count)
41 {
42         profiles_count = count;
43 }
44
45 static int __netconfig_wifi_get_profiles_count(void)
46 {
47         return profiles_count;
48 }
49
50 static void __netconfig_wifi_set_essid(void)
51 {
52         const char *essid_name = NULL;
53         const char *wifi_profile = netconfig_get_default_profile();
54
55         if (netconfig_wifi_state_get_service_state() != NETCONFIG_WIFI_CONNECTED)
56                 return;
57
58         if (wifi_profile == NULL ||
59                         netconfig_is_wifi_profile(wifi_profile) != TRUE) {
60                 ERR("Can't get Wi-Fi profile");
61                 return;
62         }
63
64         essid_name = netconfig_wifi_get_connected_essid(wifi_profile);
65         if (essid_name == NULL) {
66                 ERR("Can't get Wi-Fi name");
67                 return;
68         }
69
70         vconf_set_str(VCONFKEY_WIFI_CONNECTED_AP_NAME, essid_name);
71 }
72
73 static void __netconfig_wifi_unset_essid(void)
74 {
75         vconf_set_str(VCONFKEY_WIFI_CONNECTED_AP_NAME, "");
76 }
77
78 static GSList *__netconfig_wifi_state_get_service_profiles(DBusMessage *message)
79 {
80         GSList *service_profiles = NULL;
81         DBusMessageIter iter, dict;
82
83         dbus_message_iter_init(message, &iter);
84         dbus_message_iter_recurse(&iter, &dict);
85
86         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_STRUCT) {
87                 DBusMessageIter entry;
88                 const char *object_path = NULL;
89
90                 dbus_message_iter_recurse(&dict, &entry);
91                 dbus_message_iter_get_basic(&entry, &object_path);
92
93                 if (object_path == NULL) {
94                         dbus_message_iter_next(&dict);
95                         continue;
96                 }
97
98                 if (netconfig_is_wifi_profile(object_path) == TRUE)
99                         service_profiles = g_slist_append(service_profiles,
100                                         g_strdup(object_path));
101
102                 dbus_message_iter_next(&dict);
103         }
104
105         return service_profiles;
106 }
107
108 static char *__netconfig_wifi_get_connman_favorite_service(void)
109 {
110         char *favorite_service = NULL;
111         DBusMessage *message = NULL;
112         GSList *service_profiles = NULL;
113         GSList *list = NULL;
114
115         message = netconfig_invoke_dbus_method(CONNMAN_SERVICE,
116                         CONNMAN_MANAGER_PATH, CONNMAN_MANAGER_INTERFACE,
117                         "GetServices", NULL);
118         if (message == NULL) {
119                 ERR("Failed to get service list");
120                 return NULL;
121         }
122
123         /* Get service profiles from ConnMan Manager */
124         service_profiles = __netconfig_wifi_state_get_service_profiles(message);
125         dbus_message_unref(message);
126
127         for (list = service_profiles; list != NULL; list = list->next) {
128                 char *profile_path = list->data;
129                 DBusMessageIter iter, array;
130
131                 if (favorite_service != NULL)
132                         break;
133
134                 message = netconfig_invoke_dbus_method(CONNMAN_SERVICE,
135                                 profile_path, CONNMAN_SERVICE_INTERFACE, "GetProperties", NULL);
136
137                 if (message == NULL) {
138                         ERR("Failed to get service information of %s", profile_path);
139                         continue;
140                 }
141
142                 dbus_message_iter_init(message, &iter);
143                 dbus_message_iter_recurse(&iter, &array);
144
145                 while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
146                         DBusMessageIter entry, variant;
147                         const char *key = NULL;
148                         dbus_bool_t value;
149
150                         dbus_message_iter_recurse(&array, &entry);
151                         dbus_message_iter_get_basic(&entry, &key);
152
153                         dbus_message_iter_next(&entry);
154                         dbus_message_iter_recurse(&entry, &variant);
155
156                         if (g_str_equal(key, "Favorite") != TRUE) {
157                                 dbus_message_iter_next(&array);
158                                 continue;
159                         }
160
161                         dbus_message_iter_get_basic(&variant, &value);
162
163                         if (value)
164                                 favorite_service = g_strdup(profile_path);
165
166                         break;
167                 }
168
169                 dbus_message_unref(message);
170         }
171
172         g_slist_free(service_profiles);
173
174         return favorite_service;
175 }
176
177 static void __netconfig_wifi_state_changed(
178                 enum netconfig_wifi_service_state state)
179 {
180         GSList *list;
181
182         for (list = notifier_list; list; list = list->next) {
183                 struct netconfig_wifi_state_notifier *notifier = list->data;
184
185                 if (notifier->netconfig_wifi_state_changed != NULL)
186                         notifier->netconfig_wifi_state_changed(state, notifier->user_data);
187         }
188 }
189
190 void netconfig_wifi_state_set_service_state(
191                 enum netconfig_wifi_service_state new_state)
192 {
193         enum netconfig_wifi_service_state old_state = wifi_service_state;
194
195         if (old_state == new_state)
196                 return;
197
198         wifi_service_state = new_state;
199         DBG("Wi-Fi state %d ==> %d", old_state, new_state);
200
201         if (new_state == NETCONFIG_WIFI_CONNECTED) {
202                 netconfig_del_wifi_found_notification();
203
204                 vconf_set_int(VCONFKEY_WIFI_STATE, VCONFKEY_WIFI_CONNECTED);
205                 vconf_set_int(VCONFKEY_NETWORK_WIFI_STATE, VCONFKEY_NETWORK_WIFI_CONNECTED);
206
207                 __netconfig_wifi_set_essid();
208
209                 netconfig_wifi_indicator_start();
210         } else if (old_state == NETCONFIG_WIFI_CONNECTED) {
211                 vconf_set_int (VCONFKEY_WIFI_STATE, VCONFKEY_WIFI_UNCONNECTED);
212                 vconf_set_int(VCONFKEY_NETWORK_WIFI_STATE, VCONFKEY_NETWORK_WIFI_NOT_CONNECTED);
213
214                 __netconfig_wifi_unset_essid();
215
216                 netconfig_wifi_indicator_stop();
217         }
218
219         __netconfig_wifi_state_changed(new_state);
220 }
221
222 enum netconfig_wifi_service_state
223 netconfig_wifi_state_get_service_state(void)
224 {
225         return wifi_service_state;
226 }
227
228 enum netconfig_wifi_tech_state netconfig_wifi_get_technology_state(void)
229 {
230         DBusMessage *message = NULL;
231         DBusMessageIter iter, array;
232         enum netconfig_wifi_tech_state ret = NETCONFIG_WIFI_TECH_OFF;
233         gboolean wifi_tech_powered = FALSE;
234         gboolean wifi_tech_connected = FALSE;
235
236         message = netconfig_invoke_dbus_method(CONNMAN_SERVICE,
237                         CONNMAN_MANAGER_PATH, CONNMAN_MANAGER_INTERFACE,
238                         "GetTechnologies", NULL);
239         if (message == NULL) {
240                 ERR("Failed to get Wi-Fi technology state");
241                 return NETCONFIG_WIFI_TECH_UNKNOWN;
242         }
243
244         dbus_message_iter_init(message, &iter);
245         dbus_message_iter_recurse(&iter, &array);
246
247         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
248                 DBusMessageIter entry, dict;
249                 const char *path;
250
251                 dbus_message_iter_recurse(&array, &entry);
252                 dbus_message_iter_get_basic(&entry, &path);
253
254                 dbus_message_iter_next(&entry);
255                 dbus_message_iter_recurse(&entry, &dict);
256
257                 if (path == NULL ||
258                         g_str_equal(path, CONNMAN_WIFI_TECHNOLOGY_PREFIX) == FALSE) {
259                         dbus_message_iter_next(&array);
260                         continue;
261                 }
262
263                 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
264                         DBusMessageIter entry1, value1;
265                         const char *key, *sdata;
266                         dbus_bool_t data;
267
268                         dbus_message_iter_recurse(&dict, &entry1);
269                         dbus_message_iter_get_basic(&entry1, &key);
270
271                         dbus_message_iter_next(&entry1);
272                         dbus_message_iter_recurse(&entry1, &value1);
273
274                         if (dbus_message_iter_get_arg_type(&value1) ==
275                                         DBUS_TYPE_BOOLEAN) {
276                                 dbus_message_iter_get_basic(&value1, &data);
277                                 DBG("key-[%s] - %s", key, data ? "True" : "False");
278
279                                 if (strcmp(key, "Powered") == 0 && data) {
280                                         wifi_tech_powered = TRUE;
281                                 } else if (strcmp(key, "Connected") == 0 && data) {
282                                         wifi_tech_connected = TRUE;
283                                 } else if (strcmp(key, "Tethering") == 0 && data) {
284                                         /* For further use */
285                                 }
286                         } else if (dbus_message_iter_get_arg_type(&value1) ==
287                                         DBUS_TYPE_STRING) {
288                                 dbus_message_iter_get_basic(&value1, &sdata);
289                                 DBG("%s", sdata);
290                         }
291                         dbus_message_iter_next(&dict);
292                 }
293
294                 dbus_message_iter_next(&array);
295         }
296
297         dbus_message_unref(message);
298
299         if (wifi_tech_powered)
300                 ret = NETCONFIG_WIFI_TECH_POWERED;
301
302         if (wifi_tech_connected)
303                 ret = NETCONFIG_WIFI_TECH_CONNECTED;
304
305         return ret;
306 }
307
308 void netconfig_wifi_update_power_state(gboolean powered)
309 {
310         int wifi_state = 0;
311
312         /* It's automatically updated by signal-handler
313          * DO NOT update manually
314          * It includes Wi-Fi state configuration
315          */
316         vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
317
318         if (powered == TRUE) {
319                 if (wifi_state == VCONFKEY_WIFI_OFF &&
320                                 netconfig_is_wifi_direct_on() != TRUE &&
321                                 netconfig_is_wifi_tethering_on() != TRUE) {
322                         DBG("Wi-Fi successfully turned on or waken up from power-save mode");
323
324                         vconf_set_int(VCONFKEY_NETWORK_WIFI_STATE, VCONFKEY_NETWORK_WIFI_NOT_CONNECTED);
325                         vconf_set_int(VCONF_WIFI_LAST_POWER_STATE, WIFI_POWER_ON);
326                         vconf_set_int(VCONFKEY_WIFI_STATE, VCONFKEY_WIFI_UNCONNECTED);
327
328                         netconfig_wifi_notify_power_completed(TRUE);
329
330                         netconfig_wifi_device_picker_service_start();
331
332                         netconfig_wifi_bgscan_start();
333                 }
334         } else {
335                 if (wifi_state != VCONFKEY_WIFI_OFF) {
336                         DBG("Wi-Fi successfully turned off or in power-save mode");
337
338                         netconfig_wifi_device_picker_service_stop();
339
340                         netconfig_wifi_remove_driver();
341
342                         vconf_set_int(VCONFKEY_NETWORK_WIFI_STATE, VCONFKEY_NETWORK_WIFI_OFF);
343                         vconf_set_int(VCONF_WIFI_LAST_POWER_STATE, WIFI_POWER_OFF);
344                         vconf_set_int(VCONFKEY_WIFI_STATE, VCONFKEY_WIFI_OFF);
345
346                         netconfig_wifi_notify_power_completed(FALSE);
347
348                         netconfig_del_wifi_found_notification();
349
350                         netconfig_wifi_bgscan_stop();
351
352                         __netconfig_wifi_set_profiles_count(0);
353                 }
354         }
355 }
356
357 char *netconfig_wifi_get_favorite_service(void)
358 {
359         return __netconfig_wifi_get_connman_favorite_service();
360 }
361
362 void netconfig_wifi_check_network_notification(DBusMessage *message)
363 {
364         DBusMessageIter iter;
365         int profiles_count = 0;
366         int qs_enable, ug_state;
367
368         if (netconfig_wifi_state_get_service_state() == NETCONFIG_WIFI_CONNECTED) {
369                 DBG("Service state is connected");
370                 return;
371         }
372
373         if (vconf_get_int(VCONFKEY_WIFI_ENABLE_QS, &qs_enable) == -1) {
374                 DBG("Fail to get %s", VCONFKEY_WIFI_ENABLE_QS);
375                 return;
376         }
377
378         if (qs_enable != VCONFKEY_WIFI_QS_ENABLE) {
379                 DBG("qs_enable != VCONFKEY_WIFI_QS_ENABLE");
380                 return;
381         }
382
383         if (vconf_get_int(VCONFKEY_WIFI_UG_RUN_STATE, &ug_state) == -1) {
384                 DBG("Fail to get %s", VCONFKEY_WIFI_UG_RUN_STATE);
385                 return;
386         }
387
388         if (ug_state == VCONFKEY_WIFI_UG_RUN_STATE_ON_FOREGROUND) {
389                 DBG("ug_state == VCONFKEY_WIFI_UG_RUN_STATE_ON_FOREGROUND");
390                 return;
391         }
392
393         if (message == NULL) {
394                 ERR("Failed to get service list");
395                 return;
396         }
397
398         dbus_message_iter_init(message, &iter);
399         DBusMessageIter array, value;
400         dbus_message_iter_recurse(&iter, &array);
401         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRUCT) {
402                 DBG("Array not found. type %d", dbus_message_iter_get_arg_type(&array));
403                 return;
404         }
405
406         dbus_message_iter_recurse(&array, &value);
407         while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_OBJECT_PATH) {
408                 const char *object_path = NULL;
409
410                 dbus_message_iter_get_basic(&value, &object_path);
411
412                 DBG("found a profile: %s", object_path);
413                 if (netconfig_is_wifi_profile(object_path) == TRUE) {
414                         profiles_count++;
415                         DBG("Total wifi profile cnt = %d", profiles_count);
416                 }
417
418                 dbus_message_iter_next(&array);
419                 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRUCT) {
420                         DBG("Not a structure entry. Arg type = %d", dbus_message_iter_get_arg_type(&array));
421                         break;
422                 }
423                 dbus_message_iter_recurse(&array, &value);
424         }
425
426         if (__netconfig_wifi_get_profiles_count() != profiles_count) {
427                 DBG("profiles prev_count (%d) - profiles count (%d)",
428                                 __netconfig_wifi_get_profiles_count(), profiles_count);
429
430                 netconfig_add_wifi_found_notification();
431                 __netconfig_wifi_set_profiles_count(profiles_count);
432         } else
433                 DBG("No change in profile count[%d]", profiles_count);
434 }
435
436 void netconfig_wifi_state_notifier_cleanup(void)
437 {
438         g_slist_free_full(notifier_list, NULL);
439 }
440
441 void netconfig_wifi_state_notifier_register(
442                 struct netconfig_wifi_state_notifier *notifier)
443 {
444         DBG("register notifier");
445
446         notifier_list = g_slist_append(notifier_list, notifier);
447 }
448
449 void netconfig_wifi_state_notifier_unregister(
450                 struct netconfig_wifi_state_notifier *notifier)
451 {
452         DBG("un-register notifier");
453
454         notifier_list = g_slist_remove_all(notifier_list, notifier);
455 }