Check SSID when loading wifi configuration file
[platform/core/connectivity/net-config.git] / src / wifi-scan.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2020 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 <glib.h>
21 #include <vconf.h>
22 #include <vconf-keys.h>
23
24 #include "log.h"
25 #include "util.h"
26 #include "netdbus.h"
27 #include "wifi-state.h"
28 #include "wifi-scan.h"
29
30 typedef struct {
31         const char *interface_name;
32
33         /* background scan */
34         guint bg_interval;
35         guint bg_mode;
36         guint bg_timer_id;
37         gboolean bg_paused;
38
39         /* bssid scan*/
40         gboolean bssid_enabled;
41         gboolean bssid_aborted;
42         gboolean bssid_scanning;
43
44         /* scan */
45         gboolean scanning;
46 } scan_data_s;
47
48 static GSList *g_scan_list = NULL;
49
50 static scan_data_s *__wifi_scan_create_data(const char *interface_name)
51 {
52         scan_data_s *scan_data = g_try_malloc0(sizeof(scan_data_s));
53         if (!scan_data) {
54                 ERR("Memory allocation failed");
55                 return NULL;
56         }
57
58         scan_data->interface_name = g_strdup(interface_name);
59
60         scan_data->scanning = FALSE;
61
62         scan_data->bg_interval = SCAN_EXPONENTIAL_MIN;
63         scan_data->bg_mode = WIFI_BGSCAN_MODE_EXPONENTIAL;
64         scan_data->bg_timer_id = 0;
65         scan_data->bg_paused = FALSE;
66
67         scan_data->bssid_enabled = FALSE;
68         scan_data->bssid_aborted = FALSE;
69         scan_data->bssid_scanning = FALSE;
70
71         g_scan_list = g_slist_append(g_scan_list, scan_data);
72
73         return scan_data;
74 }
75
76 static scan_data_s *__wifi_scan_get_data(const char *interface_name)
77 {
78         GSList *list;
79         scan_data_s *scan_data;
80
81         for (list = g_scan_list; list; list = list->next) {
82                 scan_data = list->data;
83                 if (g_strcmp0(scan_data->interface_name, interface_name) == 0)
84                         return scan_data;
85         }
86
87         scan_data = __wifi_scan_create_data(interface_name);
88         return scan_data;
89 }
90
91 void netconfig_wifi_scan_set_scanning(const char *interface_name, gboolean scanning)
92 {
93         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
94
95         if (!scan_data)
96                 return;
97
98         scan_data->scanning = scanning;
99 }
100
101 guint netconfig_wifi_scan_get_scanning(const char *interface_name)
102 {
103         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
104
105         if (!scan_data)
106                 return FALSE;
107
108         return scan_data->scanning;;
109 }
110
111 gboolean netconfig_wifi_bgscan_set_mode(const char *interface_name, guint mode)
112 {
113         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
114
115         if (!scan_data)
116                 return FALSE;
117
118         if (mode != WIFI_BGSCAN_MODE_EXPONENTIAL && mode != WIFI_BGSCAN_MODE_PERIODIC) {
119                 ERR("Invalid scan mode [%d]", mode);
120                 return FALSE;
121         }
122
123         scan_data->bg_mode = mode;
124
125         return TRUE;
126 }
127
128 guint netconfig_wifi_bgscan_get_mode(const char *interface_name)
129 {
130         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
131
132         if (!scan_data)
133                 return 0;
134
135         return scan_data->bg_mode;
136 }
137
138 void netconfig_wifi_bgscan_set_timer_id(const char *interface_name, guint timer_id)
139 {
140         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
141
142         if (!scan_data)
143                 return;
144
145         scan_data->bg_timer_id = timer_id;
146 }
147
148 guint netconfig_wifi_bgscan_get_timer_id(const char *interface_name)
149 {
150         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
151
152         if (!scan_data)
153                 return 0;
154
155         return scan_data->bg_timer_id;
156 }
157
158 gboolean netconfig_wifi_bgscan_set_interval(const char *interface_name, guint interval)
159 {
160         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
161
162         if (!scan_data)
163                 return FALSE;
164
165         if ((interval < SCAN_EXPONENTIAL_MIN) || (interval > SCAN_EXPONENTIAL_MAX)) {
166                 ERR("Invalid interval [%d]", interval);
167                 return FALSE;
168         }
169
170         scan_data->bg_interval = interval;
171
172         return TRUE;
173 }
174
175 guint netconfig_wifi_bgscan_get_interval(const char *interface_name)
176 {
177         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
178
179         if (!scan_data)
180                 return SCAN_EXPONENTIAL_MIN;
181
182         return scan_data->bg_interval;
183 }
184
185 void netconfig_wifi_bgscan_set_pause(const char *interface_name, gboolean pause)
186 {
187         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
188         if (!scan_data)
189                 return;
190
191         scan_data->bg_paused = pause;
192
193         DBG("[%s] Wi-Fi background scan [%s]", interface_name,
194                         pause ? "Pause" : "Resume");
195 }
196
197 gboolean netconfig_wifi_bgscan_is_paused(const char *interface_name)
198 {
199         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
200         if (!scan_data)
201                 return FALSE;
202
203         DBG("[%s] Wi-Fi background scan is [%s]", interface_name,
204                         scan_data->bg_paused ? "Paused" : "Runnable");
205
206         return scan_data->bg_paused;
207 }
208
209 static void __wifi_scan_request_reply(GObject *source_object,
210                 GAsyncResult *res, gpointer user_data)
211 {
212         GVariant *reply;
213         GDBusConnection *conn = NULL;
214         GError *error = NULL;
215         char *interface_name = user_data;
216
217         conn = G_DBUS_CONNECTION(source_object);
218         reply = g_dbus_connection_call_finish(conn, res, &error);
219
220         if (reply == NULL) {
221                 if (error != NULL) {
222                         ERR("Fail to request status [%d: %s]", error->code, error->message);
223                         netconfig_wifi_scan_set_scanning(interface_name, FALSE);
224                         g_error_free(error);
225                 } else {
226                         ERR("Fail to request scan");
227                         netconfig_wifi_scan_set_scanning(interface_name, FALSE);
228                 }
229         } else {
230                 DBG("Successfully requested");
231                 g_variant_unref(reply);
232         }
233
234         netconfig_gdbus_pending_call_unref();
235         g_free(interface_name);
236 }
237
238 static gboolean __wifi_scan_request_connman_scan(const char *interface_name)
239 {
240         GVariant *params = NULL;
241         gboolean reply = FALSE;
242
243         netconfig_wifi_scan_set_scanning(interface_name, TRUE);
244
245         params = g_variant_new("(s)", interface_name);
246
247         reply = netconfig_invoke_dbus_method_nonblock(CONNMAN_SERVICE,
248                         CONNMAN_WIFI_TECHNOLOGY_PREFIX,
249                         CONNMAN_TECHNOLOGY_INTERFACE, "ScanDevice", params,
250                         __wifi_scan_request_reply, g_strdup(interface_name));
251         if (reply != TRUE) {
252                 ERR("Failed to send Scan request to connman");
253                 netconfig_wifi_scan_set_scanning(interface_name, FALSE);
254         }
255
256         return reply;
257 }
258
259 static gboolean __wifi_bgscan_immediate_scan(gpointer data)
260 {
261         static int retries = 0;
262         scan_data_s *scan_data = data;
263         guint state = 0;
264
265         if (!scan_data)
266                 return FALSE;
267
268         state = wifi_state_get_service_state(scan_data->interface_name);
269
270 #if !defined TIZEN_WEARABLE
271         if (netconfig_wifi_bgscan_is_paused(scan_data->interface_name)) {
272                 return FALSE;
273         }
274 #endif
275
276         if (state == NETCONFIG_WIFI_CONNECTED) {
277                 if (netconfig_wifi_bgscan_get_mode(scan_data->interface_name) == WIFI_BGSCAN_MODE_EXPONENTIAL) {
278                         DBG("[%s] Wi-Fi state is connected, scan is paused", scan_data->interface_name);
279                         return FALSE;
280                 }
281         } else if (state == NETCONFIG_WIFI_ASSOCIATION || state == NETCONFIG_WIFI_CONFIGURATION) {
282                 /* During WIFI connecting, WIFI can be disappeared.
283                  * After 1 sec, try scan even if connecting state */
284                 if (retries < 2) {
285                         retries++;
286                         return TRUE;
287                 }
288         }
289
290         if (__wifi_scan_request_connman_scan(scan_data->interface_name) == TRUE) {
291                 retries = 0;
292                 return FALSE;
293         } else if (retries > 2) {
294                 retries = 0;
295                 return FALSE;
296         }
297
298         retries++;
299
300         return TRUE;
301 }
302
303 static gboolean __wifi_bgscan_next_scan(gpointer data)
304 {
305         int pm_state = VCONFKEY_PM_STATE_NORMAL;
306         scan_data_s *scan_data = data;
307
308         if (!scan_data)
309                 return FALSE;
310
311         /* In case of LCD off, we don't need Wi-Fi scan */
312         netconfig_vconf_get_int(VCONFKEY_PM_STATE, &pm_state);
313         if (pm_state >= VCONFKEY_PM_STATE_LCDOFF)
314                 return TRUE;
315
316         netconfig_wifi_bgscan_start_timer(scan_data->interface_name, TRUE);
317
318         return FALSE;
319 }
320
321 void netconfig_wifi_bgscan_start_timer(const char *interface_name, gboolean immediate_scan)
322 {
323         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
324
325         if (!scan_data)
326                 return;
327
328         netconfig_stop_timer(&(scan_data->bg_timer_id));
329
330         switch (scan_data->bg_mode) {
331         case WIFI_BGSCAN_MODE_EXPONENTIAL:
332                 if (scan_data->bg_interval < SCAN_EXPONENTIAL_MIN ||
333                         scan_data->bg_interval == SCAN_PERIODIC_DELAY)
334                         scan_data->bg_interval = SCAN_EXPONENTIAL_MIN;
335                 break;
336         case WIFI_BGSCAN_MODE_PERIODIC:
337                 scan_data->bg_interval = SCAN_PERIODIC_DELAY;
338                 break;
339         default:
340                 DBG("Invalid Wi-Fi background scan mode[%d]", scan_data->bg_mode);
341                 return;
342         }
343
344         if (immediate_scan)
345                 DBG("[%s] Scan immediately[%d], mode[%d](0 exponential / 1 periodic)",
346                         interface_name, immediate_scan, scan_data->bg_mode);
347         else
348                 DBG("[%s] Scan immediately[%d], mode[%d](0 exponential / 1 periodic), next[%d]",
349                         interface_name, immediate_scan, scan_data->bg_mode, scan_data->bg_interval);
350
351         if (immediate_scan)
352                 g_timeout_add(500, __wifi_bgscan_immediate_scan, scan_data);
353
354         netconfig_start_timer_seconds(scan_data->bg_interval,
355                 __wifi_bgscan_next_scan, scan_data, &(scan_data->bg_timer_id));
356
357         if (scan_data->bg_mode == WIFI_BGSCAN_MODE_EXPONENTIAL && immediate_scan) {
358                 scan_data->bg_interval = scan_data->bg_interval * 2;
359                 if (scan_data->bg_interval > SCAN_EXPONENTIAL_MAX)
360                         scan_data->bg_interval = SCAN_EXPONENTIAL_MAX;
361         }
362 }
363
364 void netconfig_wifi_bgscan_stop_timer(const char *interface_name)
365 {
366         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
367
368         if (scan_data)
369                 return;
370
371         netconfig_stop_timer(&(scan_data->bg_timer_id));
372 }
373
374 void netconfig_wifi_bssidscan_set_mode(const char *interface_name, gboolean enable)
375 {
376         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
377         if (!scan_data)
378                 return;
379
380         scan_data->bssid_enabled = enable;
381 }
382
383 gboolean netconfig_wifi_bssidscan_get_mode(const char *interface_name)
384 {
385         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
386         if (!scan_data)
387                 return FALSE;
388
389         return scan_data->bssid_enabled;
390 }
391
392 void netconfig_wifi_bssidscan_set_aborted(const char *interface_name, gboolean abort)
393 {
394         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
395         if (!scan_data)
396                 return;
397
398         scan_data->bssid_aborted = abort;
399 }
400
401 gboolean netconfig_wifi_bssidscan_get_aborted(const char *interface_name)
402 {
403         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
404         if (!scan_data)
405                 return FALSE;
406
407         return scan_data->bssid_aborted;
408 }
409
410 void netconfig_wifi_bssidscan_set_scanning(const char *interface_name, gboolean scanning)
411 {
412         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
413
414         if (!scan_data)
415                 return;
416
417         scan_data->bssid_scanning = scanning;
418 }
419
420 guint netconfig_wifi_bssidscan_get_scanning(const char *interface_name)
421 {
422         scan_data_s *scan_data = __wifi_scan_get_data(interface_name);
423
424         if (!scan_data)
425                 return FALSE;
426
427         return scan_data->bssid_scanning;;
428 }