Sync with Tizen 2.4(v1.1.38)
[platform/core/connectivity/net-config.git] / 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 #include <glib.h>
23
24 #include "log.h"
25 #include "util.h"
26 #include "netdbus.h"
27 #include "neterror.h"
28 #include "wifi-wps.h"
29 #include "wifi-power.h"
30 #include "wifi-state.h"
31 #include "netsupplicant.h"
32 #include "wifi-background-scan.h"
33
34 #define NETCONFIG_SSID_LEN                                              32
35 #define NETCONFIG_BSSID_LEN                                             6
36 #define NETCONFIG_WPS_DBUS_REPLY_TIMEOUT                (10 * 1000)
37
38 #define VCONF_WIFI_ALWAYS_ALLOW_SCANNING \
39         "file/private/wifi/always_allow_scanning"
40
41 static gboolean netconfig_is_wps_enabled = FALSE;
42 static gboolean netconfig_is_device_scanning = FALSE;
43 static gboolean netconfig_is_wps_scan_aborted = FALSE;
44 static int wps_bss_list_count = 0;
45
46 struct wps_bss_info_t {
47         unsigned char ssid[NETCONFIG_SSID_LEN + 1];
48         unsigned char bssid[NETCONFIG_BSSID_LEN + 1];
49         int ssid_len;
50         int rssi;
51         int mode;
52 };
53
54 static GSList *wps_bss_info_list = NULL;
55
56 static void __netconfig_wps_set_mode(gboolean enable)
57 {
58         if (netconfig_is_wps_enabled == enable)
59                 return;
60
61         netconfig_is_wps_enabled = enable;
62 }
63
64 gboolean netconfig_wifi_is_wps_enabled(void)
65 {
66         return netconfig_is_wps_enabled;
67 }
68
69 static void __netconfig_wifi_wps_notify_scan_done(void)//check this
70 {
71         GVariantBuilder *builder = NULL;
72         GVariantBuilder *builder1 = NULL;
73         GSList* list = NULL;
74         const char *prop_ssid = "ssid";
75         const char *prop_bssid = "bssid";
76         const char *prop_rssi = "rssi";
77         const char *prop_mode = "mode";
78
79         builder = g_variant_builder_new(G_VARIANT_TYPE ("a{sv}"));
80         for (list = wps_bss_info_list; list != NULL; list = list->next) {
81                 struct wps_bss_info_t *bss_info = (struct wps_bss_info_t *)list->data;
82
83                 if (bss_info) {
84                         gchar bssid_buff[18] = { 0, };
85                         gchar *bssid_str = bssid_buff;
86                         unsigned char *ssid = (unsigned char *)bss_info->ssid;
87                         int ssid_len = (int)bss_info->ssid_len;
88                         int rssi = (int)bss_info->rssi;
89                         int mode = (int)bss_info->mode;
90                         int i = 0;
91                         g_snprintf(bssid_buff, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
92                                         bss_info->bssid[0], bss_info->bssid[1], bss_info->bssid[2],
93                                         bss_info->bssid[3], bss_info->bssid[4], bss_info->bssid[5]);
94
95                         DBG("BSS found; SSID %s, BSSID %s, RSSI %d MODE %d", ssid, bssid_str, rssi, mode);
96
97                         builder1 = g_variant_builder_new (G_VARIANT_TYPE ("ay"));
98                         for (i = 0; i < ssid_len; i++) {
99                                 g_variant_builder_add (builder1, "y", ssid[i]);
100                         }
101                         g_variant_builder_add(builder, "{sv}", prop_ssid, g_variant_builder_end(builder1));
102                         g_variant_builder_unref(builder1);
103
104                         g_variant_builder_add(builder, "{sv}", prop_bssid, g_variant_new_string(bssid_str));
105                         g_variant_builder_add(builder, "{sv}", prop_rssi, g_variant_new_int32(rssi));
106                         g_variant_builder_add(builder, "{sv}", prop_mode, g_variant_new_int32(mode));
107                 }
108         }
109
110         wifi_emit_wps_scan_completed((Wifi *)get_wifi_object(), g_variant_builder_end(builder));
111         g_variant_builder_unref(builder);
112
113         if (wps_bss_info_list != NULL) {
114                 g_slist_free_full(wps_bss_info_list, g_free);
115         }
116
117         wps_bss_info_list = NULL;
118         wps_bss_list_count = 0;
119         INFO("WpsScanCompleted");
120
121         return;
122 }
123
124 static void __netconfig_wifi_wps_get_bss_info_result(
125                 GObject *source_object, GAsyncResult *res, gpointer user_data)
126 {
127         GVariant *reply = NULL;
128         GVariant *value;
129         GVariantIter *iter;
130         gchar *key;
131         struct wps_bss_info_t *bss_info;
132         GDBusConnection *conn = NULL;
133         GError *error = NULL;
134
135         conn = G_DBUS_CONNECTION (source_object);
136         reply = g_dbus_connection_call_finish(conn, res, &error);
137
138         if (error != NULL) {
139                 ERR("Error code: [%d] Error message: [%s]", error->code, error->message);
140                 g_error_free(error);
141                 goto done;
142         }
143
144         bss_info = g_try_new0(struct wps_bss_info_t, 1);
145         if (bss_info == NULL)
146                 goto done;
147
148         g_variant_get(reply, "(a{sv})", &iter);
149         while (g_variant_iter_loop(iter, "{sv}", &key, &value)) {
150                 if (key != NULL) {
151                         if (g_strcmp0(key, "BSSID") == 0) {
152                                 const guchar *bssid;
153                                 gsize bssid_len;
154
155                                 bssid = g_variant_get_fixed_array(value, &bssid_len, sizeof(guchar));
156                                 if (bssid_len == NETCONFIG_BSSID_LEN)
157                                         memcpy(bss_info->bssid, bssid, bssid_len);
158                         } else if (g_strcmp0(key, "SSID") == 0) {
159                                 const guchar *ssid;
160                                 gsize ssid_len;
161
162                                 ssid = g_variant_get_fixed_array(value, &ssid_len, sizeof(guchar));
163                                 if (ssid != NULL && ssid_len > 0 && ssid_len <= NETCONFIG_SSID_LEN) {
164                                         memcpy(bss_info->ssid, ssid, ssid_len);
165                                         bss_info->ssid_len = ssid_len;
166                                 } else {
167                                         memset(bss_info->ssid, 0, sizeof(bss_info->ssid));
168                                         bss_info->ssid_len = 0;
169                                 }
170                         } else if (g_strcmp0(key, "Mode") == 0) {
171                                 gchar *mode = NULL;
172
173                                 g_variant_get(value, "s", &mode);
174                                 if (mode == NULL)
175                                         bss_info->mode = 0;
176                                 else {
177                                         if (g_strcmp0(mode, "infrastructure") == 0)
178                                                 bss_info->mode = 1;
179                                         else if (g_strcmp0(mode, "ad-hoc") == 0)
180                                                 bss_info->mode = 2;
181                                         else
182                                                 bss_info->mode = 0;
183                                         g_free(mode);
184                                 }
185                         } else if (g_strcmp0(key, "Signal") == 0) {
186                                 gint16 signal;
187
188                                 signal = g_variant_get_int16(value);
189                                 bss_info->rssi = signal;
190                         }
191                 }
192         }
193
194         if (bss_info->ssid[0] == '\0')
195                 g_free(bss_info);
196         else
197                 wps_bss_info_list = g_slist_append(wps_bss_info_list, bss_info);
198
199         g_variant_iter_free(iter);
200 done:
201         if (reply)
202                 g_variant_unref(reply);
203
204         netconfig_gdbus_pending_call_unref();
205
206         wps_bss_list_count--;
207         if (wps_bss_list_count <= 0) {
208                 __netconfig_wifi_wps_notify_scan_done();
209
210                 if (netconfig_is_wps_scan_aborted == FALSE)
211                         wifi_power_driver_and_supplicant(FALSE);
212         }
213 }
214
215 static void __netconfig_wifi_wps_get_bss_info(const char *path, int index)
216 {
217         gboolean reply = FALSE;
218         GVariant *param = NULL;
219
220         param = g_variant_new("(s)", SUPPLICANT_IFACE_BSS);
221
222         reply = netconfig_invoke_dbus_method_nonblock(SUPPLICANT_SERVICE,
223                         path, DBUS_INTERFACE_PROPERTIES,
224                         "GetAll", param, __netconfig_wifi_wps_get_bss_info_result);
225         if (reply != TRUE)
226                 ERR("Fail to invoke_dbus_method_nonblock GetAll");
227
228         return;
229 }
230
231 static void __netconfig_wifi_wps_get_bsss_result(GObject *source_object,
232                 GAsyncResult *res, gpointer user_data)
233 {
234         GVariant *reply = NULL;
235         GVariant *value = NULL;
236         GVariantIter *iter = NULL;
237         GDBusConnection *conn = NULL;
238         gchar *path = NULL;
239         gboolean counter_flag = FALSE;
240         GError *error = NULL;
241
242         conn = G_DBUS_CONNECTION (source_object);
243         reply = g_dbus_connection_call_finish(conn, res, &error);
244         if (error != NULL) {
245                 ERR("Error code: [%d] Error message: [%s]", error->code, error->message);
246                 g_error_free(error);
247                 goto done;
248         }
249
250         g_variant_get(reply, "(v)", &value);
251         if (g_variant_is_of_type(value, G_VARIANT_TYPE_OBJECT_PATH_ARRAY)) {
252                 g_variant_get(value, "ao", &iter);
253                 while (g_variant_iter_next(iter, "o", &path)) {
254                         if (path != NULL && g_strcmp0(path, "/") != 0) {
255                                 __netconfig_wifi_wps_get_bss_info(path, ++wps_bss_list_count);
256
257                                 counter_flag = TRUE;
258                         }
259
260                         if (path)
261                                 g_free(path);
262                 }
263         }
264
265         if (iter)
266                 g_variant_iter_free(iter);
267
268         if (value)
269                 g_variant_unref(value);
270
271 done:
272         if (reply)
273                 g_variant_unref(reply);
274
275         netconfig_gdbus_pending_call_unref();
276
277         /* Send WpsScanCompleted signal even when the BSS count is 0 */
278         if (wps_bss_list_count <= 0 && counter_flag == FALSE) {
279                 __netconfig_wifi_wps_notify_scan_done();
280
281                 if (netconfig_is_wps_scan_aborted == FALSE)
282                         wifi_power_driver_and_supplicant(FALSE);
283         }
284 }
285
286 static int _netconfig_wifi_wps_get_bsss(void)
287 {
288         gboolean reply = FALSE;
289         const char *if_path = NULL;
290         GVariant *params = NULL;
291
292         if_path = netconfig_wifi_get_supplicant_interface();
293         if (if_path == NULL) {
294                 DBG("Fail to get wpa_supplicant DBus path");
295                 return -ESRCH;
296         }
297
298         params = g_variant_new("(ss)", SUPPLICANT_IFACE_INTERFACE, "BSSs");
299
300         reply = netconfig_invoke_dbus_method_nonblock(SUPPLICANT_SERVICE,
301                         if_path, DBUS_INTERFACE_PROPERTIES,
302                         "Get", params, __netconfig_wifi_wps_get_bsss_result);
303         if (reply != TRUE) {
304                 ERR("Fail to method: Get");
305
306                 return -ESRCH;
307         }
308
309         return 0;
310 }
311
312 void netconfig_wifi_wps_signal_scandone(void)
313 {
314         wps_bss_list_count = 0;
315         _netconfig_wifi_wps_get_bsss();
316
317         netconfig_is_device_scanning = FALSE;
318
319         __netconfig_wps_set_mode(FALSE);
320 }
321
322 void netconfig_wifi_wps_signal_scanaborted(void)
323 {
324         wps_bss_list_count = 0;
325         netconfig_is_wps_scan_aborted = TRUE;
326         _netconfig_wifi_wps_get_bsss();
327
328         netconfig_is_device_scanning = FALSE;
329
330         __netconfig_wps_set_mode(FALSE);
331 }
332
333 static int __netconfig_wifi_wps_request_scan(const char *if_path)
334 {
335         GDBusConnection *connection = NULL;
336         GVariant *message = NULL;
337         GVariantBuilder *builder = NULL;
338         const char *key1 = "Type";
339         const char *val1 = "passive";
340
341         if (if_path == NULL)
342                 if_path = netconfig_wifi_get_supplicant_interface();
343
344         if (if_path == NULL) {
345                 DBG("Fail to get wpa_supplicant DBus path");
346                 return -ESRCH;
347         }
348
349         connection = netdbus_get_connection();
350         if (connection == NULL) {
351                 ERR("Failed to get GDBusconnection");
352                 return -EIO;
353         }
354
355         builder = g_variant_builder_new(G_VARIANT_TYPE ("a{sv}"));
356         g_variant_builder_add(builder, "{sv}", key1, g_variant_new_string(val1));
357         message = g_variant_new("(@a{sv})", g_variant_builder_end(builder));
358         g_variant_builder_unref(builder);
359
360         g_dbus_connection_call(connection,
361                         SUPPLICANT_SERVICE,
362                         if_path,
363                         SUPPLICANT_INTERFACE ".Interface",
364                         "Scan",
365                         message,
366                         NULL,
367                         G_DBUS_CALL_FLAGS_NONE,
368                         NETCONFIG_WPS_DBUS_REPLY_TIMEOUT,
369                         netdbus_get_cancellable(),
370                         NULL,
371                         NULL);
372
373         netconfig_is_device_scanning = TRUE;
374
375         g_variant_unref(message);
376         /* Clear bss_info_list for the next scan result */
377         if (wps_bss_info_list) {
378                 g_slist_free_full(wps_bss_info_list, g_free);
379                 wps_bss_info_list = NULL;
380         }
381
382         netconfig_is_wps_scan_aborted = FALSE;
383
384         return 0;
385 }
386
387 static void __netconfig_wifi_interface_create_result(
388                 GObject *source_object, GAsyncResult *res, gpointer user_data)
389 {
390         GVariant *message;
391         gchar *path = NULL;
392         GDBusConnection *conn = NULL;
393         GError *error = NULL;
394
395         conn = G_DBUS_CONNECTION (source_object);
396
397         message = g_dbus_connection_call_finish(conn, res, &error);
398         if (error == NULL) {
399                 g_variant_get(message, "(o)", &path);
400
401                 if (path) {
402                         __netconfig_wifi_wps_request_scan(path);
403                         g_free(path);
404                 }
405         } else {
406                 ERR("Failed to create interface, Error: %d[%s]", error->code, error->message);
407                 __netconfig_wps_set_mode(FALSE);
408                 wifi_power_driver_and_supplicant(FALSE);
409         }
410
411         g_variant_unref(message);
412 }
413
414 static int  __netconfig_wifi_wps_create_interface(void)
415 {
416         GDBusConnection *connection = NULL;
417         GVariant *message = NULL;
418         GVariantBuilder *builder = NULL;
419         const char *key = "Ifname";
420         const char *val = WIFI_IFNAME;
421
422         connection = netdbus_get_connection();
423         if (connection == NULL) {
424                 DBG("Failed to get GDBusconnection");
425                 return -EIO;
426         }
427
428         builder = g_variant_builder_new(G_VARIANT_TYPE ("a{sv}"));
429         g_variant_builder_add(builder, "{sv}", key, g_variant_new_string(val));
430         message = g_variant_new("(@a{sv})", g_variant_builder_end(builder));
431
432         g_dbus_connection_call(connection,
433                         SUPPLICANT_SERVICE,
434                         SUPPLICANT_PATH,
435                         SUPPLICANT_INTERFACE,
436                         "CreateInterface",
437                         message,
438                         NULL,
439                         G_DBUS_CALL_FLAGS_NONE,
440                         NETCONFIG_WPS_DBUS_REPLY_TIMEOUT,
441                         netdbus_get_cancellable(),
442                         (GAsyncReadyCallback) __netconfig_wifi_interface_create_result,
443                         NULL);
444
445         g_variant_unref(message);
446
447         return 0;
448 }
449
450 static int __netconfig_wifi_wps_scan(void)
451 {
452         int err = 0;
453         wifi_tech_state_e wifi_tech_state;
454
455         if (netconfig_is_device_scanning == TRUE)
456                 return -EINPROGRESS;
457
458         wifi_tech_state = wifi_state_get_technology_state();
459         if (wifi_tech_state <= NETCONFIG_WIFI_TECH_OFF)
460                 err = wifi_power_driver_and_supplicant(TRUE);
461
462         if (err < 0 && err != -EALREADY)
463                 return err;
464
465         netconfig_is_device_scanning = TRUE;
466
467         DBG("WPS scan requested");
468         if (wifi_tech_state >= NETCONFIG_WIFI_TECH_POWERED) {
469                 if (netconfig_wifi_get_scanning() == TRUE)
470                         return -EINPROGRESS;
471
472                 netconfig_wifi_bgscan_start(TRUE);
473
474                 if (wifi_tech_state == NETCONFIG_WIFI_TECH_CONNECTED)
475                         __netconfig_wifi_wps_request_scan(NULL);
476         } else {
477                 err = __netconfig_wifi_wps_create_interface();
478         }
479
480         return err;
481 }
482
483 gboolean handle_request_wps_scan(Wifi *wifi, GDBusMethodInvocation *context)
484 {
485         int err, enabled = 0;
486         wifi_tech_state_e tech_state;
487
488         g_return_val_if_fail(wifi != NULL, FALSE);
489
490         if (netconfig_is_wifi_tethering_on() == TRUE) {
491                 ERR("Wi-Fi Tethering is enabled");
492                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_NO_SERVICE, "TetheringEnabled");
493                 return -EBUSY;
494         }
495
496 #if !defined TIZEN_WEARABLE
497         if (netconfig_wifi_is_bgscan_paused()) {
498                 ERR("Scan is paused");
499                 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_NO_SERVICE, "ScanPaused");
500                 return FALSE;
501         }
502 #endif
503
504         tech_state = wifi_state_get_technology_state();
505         if (tech_state <= NETCONFIG_WIFI_TECH_OFF) {
506 #if !defined TIZEN_WEARABLE
507                 vconf_get_int(VCONF_WIFI_ALWAYS_ALLOW_SCANNING, &enabled);
508 #else
509                 enabled = 0;
510 #endif
511
512                 if (enabled == 0) {
513                         netconfig_error_permission_denied(context);
514                         return FALSE;
515                 }
516         }
517
518         __netconfig_wps_set_mode(TRUE);
519
520         err = __netconfig_wifi_wps_scan();
521         if (err < 0) {
522                 if (err == -EINPROGRESS)
523                         netconfig_error_inprogress(context);
524                 else
525                         netconfig_error_wifi_driver_failed(context);
526
527                 return FALSE;
528         }
529
530         wifi_complete_request_wps_scan(wifi, context);
531         return TRUE;
532 }
533
534 #if defined TIZEN_TV
535 static void __interface_wps_cancel_result(GObject *source_object,
536                         GAsyncResult *res, gpointer user_data)
537 {
538         GVariant *reply;
539         GDBusConnection *conn = NULL;
540         GError *error = NULL;
541
542         conn = G_DBUS_CONNECTION (source_object);
543         reply = g_dbus_connection_call_finish(conn, res, &error);
544
545         if (reply == NULL) {
546                 if (error != NULL) {
547                         ERR("Fail to request status [%d: %s]",
548                                         error->code, error->message);
549                         g_error_free(error);
550                 } else {
551                         ERR("Fail torequest status");
552                 }
553         } else {
554                 DBG("Successfully M/W--->WPAS: Interface.WPS.Cancel Method");
555         }
556
557         g_variant_unref(reply);
558         netconfig_gdbus_pending_call_unref();
559 }
560
561 static gboolean __netconfig_wifi_invoke_wps_cancel()
562 {
563         gboolean reply = FALSE;
564         const char *if_path = NULL;
565
566         if_path = netconfig_wifi_get_supplicant_interface();
567         if (if_path == NULL) {
568                 DBG("Fail to get wpa_supplicant DBus path");
569                 return -ESRCH;
570         }
571
572         DBG("M/W--->WPAS: Interface.WPS.Cancel Method");
573
574         reply = netconfig_invoke_dbus_method_nonblock(SUPPLICANT_SERVICE,
575                         if_path, SUPPLICANT_IFACE_WPS,
576                         "Cancel", NULL, __interface_wps_cancel_result);
577
578         if (reply != TRUE)
579                 ERR("M/W--->WPAS: Interface.WPS.Cancel Method Failed");
580
581         return reply;
582 }
583 #endif
584
585 gboolean netconfig_iface_wifi_request_wps_cancel(Wifi *wifi, GDBusMethodInvocation **context)
586 {
587 #if defined TIZEN_TV
588         DBG("Received WPS PBC Cancel Request");
589         g_return_val_if_fail(wifi != NULL, FALSE);
590         return __netconfig_wifi_invoke_wps_cancel();
591 #else
592         /*Not supported for mobile and Wearable profile*/
593         return FALSE;
594 #endif
595 }