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