Merge "Bug fixing: net-config crash after system reboot" into tizen
[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         gboolean wifi_tethering = FALSE;
236
237         message = netconfig_invoke_dbus_method(CONNMAN_SERVICE,
238                         CONNMAN_MANAGER_PATH, CONNMAN_MANAGER_INTERFACE,
239                         "GetTechnologies", NULL);
240         if (message == NULL) {
241                 ERR("Failed to get Wi-Fi technology state");
242                 return NETCONFIG_WIFI_TECH_UNKNOWN;
243         }
244
245         dbus_message_iter_init(message, &iter);
246         dbus_message_iter_recurse(&iter, &array);
247
248         while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRUCT) {
249                 DBusMessageIter entry, dict;
250                 const char *path;
251
252                 dbus_message_iter_recurse(&array, &entry);
253                 dbus_message_iter_get_basic(&entry, &path);
254
255                 dbus_message_iter_next(&entry);
256                 dbus_message_iter_recurse(&entry, &dict);
257
258                 if (path == NULL ||
259                         g_str_equal(path, CONNMAN_WIFI_TECHNOLOGY_PREFIX) == FALSE) {
260                         dbus_message_iter_next(&array);
261                         continue;
262                 }
263
264                 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
265                         DBusMessageIter entry1, value1;
266                         const char *key, *sdata;
267                         dbus_bool_t data;
268
269                         dbus_message_iter_recurse(&dict, &entry1);
270                         dbus_message_iter_get_basic(&entry1, &key);
271
272                         dbus_message_iter_next(&entry1);
273                         dbus_message_iter_recurse(&entry1, &value1);
274
275                         if (dbus_message_iter_get_arg_type(&value1) ==
276                                         DBUS_TYPE_BOOLEAN) {
277                                 dbus_message_iter_get_basic(&value1, &data);
278                                 DBG("key-[%s] - %s", key, data ? "True" : "False");
279
280                                 if (strcmp(key, "Powered") == 0 && data) {
281                                         wifi_tech_powered = TRUE;
282                                 } else if (strcmp(key, "Connected") == 0 && data) {
283                                         wifi_tech_connected = TRUE;
284                                 } else if (strcmp(key, "Tethering") == 0 && data) {
285                                         wifi_tethering = TRUE;
286                                 }
287                         } else if (dbus_message_iter_get_arg_type(&value1) ==
288                                         DBUS_TYPE_STRING) {
289                                 dbus_message_iter_get_basic(&value1, &sdata);
290                                 DBG("%s", sdata);
291                         }
292                         dbus_message_iter_next(&dict);
293                 }
294
295                 dbus_message_iter_next(&array);
296         }
297
298         dbus_message_unref(message);
299
300         if (wifi_tech_powered)
301                 ret = NETCONFIG_WIFI_TECH_POWERED;
302
303         if (wifi_tech_connected)
304                 ret = NETCONFIG_WIFI_TECH_CONNECTED;
305
306         if (wifi_tethering)
307                 ret = NETCONFIG_WIFI_TECH_TETHERING_ON;
308
309         return ret;
310 }
311
312 void netconfig_wifi_update_power_state(gboolean powered)
313 {
314         int wifi_state = 0;
315
316         /* It's automatically updated by signal-handler
317          * DO NOT update manually
318          * It includes Wi-Fi state configuration
319          */
320         vconf_get_int(VCONFKEY_WIFI_STATE, &wifi_state);
321
322         if (powered == TRUE) {
323                 if (wifi_state == VCONFKEY_WIFI_OFF &&
324                                 netconfig_is_wifi_direct_on() != TRUE &&
325                                 netconfig_is_wifi_tethering_on() != TRUE) {
326                         DBG("Wi-Fi successfully turned on or waken up from power-save mode");
327
328                         vconf_set_int(VCONFKEY_NETWORK_WIFI_STATE, VCONFKEY_NETWORK_WIFI_NOT_CONNECTED);
329                         vconf_set_int(VCONF_WIFI_LAST_POWER_STATE, WIFI_POWER_ON);
330                         vconf_set_int(VCONFKEY_WIFI_STATE, VCONFKEY_WIFI_UNCONNECTED);
331
332                         netconfig_wifi_notify_power_completed(TRUE);
333
334                         netconfig_wifi_device_picker_service_start();
335
336                         netconfig_wifi_bgscan_start();
337                 }
338         } else {
339                 if (wifi_state != VCONFKEY_WIFI_OFF) {
340                         DBG("Wi-Fi successfully turned off or in power-save mode");
341
342                         netconfig_wifi_device_picker_service_stop();
343
344                         if (netconfig_is_wifi_tethering_on() != TRUE)
345                                 netconfig_wifi_remove_driver();
346
347                         vconf_set_int(VCONFKEY_NETWORK_WIFI_STATE, VCONFKEY_NETWORK_WIFI_OFF);
348                         vconf_set_int(VCONF_WIFI_LAST_POWER_STATE, WIFI_POWER_OFF);
349                         vconf_set_int(VCONFKEY_WIFI_STATE, VCONFKEY_WIFI_OFF);
350
351                         netconfig_wifi_notify_power_completed(FALSE);
352
353                         netconfig_del_wifi_found_notification();
354
355                         netconfig_wifi_bgscan_stop();
356
357                         __netconfig_wifi_set_profiles_count(0);
358                 }
359         }
360 }
361
362 char *netconfig_wifi_get_favorite_service(void)
363 {
364         return __netconfig_wifi_get_connman_favorite_service();
365 }
366
367 void netconfig_wifi_check_network_notification(DBusMessage *message)
368 {
369         DBusMessageIter iter;
370         int profiles_count = 0;
371         int qs_enable, ug_state;
372
373         if (netconfig_wifi_state_get_service_state() == NETCONFIG_WIFI_CONNECTED) {
374                 DBG("Service state is connected");
375                 return;
376         }
377
378         if (vconf_get_int(VCONFKEY_WIFI_ENABLE_QS, &qs_enable) == -1) {
379                 DBG("Fail to get %s", VCONFKEY_WIFI_ENABLE_QS);
380                 return;
381         }
382
383         if (qs_enable != VCONFKEY_WIFI_QS_ENABLE) {
384                 DBG("qs_enable != VCONFKEY_WIFI_QS_ENABLE");
385                 return;
386         }
387
388         if (vconf_get_int(VCONFKEY_WIFI_UG_RUN_STATE, &ug_state) == -1) {
389                 DBG("Fail to get %s", VCONFKEY_WIFI_UG_RUN_STATE);
390                 return;
391         }
392
393         if (ug_state == VCONFKEY_WIFI_UG_RUN_STATE_ON_FOREGROUND) {
394                 DBG("ug_state == VCONFKEY_WIFI_UG_RUN_STATE_ON_FOREGROUND");
395                 return;
396         }
397
398         if (message == NULL) {
399                 ERR("Failed to get service list");
400                 return;
401         }
402
403         dbus_message_iter_init(message, &iter);
404         DBusMessageIter array, value;
405         dbus_message_iter_recurse(&iter, &array);
406         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRUCT) {
407                 DBG("Array not found. type %d", dbus_message_iter_get_arg_type(&array));
408                 return;
409         }
410
411         dbus_message_iter_recurse(&array, &value);
412         while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_OBJECT_PATH) {
413                 const char *object_path = NULL;
414
415                 dbus_message_iter_get_basic(&value, &object_path);
416
417                 DBG("found a profile: %s", object_path);
418                 if (netconfig_is_wifi_profile(object_path) == TRUE) {
419                         profiles_count++;
420                         DBG("Total wifi profile cnt = %d", profiles_count);
421                 }
422
423                 dbus_message_iter_next(&array);
424                 if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRUCT) {
425                         DBG("Not a structure entry. Arg type = %d", dbus_message_iter_get_arg_type(&array));
426                         break;
427                 }
428                 dbus_message_iter_recurse(&array, &value);
429         }
430
431         if (__netconfig_wifi_get_profiles_count() != profiles_count) {
432                 DBG("profiles prev_count (%d) - profiles count (%d)",
433                                 __netconfig_wifi_get_profiles_count(), profiles_count);
434
435                 netconfig_add_wifi_found_notification();
436                 __netconfig_wifi_set_profiles_count(profiles_count);
437         } else
438                 DBG("No change in profile count[%d]", profiles_count);
439 }
440
441 void netconfig_wifi_state_notifier_cleanup(void)
442 {
443         /*
444          * Now, all the user_data of notifier_list's element
445          * is NULL, so we don't free that, only use g_slist_free.
446          * If user_data is not NULL, using g_slist_free_full with
447          * destory_notify function to free user_data
448          */
449         g_slist_free(notifier_list);
450 }
451
452 void netconfig_wifi_state_notifier_register(
453                 struct netconfig_wifi_state_notifier *notifier)
454 {
455         DBG("register notifier");
456
457         notifier_list = g_slist_append(notifier_list, notifier);
458 }
459
460 void netconfig_wifi_state_notifier_unregister(
461                 struct netconfig_wifi_state_notifier *notifier)
462 {
463         DBG("un-register notifier");
464
465         notifier_list = g_slist_remove_all(notifier_list, notifier);
466 }