Revise signal handler for Wi-Fi powered event from ConnMan
[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                         netconfig_wifi_notify_power_completed(TRUE);
325
326                         netconfig_wifi_device_picker_service_start();
327
328                         vconf_set_int(VCONFKEY_NETWORK_WIFI_STATE, VCONFKEY_NETWORK_WIFI_NOT_CONNECTED);
329
330                         vconf_set_int(VCONF_WIFI_LAST_POWER_STATE, WIFI_POWER_ON);
331
332                         vconf_set_int(VCONFKEY_WIFI_STATE, VCONFKEY_WIFI_UNCONNECTED);
333
334                         netconfig_wifi_bgscan_start();
335                 }
336         } else {
337                 if (wifi_state != VCONFKEY_WIFI_OFF) {
338                         DBG("Wi-Fi successfully turned off or in power-save mode");
339
340                         netconfig_wifi_device_picker_service_stop();
341
342                         netconfig_wifi_remove_driver();
343
344                         netconfig_wifi_notify_power_completed(FALSE);
345
346                         netconfig_del_wifi_found_notification();
347
348                         netconfig_wifi_bgscan_stop();
349
350                         __netconfig_wifi_set_profiles_count(0);
351
352                         vconf_set_int(VCONFKEY_NETWORK_WIFI_STATE, VCONFKEY_NETWORK_WIFI_OFF);
353
354                         vconf_set_int(VCONF_WIFI_LAST_POWER_STATE, WIFI_POWER_OFF);
355
356                         vconf_set_int(VCONFKEY_WIFI_STATE, VCONFKEY_WIFI_OFF);
357                 }
358         }
359 }
360
361 char *netconfig_wifi_get_favorite_service(void)
362 {
363         return __netconfig_wifi_get_connman_favorite_service();
364 }
365
366 void netconfig_wifi_check_network_notification(DBusMessage *message)
367 {
368         DBusMessageIter iter;
369         int profiles_count = 0;
370         int qs_enable, ug_state;
371
372         if (netconfig_wifi_state_get_service_state() == NETCONFIG_WIFI_CONNECTED) {
373                 DBG("Service state is connected");
374                 return;
375         }
376
377         if (vconf_get_int(VCONFKEY_WIFI_ENABLE_QS, &qs_enable) == -1) {
378                 DBG("Fail to get %s", VCONFKEY_WIFI_ENABLE_QS);
379                 return;
380         }
381
382         if (qs_enable != VCONFKEY_WIFI_QS_ENABLE) {
383                 DBG("qs_enable != VCONFKEY_WIFI_QS_ENABLE");
384                 return;
385         }
386
387         if (vconf_get_int(VCONFKEY_WIFI_UG_RUN_STATE, &ug_state) == -1) {
388                 DBG("Fail to get %s", VCONFKEY_WIFI_UG_RUN_STATE);
389                 return;
390         }
391
392         if (ug_state == VCONFKEY_WIFI_UG_RUN_STATE_ON_FOREGROUND) {
393                 DBG("ug_state == VCONFKEY_WIFI_UG_RUN_STATE_ON_FOREGROUND");
394                 return;
395         }
396
397         if (message == NULL) {
398                 ERR("Failed to get service list");
399                 return;
400         }
401
402         dbus_message_iter_init(message, &iter);
403         DBusMessageIter array, value;
404         dbus_message_iter_recurse(&iter, &array);
405         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRUCT) {
406                 DBG("Array not found. type %d", dbus_message_iter_get_arg_type(&array));
407                 return;
408         }
409
410         dbus_message_iter_recurse(&array, &value);
411         while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_OBJECT_PATH) {
412                 const char *object_path = NULL;
413
414                 dbus_message_iter_get_basic(&value, &object_path);
415
416                 DBG("found a profile: %s", object_path);
417                 if (netconfig_is_wifi_profile(object_path) == TRUE) {
418                         profiles_count++;
419                         DBG("Total wifi profile cnt = %d", profiles_count);
420                 }
421
422                 dbus_message_iter_next(&array);
423                 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRUCT) {
424                         DBG("Not a structure entry. Arg type = %d", dbus_message_iter_get_arg_type(&array));
425                         break;
426                 }
427                 dbus_message_iter_recurse(&array, &value);
428         }
429
430         if (__netconfig_wifi_get_profiles_count() != profiles_count) {
431                 DBG("profiles prev_count (%d) - profiles count (%d)",
432                                 __netconfig_wifi_get_profiles_count(), profiles_count);
433
434                 netconfig_add_wifi_found_notification();
435                 __netconfig_wifi_set_profiles_count(profiles_count);
436         } else
437                 DBG("No change in profile count[%d]", profiles_count);
438 }
439
440 void netconfig_wifi_state_notifier_cleanup(void)
441 {
442         g_slist_free_full(notifier_list, NULL);
443 }
444
445 void netconfig_wifi_state_notifier_register(
446                 struct netconfig_wifi_state_notifier *notifier)
447 {
448         DBG("register notifier");
449
450         notifier_list = g_slist_append(notifier_list, notifier);
451 }
452
453 void netconfig_wifi_state_notifier_unregister(
454                 struct netconfig_wifi_state_notifier *notifier)
455 {
456         DBG("un-register notifier");
457
458         notifier_list = g_slist_remove_all(notifier_list, notifier);
459 }