Tizen 2.1 base
[platform/core/connectivity/net-config.git] / src / wifi-ssid-scan.c
1 /*
2  * Network Configuration Module
3  *
4  * Copyright (c) 2012-2013 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 struct bss_info_t {
29         unsigned char ssid[32];
30         enum netconfig_wifi_security security;
31         dbus_bool_t privacy;
32         dbus_bool_t wps;
33 };
34
35 static gboolean wifi_ssid_scan_state = FALSE;
36 static GSList *wifi_bss_info_list = NULL;
37 static guint netconfig_wifi_ssid_scan_timer = 0;
38
39 static gboolean __netconfig_wifi_ssid_scan_timeout(gpointer data)
40 {
41         netconfig_wifi_notify_ssid_scan_done();
42
43         return FALSE;
44 }
45
46 static void __netconfig_wifi_ssid_scan_started(void)
47 {
48         INFO("Wi-Fi SSID scan started");
49         wifi_ssid_scan_state = TRUE;
50
51         netconfig_start_timer_seconds(
52                         5,
53                         __netconfig_wifi_ssid_scan_timeout,
54                         NULL,
55                         &netconfig_wifi_ssid_scan_timer);
56 }
57
58 static void __netconfig_wifi_ssid_scan_finished(void)
59 {
60         INFO("Wi-Fi SSID scan finished");
61         wifi_ssid_scan_state = FALSE;
62
63         netconfig_stop_timer(&netconfig_wifi_ssid_scan_timer);
64 }
65
66 static gboolean __netconfig_wifi_invoke_ssid_scan(
67                 const char *object_path, const char *ssid)
68 {
69         /* TODO: Revise following code */
70
71 #define NETCONFIG_DBUS_REPLY_TIMEOUT (10 * 1000)
72
73         DBusConnection *connection = NULL;
74         DBusMessage *message = NULL;
75         DBusMessage *reply = NULL;
76         DBusMessageIter iter, dict, entry;
77         DBusMessageIter value, array, array2;
78         DBusError error;
79         int MessageType = 0;
80         const char *key1 = "Type";
81         const char *val1 = "active";
82         const char *key2 = "SSIDs";
83
84         connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
85         if (connection == NULL) {
86                 ERR("Error!!! Failed to get system DBus");
87                 goto error;
88         }
89
90         message = dbus_message_new_method_call(SUPPLICANT_SERVICE,
91                         object_path, SUPPLICANT_INTERFACE ".Interface", "Scan");
92         if (message == NULL) {
93                 ERR("Error!!! DBus method call fail");
94                 goto error;
95         }
96
97         dbus_message_iter_init_append(message, &iter);
98         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
99                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
100                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
101                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
102
103         dbus_message_iter_open_container(&dict,
104                         DBUS_TYPE_DICT_ENTRY, NULL, &entry);
105         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key1);
106
107         dbus_message_iter_open_container(&entry,
108                         DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &value);
109         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &val1);
110
111         dbus_message_iter_close_container(&entry, &value);
112         dbus_message_iter_close_container(&dict, &entry);
113
114         dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, NULL, &entry);
115         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key2);
116
117         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
118                         DBUS_TYPE_ARRAY_AS_STRING
119                         DBUS_TYPE_ARRAY_AS_STRING
120                         DBUS_TYPE_BYTE_AS_STRING,
121                         &value);
122         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
123                         DBUS_TYPE_ARRAY_AS_STRING
124                         DBUS_TYPE_BYTE_AS_STRING,
125                         &array);
126         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &array2);
127
128         dbus_message_iter_append_fixed_array(&array2, DBUS_TYPE_BYTE, &ssid, strlen(ssid));
129
130         dbus_message_iter_close_container(&array, &array2);
131         dbus_message_iter_close_container(&value, &array);
132         dbus_message_iter_close_container(&entry, &value);
133         dbus_message_iter_close_container(&dict, &entry);
134         dbus_message_iter_close_container(&iter, &dict);
135
136         dbus_error_init(&error);
137
138         reply = dbus_connection_send_with_reply_and_block(connection, message,
139                         NETCONFIG_DBUS_REPLY_TIMEOUT, &error);
140
141         if (reply == NULL) {
142                 if (dbus_error_is_set(&error) == TRUE) {
143                         ERR("Error!!! dbus_connection_send_with_reply_and_block() failed. "
144                                         "DBus error [%s: %s]", error.name, error.message);
145
146                         dbus_error_free(&error);
147                         return FALSE;
148                 } else
149                         ERR("Error!!! Failed to get properties");
150
151                 goto error;
152         }
153
154         MessageType = dbus_message_get_type(reply);
155         if (MessageType == DBUS_MESSAGE_TYPE_ERROR) {
156                 const char *err_msg = dbus_message_get_error_name(reply);
157                 ERR("Error!!! Error message received %s", err_msg);
158                 goto error;
159         }
160
161         dbus_message_unref(message);
162         dbus_message_unref(reply);
163         dbus_connection_unref(connection);
164
165         return TRUE;
166
167 error:
168         if (message != NULL)
169                 dbus_message_unref(message);
170
171         if (reply != NULL)
172                 dbus_message_unref(reply);
173
174         if (connection != NULL)
175                 dbus_connection_unref(connection);
176
177         return FALSE;
178 }
179
180 static void __netconfig_wifi_notify_ssid_scan_done(void)
181 {
182         DBusMessage *signal;
183         DBusConnection *connection = NULL;
184         DBusMessageIter dict, type, array, value;
185         DBusError error;
186         char *prop_ssid = "ssid";
187         char *prop_security = "security";
188         const char *sig_name = "SpecificScanCompleted";
189
190         dbus_error_init(&error);
191
192         connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
193         if (connection == NULL) {
194                 /* TODO: If this occurs then UG should be informed abt SCAN fail. CHECK THIS. */
195                 ERR("Error!!! Failed to get system DBus, error [%s]", error.message);
196                 dbus_error_free(&error);
197
198                 g_slist_free_full(wifi_bss_info_list, g_free);
199                 wifi_bss_info_list = NULL;
200
201                 return;
202         }
203
204         signal = dbus_message_new_signal(NETCONFIG_WIFI_PATH, NETCONFIG_WIFI_INTERFACE, sig_name);
205         if (signal == NULL) {
206                 /* TODO: If this occurs then UG should be informed abt SCAN fail. CHECK THIS. */
207                 dbus_connection_unref(connection);
208
209                 g_slist_free_full(wifi_bss_info_list, g_free);
210                 wifi_bss_info_list = NULL;
211
212                 return;
213         }
214
215         dbus_message_iter_init_append(signal, &array);
216         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY, "{sv}", &dict);
217         GSList* list = wifi_bss_info_list;
218         while (list) {
219                 struct bss_info_t *bss_info = (struct bss_info_t *)g_slist_nth_data(list, 0);
220
221                 if (bss_info) {
222                         char *ssid = (char *)&(bss_info->ssid[0]);
223                         dbus_int16_t security = bss_info->security;
224                         DBG("Bss found. SSID: %s; Sec mode: %d;", ssid, security);
225
226                         /* Lets pack the SSID */
227                         dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, 0, &type);
228                         dbus_message_iter_append_basic(&type, DBUS_TYPE_STRING, &prop_ssid);
229                         dbus_message_iter_open_container(&type, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &value);
230
231                         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &ssid);
232                         dbus_message_iter_close_container(&type, &value);
233                         dbus_message_iter_close_container(&dict, &type);
234
235                         /* Lets pack the Security */
236                         dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, 0, &type);
237                         dbus_message_iter_append_basic(&type, DBUS_TYPE_STRING, &prop_security);
238                         dbus_message_iter_open_container(&type, DBUS_TYPE_VARIANT, DBUS_TYPE_INT16_AS_STRING, &value);
239
240                         dbus_message_iter_append_basic(&value, DBUS_TYPE_INT16, &security);
241                         dbus_message_iter_close_container(&type, &value);
242                         dbus_message_iter_close_container(&dict, &type);
243                 }
244                 list = g_slist_next(list);
245         }
246
247         dbus_message_iter_close_container(&array, &dict);
248
249         dbus_error_init(&error);
250         dbus_connection_send(connection, signal, NULL);
251
252         dbus_message_unref(signal);
253         dbus_connection_unref(connection);
254
255         g_slist_free_full(wifi_bss_info_list, g_free);
256         wifi_bss_info_list = NULL;
257
258         INFO("(%s)", sig_name);
259 }
260
261 static void __netconfig_wifi_check_security(const char *str_keymgmt, struct bss_info_t *bss_data)
262 {
263         INFO("keymgmt : %s", str_keymgmt);
264
265         if (strcmp(str_keymgmt, "ieee8021x") == 0) {
266                 bss_data->security = WIFI_SECURITY_IEEE8021X;
267         } else if (strcmp(str_keymgmt, "wpa-psk") == 0) {
268                 bss_data->security = WIFI_SECURITY_PSK;
269         } else if (strcmp(str_keymgmt, "wpa-psk-sha256") == 0) {
270                 bss_data->security = WIFI_SECURITY_PSK;
271         } else if (strcmp(str_keymgmt, "wpa-ft-psk") == 0) {
272                 bss_data->security = WIFI_SECURITY_PSK;
273         } else if (strcmp(str_keymgmt, "wpa-ft-eap") == 0) {
274                 bss_data->security = WIFI_SECURITY_IEEE8021X;
275         } else if (strcmp(str_keymgmt, "wpa-eap") == 0) {
276                 bss_data->security = WIFI_SECURITY_IEEE8021X;
277         } else if (strcmp(str_keymgmt, "wpa-eap-sha256") == 0) {
278                 bss_data->security = WIFI_SECURITY_IEEE8021X;
279         } else if (strcmp(str_keymgmt, "wps") == 0) {
280                 bss_data->wps = TRUE;
281         }
282 }
283
284 static void __netconfig_wifi_parse_keymgmt_message(DBusMessageIter *iter, struct bss_info_t *bss_data)
285 {
286         DBusMessageIter dict, entry, array, value;
287         const char *key;
288
289         if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
290                 return;
291
292         dbus_message_iter_recurse(iter, &dict);
293         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
294                 dbus_message_iter_recurse(&dict, &entry);
295
296                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
297                         return;
298
299                 dbus_message_iter_get_basic(&entry, &key);
300                 if (g_strcmp0(key, "KeyMgmt") == 0) {
301                         dbus_message_iter_next(&entry);
302
303                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
304                                 return;
305
306                         dbus_message_iter_recurse(&entry, &array);
307                         if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_ARRAY)
308                                 return;
309
310                         dbus_message_iter_recurse(&array, &value);
311                         while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
312                                 const char *str = NULL;
313
314                                 dbus_message_iter_get_basic(&value, &str);
315                                 if (str == NULL)
316                                         return;
317
318                                 __netconfig_wifi_check_security(str, bss_data);
319                                 dbus_message_iter_next(&value);
320                         }
321                 }
322
323                 dbus_message_iter_next(&dict);
324         }
325 }
326
327 gboolean netconfig_wifi_get_ssid_scan_state(void)
328 {
329         return wifi_ssid_scan_state;
330 }
331
332 void netconfig_wifi_notify_ssid_scan_done(void)
333 {
334         if (netconfig_wifi_get_ssid_scan_state() != TRUE)
335                 return;
336
337         __netconfig_wifi_ssid_scan_finished();
338
339         __netconfig_wifi_notify_ssid_scan_done();
340
341         netconfig_wifi_bgscan_start();
342 }
343
344 void netconfig_wifi_bss_added(DBusMessage *message)
345 {
346         DBusMessageIter iter, dict, entry;
347         DBusMessageIter value, array;
348         const char *key;
349         struct bss_info_t *bss_info;
350
351         if (netconfig_wifi_get_ssid_scan_state() != TRUE)
352                 return;
353
354         INFO("NEW BSS added");
355
356         if (!dbus_message_iter_init(message, &iter)) {
357                 DBG("Message does not have parameters");
358                 return;
359         }
360
361         dbus_message_iter_next(&iter);
362
363         if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
364                 DBG("Invalid message type");
365                 return;
366         }
367
368         bss_info = g_try_new0(struct bss_info_t, 1);
369         if (bss_info == NULL) {
370                 DBG("Out of memory");
371                 return;
372         }
373
374         dbus_message_iter_recurse(&iter, &dict);
375         while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
376                 dbus_message_iter_recurse(&dict, &entry);
377
378                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
379                         goto error;
380
381                 dbus_message_iter_get_basic(&entry, &key);
382                 if (key == NULL)
383                         goto error;
384
385                 dbus_message_iter_next(&entry);
386                 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
387                         goto error;
388
389                 dbus_message_iter_recurse(&entry, &value);
390
391                 if (g_strcmp0(key, "SSID") == 0) {
392                         unsigned char *ssid;
393                         int ssid_len;
394
395                         dbus_message_iter_recurse(&value, &array);
396                         dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
397
398                         if (ssid_len > 0 && ssid_len < 33)
399                                 memcpy(bss_info->ssid, ssid, ssid_len);
400                         else
401                                 memset(bss_info->ssid, 0, sizeof(bss_info->ssid));
402                 } else if (g_strcmp0(key, "Privacy") == 0) {
403                         dbus_bool_t privacy = FALSE;
404
405                         dbus_message_iter_get_basic(&value, &privacy);
406                         bss_info->privacy = privacy;
407                 } else if ((g_strcmp0(key, "RSN") == 0) || (g_strcmp0(key, "WPA") == 0)) {
408
409                         __netconfig_wifi_parse_keymgmt_message(&value, bss_info);
410                 } else if (g_strcmp0(key, "IEs") == 0) {
411                         unsigned char *ie;
412                         int ie_len;
413
414                         dbus_message_iter_recurse(&value, &array);
415                         dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
416                 }
417
418                 dbus_message_iter_next(&dict);
419         }
420
421         if (bss_info->ssid[0] == 0)
422                 goto error;
423
424         if (bss_info->security == WIFI_SECURITY_UNKNOWN) {
425                 if (bss_info->privacy == TRUE)
426                         bss_info->security = WIFI_SECURITY_WEP;
427                 else
428                         bss_info->security = WIFI_SECURITY_NONE;
429         }
430
431         wifi_bss_info_list = g_slist_append(wifi_bss_info_list, bss_info);
432         return;
433
434 error:
435         g_free(bss_info);
436 }
437
438 gboolean netconfig_wifi_ssid_scan(const char *ssid)
439 {
440         char object_path[DBUS_PATH_MAX_BUFLEN] = { 0, };
441         char *path_ptr = &object_path[0];
442         static char *scan_ssid = NULL;
443
444         netconfig_wifi_bgscan_stop();
445
446         if (ssid != NULL) {
447                 g_free(scan_ssid);
448                 scan_ssid = g_strdup(ssid);
449         }
450
451         if (scan_ssid == NULL) {
452                 netconfig_wifi_bgscan_start();
453                 return FALSE;
454         }
455
456         if (netconfig_wifi_get_scanning() == TRUE) {
457                 DBG("Wi-Fi scan is in progress! SSID %s scan will be delayed",
458                                 scan_ssid);
459                 return FALSE;
460         }
461
462         INFO("Start SSID Scan with %s", scan_ssid);
463
464         if (wifi_bss_info_list) {
465                 g_slist_free_full(wifi_bss_info_list, g_free);
466                 wifi_bss_info_list = NULL;
467         }
468
469         if (netconfig_wifi_get_supplicant_interface(&path_ptr) != TRUE) {
470                 DBG("Fail to get wpa_supplicant DBus path");
471                 return FALSE;
472         }
473
474         if (__netconfig_wifi_invoke_ssid_scan(
475                         (const char *)object_path, (const char *)scan_ssid) == TRUE) {
476                 __netconfig_wifi_ssid_scan_started();
477
478                 g_free(scan_ssid);
479                 scan_ssid = NULL;
480
481                 return TRUE;
482         }
483
484         return FALSE;
485 }
486
487 gboolean netconfig_iface_wifi_request_specific_scan(NetconfigWifi *wifi,
488                 gchar *ssid, GError **error)
489 {
490         g_return_val_if_fail(wifi != NULL, FALSE);
491         g_return_val_if_fail(ssid != NULL, FALSE);
492
493         netconfig_wifi_ssid_scan((const char *)ssid);
494
495         return TRUE;
496 }