Apply coding rule
[platform/core/connectivity/net-config.git] / src / wifi-ssid-scan.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2000 - 2012 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 "log.h"
21 #include "util.h"
22 #include "neterror.h"
23 #include "netdbus.h"
24 #include "netsupplicant.h"
25 #include "wifi-ssid-scan.h"
26 #include "wifi-background-scan.h"
27
28 typedef enum {
29         WIFI_SECURITY_UNKNOWN = 0x00,
30         WIFI_SECURITY_NONE = 0x01,
31         WIFI_SECURITY_WEP = 0x02,
32         WIFI_SECURITY_PSK = 0x03,
33         WIFI_SECURITY_IEEE8021X = 0x04,
34 } wifi_security_e;
35
36 typedef struct {
37         unsigned char ssid[33];
38         wifi_security_e security;
39         gboolean privacy;
40         gboolean wps;
41 } bss_info_t;
42
43 static gboolean g_ssid_scan_state = FALSE;
44 static GSList *bss_info_list = NULL;
45 static guint ssid_scan_timer = 0;
46 static char *g_ssid = NULL;
47
48 static void __check_security(const char *str_keymgmt, bss_info_t *bss_info)
49 {
50         INFO("keymgmt : %s", str_keymgmt);
51
52         if (g_strcmp0(str_keymgmt, "ieee8021x") == 0)
53                 bss_info->security = WIFI_SECURITY_IEEE8021X;
54         else if (g_strcmp0(str_keymgmt, "wpa-psk") == 0)
55                 bss_info->security = WIFI_SECURITY_PSK;
56         else if (g_strcmp0(str_keymgmt, "wpa-psk-sha256") == 0)
57                 bss_info->security = WIFI_SECURITY_PSK;
58         else if (g_strcmp0(str_keymgmt, "wpa-ft-psk") == 0)
59                 bss_info->security = WIFI_SECURITY_PSK;
60         else if (g_strcmp0(str_keymgmt, "wpa-ft-eap") == 0)
61                 bss_info->security = WIFI_SECURITY_IEEE8021X;
62         else if (g_strcmp0(str_keymgmt, "wpa-eap") == 0)
63                 bss_info->security = WIFI_SECURITY_IEEE8021X;
64         else if (g_strcmp0(str_keymgmt, "wpa-eap-sha256") == 0)
65                 bss_info->security = WIFI_SECURITY_IEEE8021X;
66         else if (g_strcmp0(str_keymgmt, "wps") == 0)
67                 bss_info->wps = TRUE;
68 }
69
70 static gboolean __ssid_scan_timeout(gpointer data)
71 {
72         wifi_ssid_scan_emit_scan_completed();
73
74         return FALSE;
75 }
76
77 static void _start_ssid_scan_timer(void)
78 {
79         INFO("Wi-Fi SSID scan started");
80         g_ssid_scan_state = TRUE;
81
82         netconfig_start_timer_seconds(5, __ssid_scan_timeout, NULL, &ssid_scan_timer);
83 }
84
85 static void _stop_ssid_scan_timer(void)
86 {
87         INFO("Wi-Fi SSID scan finished");
88         g_ssid_scan_state = FALSE;
89
90         netconfig_stop_timer(&ssid_scan_timer);
91 }
92
93 static void _parse_keymgmt_message(GVariant *param, bss_info_t *bss_info)
94 {
95         GVariantIter *iter1;
96         GVariant *var;
97         gchar *key;
98
99         g_variant_get(param, "a{sv}", &iter1);
100         while (g_variant_iter_loop(iter1, "{sv}", &key, &var)) {
101                 if (g_strcmp0(key, "KeyMgmt") == 0) {
102                         GVariantIter *iter2;
103                         g_variant_get(var, "as", &iter2);
104                         char *str;
105                         while (g_variant_iter_loop(iter2, "s", &str)) {
106                                 if (str == NULL)
107                                         break;
108                                 __check_security(str, bss_info);
109                         }
110                         g_variant_iter_free(iter2);
111                 }
112         }
113
114         g_variant_iter_free(iter1);
115
116         return;
117 }
118
119 static gboolean _request_ssid_scan(const char *object_path, const char *ssid)
120 {
121         /* TODO: Revise following code */
122
123 #define NETCONFIG_DBUS_REPLY_TIMEOUT (10 * 1000)
124         GDBusConnection *connection = NULL;
125         GVariant *reply = NULL;
126         GVariant *params = NULL;
127         GError *error = NULL;
128         GVariantBuilder *builder1 = NULL;
129         GVariantBuilder *builder2 = NULL;
130         GVariantBuilder *builder3 = NULL;
131         const gchar *key1 = "Type";
132         const gchar *val1 = "active";
133         const gchar *key2 = "SSIDs";
134         int i = 0;
135
136         connection = netdbus_get_connection();
137         if (connection == NULL) {
138                 DBG("Failed to get GDBusconnection");
139                 return FALSE;
140         }
141
142         builder1 = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
143         g_variant_builder_add(builder1, "{sv}", key1, g_variant_new_string(val1));
144
145         builder2 = g_variant_builder_new(G_VARIANT_TYPE("aay"));
146         builder3 = g_variant_builder_new(G_VARIANT_TYPE("ay"));
147
148         for (i = 0; i < strlen(ssid); i++)
149                 g_variant_builder_add(builder3, "y", ssid[i]);
150
151         g_variant_builder_add(builder2, "@ay", g_variant_builder_end(builder3));
152         g_variant_builder_add(builder1, "{sv}", key2, g_variant_builder_end(builder2));
153
154         params = g_variant_new("(@a{sv})", g_variant_builder_end(builder1));
155
156         g_variant_builder_unref(builder1);
157         g_variant_builder_unref(builder2);
158         g_variant_builder_unref(builder3);
159
160         reply = g_dbus_connection_call_sync(
161                         connection,
162                         SUPPLICANT_SERVICE,
163                         object_path,
164                         SUPPLICANT_INTERFACE ".Interface",
165                         "Scan",
166                         params,
167                         NULL,
168                         G_DBUS_CALL_FLAGS_NONE,
169                         NETCONFIG_DBUS_REPLY_TIMEOUT,
170                         netdbus_get_cancellable(),
171                         &error);
172
173         if (reply == NULL) {
174                 if (error != NULL) {
175                         ERR("Error!!! dbus_connection_send_with_reply_and_block() failed. "
176                                         "DBus error [%d: %s]", error->code, error->message);
177                         g_error_free(error);
178                 } else
179                         ERR("Error!!! Failed to get properties");
180
181                 return FALSE;
182         }
183
184         if (g_ssid != NULL)
185                 g_free(g_ssid);
186
187         g_ssid = g_strdup(ssid);
188
189         g_variant_unref(reply);
190
191         return TRUE;
192 }
193
194 static void _emit_ssid_scan_completed(void)
195 {
196         GVariantBuilder *builder = NULL;
197         GSList* list = NULL;
198         const char *prop_ssid = "ssid";
199         const char *prop_security = "security";
200         const char *prop_wps = "wps";
201
202         builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
203         for (list = bss_info_list; list != NULL; list = list->next) {
204                 bss_info_t *bss_info = (bss_info_t *)list->data;
205                 if (bss_info && g_strcmp0((char *)bss_info->ssid, g_ssid) == 0) {
206                         const gchar *ssid = (char *)bss_info->ssid;
207                         wifi_security_e security = bss_info->security;
208                         gboolean wps = bss_info->wps;
209                         DBG("BSS found; SSID:%s security:%d WPS:%d", ssid, security, wps);
210                         g_variant_builder_add(builder, "{sv}", prop_ssid, g_variant_new_string(ssid));
211                         g_variant_builder_add(builder, "{sv}", prop_security, g_variant_new_int32(security));
212                         /* WPS */
213                         g_variant_builder_add(builder, "{sv}", prop_wps, g_variant_new_boolean(wps));
214                 }
215         }
216
217         wifi_emit_specific_scan_completed((Wifi *)get_wifi_object(), g_variant_builder_end(builder));
218
219         if (builder)
220                 g_variant_builder_unref(builder);
221
222         if (bss_info_list != NULL) {
223                 g_slist_free_full(bss_info_list, g_free);
224                 bss_info_list = NULL;
225         }
226
227         if (g_ssid != NULL) {
228                 g_free(g_ssid);
229                 g_ssid = NULL;
230         }
231
232         INFO("SpecificScanCompleted");
233
234         return;
235 }
236
237 gboolean wifi_ssid_scan(const char *ssid)
238 {
239         const char *if_path;
240         static char *scan_ssid = NULL;
241
242         netconfig_wifi_bgscan_stop();
243
244         if (ssid != NULL) {
245                 if (scan_ssid != NULL)
246                         g_free(scan_ssid);
247                 scan_ssid = g_strdup(ssid);
248         }
249
250         if (scan_ssid == NULL)
251                 goto error;
252
253         if_path = netconfig_wifi_get_supplicant_interface();
254         if (if_path == NULL) {
255                 DBG("Fail to get wpa_supplicant DBus path");
256                 goto error;
257         }
258
259         if (netconfig_wifi_get_scanning() == TRUE) {
260                 DBG("Wi-Fi scan in progress, %s scan will be delayed", scan_ssid);
261                 g_free(scan_ssid);
262                 return TRUE;
263         }
264
265         if (bss_info_list) {
266                 g_slist_free_full(bss_info_list, g_free);
267                 bss_info_list = NULL;
268         }
269
270         INFO("Start Wi-Fi scan with %s(%d)", scan_ssid, strlen(scan_ssid));
271         if (_request_ssid_scan(if_path, (const char *)scan_ssid) == TRUE) {
272                 _start_ssid_scan_timer();
273                 g_free(scan_ssid);
274                 scan_ssid = NULL;
275                 return TRUE;
276         }
277
278 error:
279         if (scan_ssid != NULL) {
280                 g_free(scan_ssid);
281                 scan_ssid = NULL;
282         }
283
284         netconfig_wifi_bgscan_start(FALSE);
285
286         return FALSE;
287 }
288
289 gboolean wifi_ssid_scan_get_state(void)
290 {
291         return g_ssid_scan_state;
292 }
293
294 void wifi_ssid_scan_emit_scan_completed(void)
295 {
296         if (g_ssid_scan_state != TRUE)
297                 return;
298
299         _stop_ssid_scan_timer();
300         _emit_ssid_scan_completed();
301 }
302
303 void wifi_ssid_scan_add_bss(GVariant *message)
304 {
305         GVariantIter *iter;
306         GVariant *value;
307         gchar *path = NULL;
308         gchar *key;
309         bss_info_t *bss_info;
310
311         if (g_ssid_scan_state != TRUE)
312                 return;
313
314         INFO("NEW BSS added");
315
316         if (message == NULL) {
317                 DBG("Message does not have parameters");
318                 return;
319         }
320
321         if (path != NULL)
322                 INFO("Object path of BSS added is %s", path);
323
324         bss_info = g_try_new0(bss_info_t, 1);
325         if (bss_info == NULL)
326                 return;
327
328         g_variant_get(message, "(oa{sv})", &path, &iter);
329         while (g_variant_iter_loop(iter, "{sv}", &key, &value)) {
330                 if (g_strcmp0(key, "SSID") == 0) {
331                         const guchar *ssid;
332                         gsize ssid_len;
333                         ssid = g_variant_get_fixed_array(value, &ssid_len, sizeof(guchar));
334                         if (ssid != NULL && ssid_len > 0 && ssid_len < 33)
335                                 memcpy(bss_info->ssid, ssid, ssid_len);
336                         else
337                                 memset(bss_info->ssid, 0, sizeof(bss_info->ssid));
338                 } else if (g_strcmp0(key, "Privacy") == 0) {
339                         gboolean privacy = FALSE;
340                         privacy = g_variant_get_boolean(value);
341                         bss_info->privacy = privacy;
342                 } else if ((g_strcmp0(key, "RSN") == 0) || (g_strcmp0(key, "WPA") == 0)) {
343                         _parse_keymgmt_message(value, bss_info);
344                 } else if (g_strcmp0(key, "IEs") == 0) {
345                         const guchar *ie;
346                         gsize ie_len;
347                         ie = g_variant_get_fixed_array(value, &ie_len, sizeof(guchar));
348                         DBG("The IE : %s", ie);
349                 }
350         }
351
352         g_variant_iter_free(iter);
353         if (path)
354                 g_free(path);
355
356         if (bss_info->ssid[0] == '\0') {
357                 g_free(bss_info);
358                 return;
359         }
360
361         if (bss_info->security == WIFI_SECURITY_UNKNOWN) {
362                 if (bss_info->privacy == TRUE)
363                         bss_info->security = WIFI_SECURITY_WEP;
364                 else
365                         bss_info->security = WIFI_SECURITY_NONE;
366         }
367
368         bss_info_list = g_slist_append(bss_info_list, bss_info);
369 }
370
371 gboolean handle_request_specific_scan(Wifi *wifi,
372                 GDBusMethodInvocation *context, const gchar *ssid)
373 {
374         gboolean result = FALSE;
375
376         g_return_val_if_fail(wifi != NULL, FALSE);
377         g_return_val_if_fail(ssid != NULL, FALSE);
378
379         result = wifi_ssid_scan((const char *)ssid);
380
381         if (result != TRUE)
382                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "FailSpecificScan");
383         else
384                 wifi_complete_request_wps_scan(wifi, context);
385
386         return result;
387 }