Initialize Tizen 2.3
[framework/connectivity/net-config.git] / wearable / src / wifi-wps.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 <errno.h>
21 #include <vconf.h>
22
23 #include "log.h"
24 #include "util.h"
25 #include "netdbus.h"
26 #include "neterror.h"
27 #include "wifi-wps.h"
28 #include "wifi-power.h"
29 #include "wifi-state.h"
30 #include "netsupplicant.h"
31 #include "wifi-background-scan.h"
32
33 #define NETCONFIG_SSID_LEN                                              32
34 #define NETCONFIG_BSSID_LEN                                             6
35 #define NETCONFIG_WPS_DBUS_REPLY_TIMEOUT                (10 * 1000)
36
37 #define VCONF_WIFI_ALWAYS_ALLOW_SCANNING \
38         "file/private/wifi/always_allow_scanning"
39
40 static gboolean netconfig_is_wps_enabled = FALSE;
41 static gboolean netconfig_is_device_scanning = FALSE;
42 static gboolean netconfig_is_wps_scan_aborted = FALSE;
43 static int wps_bss_list_count = 0;
44
45 struct wps_bss_info_t {
46         unsigned char ssid[NETCONFIG_SSID_LEN + 1];
47         unsigned char bssid[NETCONFIG_BSSID_LEN + 1];
48         int ssid_len;
49         int rssi;
50         int mode;
51 };
52
53 static GSList *wps_bss_info_list = NULL;
54
55 static void __netconfig_wps_set_mode(gboolean enable)
56 {
57         if (netconfig_is_wps_enabled == enable)
58                 return;
59
60         netconfig_is_wps_enabled = enable;
61 }
62
63 gboolean netconfig_wifi_is_wps_enabled(void)
64 {
65         return netconfig_is_wps_enabled;
66 }
67
68 static void __netconfig_wifi_wps_notify_scan_done(void)
69 {
70         DBusMessage *signal;
71         DBusConnection *connection = NULL;
72         DBusMessageIter dict, type, array, value, iter;
73         DBusError error;
74
75         GSList* list = NULL;
76         const char *prop_ssid = "ssid";
77         const char *prop_bssid = "bssid";
78         const char *prop_rssi = "rssi";
79         const char *prop_mode = "mode";
80         const char *sig_name = "WpsScanCompleted";
81
82         dbus_error_init(&error);
83
84         connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
85         if (connection == NULL) {
86                 ERR("Failed to get system DBus, error [%s]", error.message);
87                 dbus_error_free(&error);
88                 return;
89         }
90
91         signal = dbus_message_new_signal(NETCONFIG_WIFI_PATH,
92                                                 NETCONFIG_WIFI_INTERFACE, sig_name);
93         if (signal == NULL) {
94                 dbus_connection_unref(connection);
95                 return;
96         }
97
98         dbus_message_iter_init_append(signal, &array);
99         dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY, "{sv}", &dict);
100
101         for (list = wps_bss_info_list; list != NULL; list = list->next) {
102                 struct wps_bss_info_t *bss_info = (struct wps_bss_info_t *)list->data;
103
104                 if (bss_info) {
105                         char bssid_buff[18] = { 0, };
106                         char *bssid_str = bssid_buff;
107                         unsigned char *ssid = (unsigned char *)bss_info->ssid;
108                         int ssid_len = (int)bss_info->ssid_len;
109                         int rssi = (int)bss_info->rssi;
110                         int mode = (int)bss_info->mode;
111                         g_snprintf(bssid_buff, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
112                                         bss_info->bssid[0], bss_info->bssid[1], bss_info->bssid[2],
113                                         bss_info->bssid[3], bss_info->bssid[4], bss_info->bssid[5]);
114
115                         DBG("BSS found; SSID %s, BSSID %s, RSSI %d MODE %d", ssid, bssid_str, rssi, mode);
116
117                         dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, 0, &type);
118                         dbus_message_iter_append_basic(&type, DBUS_TYPE_STRING, &prop_ssid);
119                         dbus_message_iter_open_container(&type, DBUS_TYPE_VARIANT,
120                                         DBUS_TYPE_ARRAY_AS_STRING
121                                         DBUS_TYPE_BYTE_AS_STRING,
122                                         &value);
123                         dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &iter);
124                         dbus_message_iter_append_fixed_array(&iter, DBUS_TYPE_BYTE, &ssid, ssid_len);
125                         dbus_message_iter_close_container(&value, &iter);
126                         dbus_message_iter_close_container(&type, &value);
127                         dbus_message_iter_close_container(&dict, &type);
128
129                         dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, 0, &type);
130                         dbus_message_iter_append_basic(&type, DBUS_TYPE_STRING, &prop_bssid);
131                         dbus_message_iter_open_container(&type, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &value);
132                         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &bssid_str);
133                         dbus_message_iter_close_container(&type, &value);
134                         dbus_message_iter_close_container(&dict, &type);
135
136                         dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, 0, &type);
137                         dbus_message_iter_append_basic(&type, DBUS_TYPE_STRING, &prop_rssi);
138                         dbus_message_iter_open_container(&type, DBUS_TYPE_VARIANT, DBUS_TYPE_INT32_AS_STRING, &value);
139                         dbus_message_iter_append_basic(&value, DBUS_TYPE_INT32, &rssi);
140                         dbus_message_iter_close_container(&type, &value);
141                         dbus_message_iter_close_container(&dict, &type);
142
143                         dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY, 0, &type);
144                         dbus_message_iter_append_basic(&type, DBUS_TYPE_STRING, &prop_mode);
145                         dbus_message_iter_open_container(&type, DBUS_TYPE_VARIANT, DBUS_TYPE_INT32_AS_STRING, &value);
146                         dbus_message_iter_append_basic(&value, DBUS_TYPE_INT32, &mode);
147                         dbus_message_iter_close_container(&type, &value);
148                         dbus_message_iter_close_container(&dict, &type);
149                 }
150         }
151
152         dbus_message_iter_close_container(&array, &dict);
153
154         dbus_connection_send(connection, signal, NULL);
155
156         dbus_message_unref(signal);
157         dbus_connection_unref(connection);
158
159         g_slist_free_full(wps_bss_info_list, g_free);
160         wps_bss_info_list = NULL;
161         wps_bss_list_count = 0;
162 }
163
164 static void __netconfig_wifi_wps_get_bss_info_result(
165                 DBusPendingCall *call, void *data)
166 {
167         DBusMessage *reply;
168         DBusMessageIter iter;
169         DBusMessageIter dict;
170         struct wps_bss_info_t *bss_info;
171
172         reply = dbus_pending_call_steal_reply(call);
173
174         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
175                 goto done;
176
177         if (dbus_message_iter_init(reply, &iter) == FALSE)
178                 goto done;
179
180         bss_info = g_try_new0(struct wps_bss_info_t, 1);
181         if (bss_info == NULL)
182                 goto done;
183
184         if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY) {
185                 dbus_message_iter_recurse(&iter, &dict);
186
187                 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
188                         DBusMessageIter entry, value;
189                         const char *key;
190
191                         dbus_message_iter_recurse(&dict, &entry);
192
193                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
194                                 break;
195
196                         dbus_message_iter_get_basic(&entry, &key);
197                         dbus_message_iter_next(&entry);
198
199                         if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
200                                 break;
201
202                         dbus_message_iter_recurse(&entry, &value);
203
204                         if (key != NULL) {
205                                 if (g_strcmp0(key, "BSSID") == 0) {
206                                         DBusMessageIter array;
207                                         unsigned char *bssid;
208                                         int bssid_len;
209
210                                         dbus_message_iter_recurse(&value, &array);
211                                         dbus_message_iter_get_fixed_array(&array, &bssid, &bssid_len);
212
213                                         if (bssid_len == NETCONFIG_BSSID_LEN)
214                                                 memcpy(bss_info->bssid, bssid, bssid_len);
215                                 } else if (g_strcmp0(key, "SSID") == 0) {
216                                         DBusMessageIter array;
217                                         unsigned char *ssid;
218                                         int ssid_len;
219
220                                         dbus_message_iter_recurse(&value, &array);
221                                         dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
222
223                                         if (ssid_len > 0 && ssid_len <= NETCONFIG_SSID_LEN) {
224                                                 memcpy(bss_info->ssid, ssid, ssid_len);
225                                                 bss_info->ssid_len = ssid_len;
226                                         } else {
227                                                 memset(bss_info->ssid, 0, sizeof(bss_info->ssid));
228                                                 bss_info->ssid_len = 0;
229                                         }
230                                 } else if (g_strcmp0(key, "Mode") == 0) {;
231                                         const char *mode = NULL;
232
233                                         dbus_message_iter_get_basic(&value, &mode);
234
235                                         if (mode == NULL)
236                                                 bss_info->mode = 0;
237                                         else {
238                                                 if (g_str_equal(mode, "infrastructure") == TRUE)
239                                                         bss_info->mode = 1;
240                                                 else if (g_str_equal(mode, "ad-hoc") == TRUE)
241                                                         bss_info->mode = 2;
242                                                 else
243                                                         bss_info->mode = 0;
244                                         }
245                                 } else if (g_strcmp0(key, "Signal") == 0) {
246                                         dbus_int16_t signal = 0;
247
248                                         dbus_message_iter_get_basic(&value, &signal);
249
250                                         bss_info->rssi = signal;
251                                 }
252                         }
253
254                         dbus_message_iter_next(&dict);
255                 }
256         }
257
258         if (bss_info->ssid[0] == '\0')
259                 g_free(bss_info);
260         else
261                 wps_bss_info_list = g_slist_append(wps_bss_info_list, bss_info);
262
263 done:
264         dbus_message_unref(reply);
265
266         dbus_pending_call_unref(call);
267
268         wps_bss_list_count--;
269         if (wps_bss_list_count <= 0) {
270                 __netconfig_wifi_wps_notify_scan_done();
271
272                 if (netconfig_is_wps_scan_aborted == FALSE)
273                         netconfig_wifi_driver_and_supplicant(FALSE);
274         }
275 }
276
277 static void __netconfig_wifi_wps_get_bss_info(const char *path, int index)
278 {
279         gboolean reply = FALSE;
280         char *param0 = NULL;
281         char *param_array[] = { NULL, NULL };
282
283         param0 = g_strdup_printf("string:%s", SUPPLICANT_IFACE_BSS);
284         param_array[0] = param0;
285         reply = netconfig_invoke_dbus_method_nonblock(SUPPLICANT_SERVICE,
286                         path, DBUS_INTERFACE_PROPERTIES,
287                         "GetAll", param_array, __netconfig_wifi_wps_get_bss_info_result);
288         if (reply != TRUE)
289                 ERR("Fail to invoke_dbus_method_nonblock GetAll");
290
291         if (param0)
292                 g_free(param0);
293 }
294
295 static void __netconfig_wifi_wps_get_bsss_result(
296                 DBusPendingCall *call, void *data)
297 {
298         DBusMessage *reply;
299         DBusMessageIter iter;
300         char *path;
301
302         reply = dbus_pending_call_steal_reply(call);
303
304         if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
305                 goto done;
306
307         if (dbus_message_iter_init(reply, &iter) == FALSE)
308                 goto done;
309
310         if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_VARIANT) {
311                 DBusMessageIter variant, entry;
312
313                 dbus_message_iter_recurse(&iter, &variant);
314
315                 if (dbus_message_iter_get_arg_type(&variant) == DBUS_TYPE_ARRAY) {
316                         dbus_message_iter_recurse(&variant, &entry);
317                         while (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_INVALID) {
318                                 dbus_message_iter_get_basic(&entry, &path);
319                                 if (path != NULL && g_strcmp0(path, "/") != 0)
320                                         __netconfig_wifi_wps_get_bss_info(path, ++wps_bss_list_count);
321
322                                 dbus_message_iter_next(&entry);
323                         }
324                 }
325         }
326
327 done:
328         dbus_message_unref(reply);
329
330         dbus_pending_call_unref(call);
331 }
332
333 static int _netconfig_wifi_wps_get_bsss(void)
334 {
335         gboolean reply = FALSE;
336         const char *if_path = NULL;
337         char *param0 = NULL;
338         char param1[] = "string:BSSs";
339         char *param_array[] = { NULL, NULL, NULL };
340
341         if_path = netconfig_wifi_get_supplicant_interface();
342         if (if_path == NULL) {
343                 DBG("Fail to get wpa_supplicant DBus path");
344                 return -ESRCH;
345         }
346
347         param0 = g_strdup_printf("string:%s", SUPPLICANT_IFACE_INTERFACE);
348         param_array[0] = param0;
349         param_array[1] = param1;
350
351         reply = netconfig_invoke_dbus_method_nonblock(SUPPLICANT_SERVICE,
352                         if_path, DBUS_INTERFACE_PROPERTIES,
353                         "Get", param_array, __netconfig_wifi_wps_get_bsss_result);
354         if (reply != TRUE) {
355                 ERR("Fail to invoke_dbus_method_nonblock Get");
356
357                 if (param0)
358                         g_free(param0);
359                 return -ESRCH;
360         }
361
362         if (param0)
363                 g_free(param0);
364         return 0;
365 }
366
367 void netconfig_wifi_wps_signal_scandone(void)
368 {
369         wps_bss_list_count = 0;
370         _netconfig_wifi_wps_get_bsss();
371
372         netconfig_is_device_scanning = FALSE;
373
374         __netconfig_wps_set_mode(FALSE);
375 }
376
377 void netconfig_wifi_wps_signal_scanaborted(void)
378 {
379         wps_bss_list_count = 0;
380         netconfig_is_wps_scan_aborted = TRUE;
381         _netconfig_wifi_wps_get_bsss();
382
383         netconfig_is_device_scanning = FALSE;
384
385         __netconfig_wps_set_mode(FALSE);
386 }
387
388 static int __netconfig_wifi_wps_request_scan(const char *if_path)
389 {
390         dbus_bool_t result = FALSE;
391         DBusConnection *connection = NULL;
392         DBusMessage *message = NULL;
393         DBusPendingCall *call;
394         DBusMessageIter iter, dict, entry;
395         DBusMessageIter value;
396         const char *key1 = "Type";
397         const char *val1 = "passive";
398
399         if (if_path == NULL)
400                 if_path = netconfig_wifi_get_supplicant_interface();
401
402         if (if_path == NULL) {
403                 DBG("Fail to get wpa_supplicant DBus path");
404                 return -ESRCH;
405         }
406
407         connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
408         if (connection == NULL) {
409                 ERR("Failed to get system bus");
410                 return -EIO;
411         }
412
413         message = dbus_message_new_method_call(SUPPLICANT_SERVICE,
414                                         if_path, SUPPLICANT_INTERFACE ".Interface", "Scan");
415         if (message == NULL) {
416                 ERR("Failed DBus method call");
417                 dbus_connection_unref(connection);
418                 return -EIO;
419         }
420
421         dbus_message_iter_init_append(message, &iter);
422         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
423                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
424                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
425                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
426
427         dbus_message_iter_open_container(&dict,
428                         DBUS_TYPE_DICT_ENTRY, NULL, &entry);
429         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key1);
430
431         dbus_message_iter_open_container(&entry,
432                         DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &value);
433         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &val1);
434
435         dbus_message_iter_close_container(&entry, &value);
436         dbus_message_iter_close_container(&dict, &entry);
437         dbus_message_iter_close_container(&iter, &dict);
438
439         result = dbus_connection_send_with_reply(connection, message, &call,
440                         NETCONFIG_WPS_DBUS_REPLY_TIMEOUT);
441         if (result == FALSE || call == NULL) {
442                 ERR("dbus_connection_send_with_reply() failed");
443
444                 dbus_message_unref(message);
445                 dbus_connection_unref(connection);
446
447                 return -ESRCH;
448         }
449
450         dbus_pending_call_cancel(call);
451         dbus_message_unref(message);
452         dbus_connection_unref(connection);
453
454         /* Clear bss_info_list for the next scan result */
455         if (wps_bss_info_list) {
456                 g_slist_free_full(wps_bss_info_list, g_free);
457                 wps_bss_info_list = NULL;
458         }
459
460         netconfig_is_wps_scan_aborted = FALSE;
461
462         return 0;
463 }
464
465 static void __netconfig_wifi_interface_create_result(
466                 DBusPendingCall *call, void *data)
467 {
468         DBusMessage *message;
469         DBusMessageIter iter;
470         const char *path = NULL;
471
472         message = dbus_pending_call_steal_reply(call);
473         if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_ERROR) {
474                 dbus_message_iter_init(message, &iter);
475                 dbus_message_iter_get_basic(&iter, &path);
476
477                 if (path)
478                         __netconfig_wifi_wps_request_scan(path);
479         } else {
480                 DBG("Failed to create interface");
481         }
482
483         dbus_message_unref(message);
484         dbus_pending_call_unref(call);
485 }
486
487 static int  __netconfig_wifi_wps_create_interface(void)
488 {
489         dbus_bool_t result = FALSE;
490         DBusConnection *connection = NULL;
491         DBusMessage *message = NULL;
492         DBusPendingCall *call;
493         DBusMessageIter iter, dict, entry, value;
494         const char *key = "Ifname";
495         const char *val = WIFI_IFNAME;
496
497         connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
498         if (connection == NULL) {
499                 ERR("Failed to get system bus");
500                 return -EIO;
501         }
502
503         message = dbus_message_new_method_call(SUPPLICANT_SERVICE,
504                                 SUPPLICANT_PATH, SUPPLICANT_INTERFACE, "CreateInterface");
505         if (message == NULL) {
506                 ERR("Failed DBus method call");
507                 dbus_connection_unref(connection);
508                 return -EIO;
509         }
510
511         dbus_message_iter_init_append(message, &iter);
512         dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
513                         DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
514                         DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
515                         DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
516         dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
517                         NULL, &entry);
518
519         dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
520         dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
521                         DBUS_TYPE_STRING_AS_STRING, &value);
522         dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &val);
523         dbus_message_iter_close_container(&entry, &value);
524         dbus_message_iter_close_container(&dict, &entry);
525         dbus_message_iter_close_container(&iter, &dict);
526
527         result = dbus_connection_send_with_reply(connection, message, &call,
528                                 NETCONFIG_WPS_DBUS_REPLY_TIMEOUT);
529         if (result == FALSE || call == NULL) {
530                 ERR("dbus_connection_send_with_reply() failed");
531
532                 dbus_message_unref(message);
533                 dbus_connection_unref(connection);
534
535                 return -ESRCH;
536         }
537
538         dbus_pending_call_set_notify(call,
539                         __netconfig_wifi_interface_create_result, NULL, NULL);
540
541         dbus_message_unref(message);
542         dbus_connection_unref(connection);
543
544         return 0;
545 }
546
547 static int __netconfig_wifi_wps_scan(void)
548 {
549         int err = 0;
550         enum netconfig_wifi_tech_state wifi_tech_state;
551
552         if (netconfig_is_device_scanning == TRUE)
553                 return -EINPROGRESS;
554
555         wifi_tech_state = netconfig_wifi_state_get_technology_state();
556         if (wifi_tech_state <= NETCONFIG_WIFI_TECH_OFF)
557                 err = netconfig_wifi_driver_and_supplicant(TRUE);
558
559         if (err < 0 && err != -EALREADY)
560                 return err;
561
562         netconfig_is_device_scanning = TRUE;
563
564         if (wifi_tech_state >= NETCONFIG_WIFI_TECH_POWERED) {
565                 if (netconfig_wifi_get_scanning() == TRUE)
566                         return -EINPROGRESS;
567
568                 netconfig_wifi_bgscan_start();
569
570                 if (wifi_tech_state == NETCONFIG_WIFI_TECH_CONNECTED)
571                         __netconfig_wifi_wps_request_scan(NULL);
572         } else {
573                 err = __netconfig_wifi_wps_create_interface();
574         }
575
576         return err;
577 }
578
579 gboolean netconfig_iface_wifi_request_wps_scan(NetconfigWifi *wifi,
580                 GError **error)
581 {
582         int err, enabled = 0;
583         enum netconfig_wifi_tech_state wifi_tech_state;
584
585         g_return_val_if_fail(wifi != NULL, FALSE);
586
587         wifi_tech_state = netconfig_wifi_state_get_technology_state();
588         if (wifi_tech_state <= NETCONFIG_WIFI_TECH_OFF) {
589                 vconf_get_int(VCONF_WIFI_ALWAYS_ALLOW_SCANNING, &enabled);
590
591                 if (enabled == 0) {
592                         netconfig_error_permission_denied(error);
593                         return FALSE;
594                 }
595         }
596
597         __netconfig_wps_set_mode(TRUE);
598
599         err = __netconfig_wifi_wps_scan();
600         if (err < 0) {
601                 if (err == -EINPROGRESS)
602                         netconfig_error_inprogress(error);
603                 else
604                         netconfig_error_wifi_driver_failed(error);
605
606                 return FALSE;
607         }
608
609         return TRUE;
610 }