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