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