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