2 * Network Configuration Module
4 * Copyright (c) 2000 - 2012 Samsung Electronics Co., Ltd. All rights reserved.
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
10 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 #include "netsupplicant.h"
24 #include "wifi-bssid-scan.h"
26 #include "wifi-power.h"
27 #include "wifi-state.h"
28 #include "wifi-scan.h"
29 #include "wifi-background-scan.h"
31 #define NETCONFIG_SSID_LEN 32
32 #define NETCONFIG_BSSID_LEN 6
34 #define VCONF_WIFI_ALWAYS_ALLOW_SCANNING \
35 "file/private/wifi/always_allow_scanning"
38 unsigned char ssid[NETCONFIG_SSID_LEN + 1];
39 unsigned char bssid[NETCONFIG_BSSID_LEN + 1];
48 GSList *scan_info_list;
51 static GSList *g_bssid_scan_list = NULL;
53 static void __free_bssid_scan_data(gpointer data)
55 bssid_scan_data_s *scan_data = data;
57 g_slist_free_full(scan_data->scan_info_list, g_free);
58 g_free(scan_data->interface_name);
62 static bssid_scan_data_s *__create_bssid_scan_data(const char *interface_name)
64 bssid_scan_data_s *scan_data;
66 scan_data = g_try_new0(bssid_scan_data_s, 1);
67 if (scan_data == NULL)
70 scan_data->interface_name = g_strdup(interface_name);
72 g_bssid_scan_list = g_slist_append(g_bssid_scan_list, scan_data);
77 static bssid_scan_data_s *__get_bssid_scan_data(const char *interface_name)
80 bssid_scan_data_s *scan_data = NULL;
82 for (list = g_bssid_scan_list; list; list = list->next) {
83 scan_data = list->data;
84 if (g_strcmp0(scan_data->interface_name, interface_name) == 0)
88 scan_data = __create_bssid_scan_data(interface_name);
92 static void __update_bssid_scan_info_count(const char *interface_name,
95 bssid_scan_data_s *scan_data;
97 scan_data = __get_bssid_scan_data(interface_name);
98 if (scan_data == NULL)
102 scan_data->scan_info_count--;
104 scan_data->scan_info_count++;
107 static int __get_bssid_scan_info_count(const char *interface_name)
109 bssid_scan_data_s *scan_data;
111 scan_data = __get_bssid_scan_data(interface_name);
112 if (scan_data == NULL)
115 return scan_data->scan_info_count;
118 static void __append_bssid_scan_info(const char *interface_name,
119 bssid_scan_info_s *scan_info)
121 bssid_scan_data_s *scan_data;
123 scan_data = __get_bssid_scan_data(interface_name);
124 if (scan_data == NULL)
127 scan_data->scan_info_list = g_slist_append(scan_data->scan_info_list, scan_info);
130 static void __destroy_bssid_scan_data(const char *interface_name)
132 bssid_scan_data_s *scan_data;
134 scan_data = __get_bssid_scan_data(interface_name);
135 if (scan_data == NULL)
138 g_bssid_scan_list = g_slist_remove(g_bssid_scan_list, scan_data);
139 __free_bssid_scan_data(scan_data);
142 static void __netconfig_wifi_bssid_notify_scan_done(const char *interface_name)
144 GVariantBuilder *builder = NULL;
145 GVariantBuilder *builder1 = NULL;
147 const char *prop_ssid = "ssid";
148 const char *prop_bssid = "bssid";
149 const char *prop_rssi = "rssi";
150 const char *prop_mode = "mode";
151 bssid_scan_data_s *scan_data = NULL;
153 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
155 scan_data = __get_bssid_scan_data(interface_name);
156 if (scan_data == NULL)
159 for (list = scan_data->scan_info_list; list != NULL; list = list->next) {
160 bssid_scan_info_s *bss_info = (bssid_scan_info_s *)list->data;
163 gchar bssid_buff[18] = { 0, };
164 gchar *bssid_str = bssid_buff;
165 unsigned char *ssid = (unsigned char *)bss_info->ssid;
166 int ssid_len = (int)bss_info->ssid_len;
167 int rssi = (int)bss_info->rssi;
168 int mode = (int)bss_info->mode;
170 g_snprintf(bssid_buff, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
171 bss_info->bssid[0], bss_info->bssid[1], bss_info->bssid[2],
172 bss_info->bssid[3], bss_info->bssid[4], bss_info->bssid[5]);
174 DBG("BSS found; SSID %s, BSSID %s, RSSI %d MODE %d", ssid, bssid_str, rssi, mode);
176 builder1 = g_variant_builder_new(G_VARIANT_TYPE("ay"));
177 for (i = 0; i < ssid_len; i++)
178 g_variant_builder_add(builder1, "y", ssid[i]);
179 g_variant_builder_add(builder, "{sv}", prop_ssid, g_variant_builder_end(builder1));
180 g_variant_builder_unref(builder1);
182 g_variant_builder_add(builder, "{sv}", prop_bssid, g_variant_new_string(bssid_str));
183 g_variant_builder_add(builder, "{sv}", prop_rssi, g_variant_new_int32(rssi));
184 g_variant_builder_add(builder, "{sv}", prop_mode, g_variant_new_int32(mode));
189 wifi_emit_bssid_scan_completed((Wifi *)get_wifi_object(),
190 interface_name, g_variant_builder_end(builder));
191 g_variant_builder_unref(builder);
193 __destroy_bssid_scan_data(interface_name);
195 INFO("BSSIDScanCompleted");
200 static void __netconfig_wifi_bssid_get_bss_info_result(
201 GObject *source_object, GAsyncResult *res, gpointer user_data)
203 GVariant *reply = NULL;
207 bssid_scan_info_s *bss_info;
208 GDBusConnection *conn = NULL;
209 GError *error = NULL;
210 char *interface_name = user_data;
212 conn = G_DBUS_CONNECTION(source_object);
213 reply = g_dbus_connection_call_finish(conn, res, &error);
216 ERR("Error code: [%d] Error message: [%s]", error->code, error->message);
221 bss_info = g_try_new0(bssid_scan_info_s, 1);
222 if (bss_info == NULL)
225 g_variant_get(reply, "(a{sv})", &iter);
226 while (g_variant_iter_loop(iter, "{sv}", &key, &value)) {
228 if (g_strcmp0(key, "BSSID") == 0) {
232 bssid = g_variant_get_fixed_array(value, &bssid_len, sizeof(guchar));
233 if (bssid != NULL && bssid_len == NETCONFIG_BSSID_LEN)
234 memcpy(bss_info->bssid, bssid, bssid_len);
235 } else if (g_strcmp0(key, "SSID") == 0) {
239 ssid = g_variant_get_fixed_array(value, &ssid_len, sizeof(guchar));
240 if (ssid != NULL && ssid_len > 0 && ssid_len <= NETCONFIG_SSID_LEN) {
241 memcpy(bss_info->ssid, ssid, ssid_len);
242 bss_info->ssid_len = ssid_len;
244 memset(bss_info->ssid, 0, sizeof(bss_info->ssid));
245 bss_info->ssid_len = 0;
247 } else if (g_strcmp0(key, "Mode") == 0) {
250 g_variant_get(value, "s", &mode);
254 if (g_strcmp0(mode, "infrastructure") == 0)
256 else if (g_strcmp0(mode, "ad-hoc") == 0)
262 } else if (g_strcmp0(key, "Signal") == 0) {
265 signal = g_variant_get_int16(value);
266 bss_info->rssi = signal;
271 if (bss_info->ssid[0] == '\0')
274 __append_bssid_scan_info(interface_name, bss_info);
276 g_variant_iter_free(iter);
279 g_variant_unref(reply);
281 netconfig_gdbus_pending_call_unref();
283 __update_bssid_scan_info_count(interface_name, 0);
284 if (__get_bssid_scan_info_count(interface_name) <= 0) {
285 __netconfig_wifi_bssid_notify_scan_done(interface_name);
287 if (netconfig_wifi_bssidscan_get_aborted(interface_name) == FALSE)
288 wifi_power_driver_and_supplicant(interface_name, FALSE);
291 g_free(interface_name);
294 static void __netconfig_wifi_bssid_get_bss_info(const char *interface_name,
297 gboolean reply = FALSE;
298 GVariant *param = NULL;
300 param = g_variant_new("(s)", SUPPLICANT_IFACE_BSS);
302 reply = netconfig_invoke_dbus_method_nonblock(SUPPLICANT_SERVICE,
303 path, DBUS_INTERFACE_PROPERTIES, "GetAll", param,
304 __netconfig_wifi_bssid_get_bss_info_result,
305 g_strdup(interface_name));
307 ERR("Fail to invoke_dbus_method_nonblock GetAll");
312 static void __netconfig_wifi_bssid_get_bss_result(GObject *source_object,
313 GAsyncResult *res, gpointer user_data)
315 GVariant *reply = NULL;
316 GVariant *value = NULL;
317 GVariantIter *iter = NULL;
318 GDBusConnection *conn = NULL;
320 gboolean counter_flag = FALSE;
321 GError *error = NULL;
322 char *interface_name = user_data;
324 conn = G_DBUS_CONNECTION(source_object);
325 reply = g_dbus_connection_call_finish(conn, res, &error);
327 ERR("Error code: [%d] Error message: [%s]", error->code, error->message);
332 g_variant_get(reply, "(v)", &value);
333 if (g_variant_is_of_type(value, G_VARIANT_TYPE_OBJECT_PATH_ARRAY)) {
334 g_variant_get(value, "ao", &iter);
335 while (g_variant_iter_next(iter, "o", &path)) {
336 if (path != NULL && g_strcmp0(path, "/") != 0) {
337 __update_bssid_scan_info_count(interface_name, 1);
338 __netconfig_wifi_bssid_get_bss_info(interface_name, path);
349 g_variant_iter_free(iter);
352 g_variant_unref(value);
356 g_variant_unref(reply);
358 netconfig_gdbus_pending_call_unref();
360 /* Send BssidScanCompleted signal even when the BSS count is 0 */
361 if (__get_bssid_scan_info_count(interface_name) <= 0 && counter_flag == FALSE) {
362 __netconfig_wifi_bssid_notify_scan_done(interface_name);
364 if (netconfig_wifi_bssidscan_get_aborted(interface_name) == FALSE)
365 wifi_power_driver_and_supplicant(interface_name, FALSE);
368 g_free(interface_name);
371 static int _netconfig_wifi_bssid_get_bss(const char *interface_name)
373 gboolean reply = FALSE;
374 char *if_path = NULL;
375 GVariant *params = NULL;
377 if_path = netconfig_wifi_get_supplicant_interface_path(interface_name);
378 if (if_path == NULL) {
379 DBG("Fail to get wpa_supplicant DBus path");
383 params = g_variant_new("(ss)", SUPPLICANT_IFACE_INTERFACE, "BSSs");
385 reply = netconfig_invoke_dbus_method_nonblock(SUPPLICANT_SERVICE,
386 if_path, DBUS_INTERFACE_PROPERTIES, "Get", params,
387 __netconfig_wifi_bssid_get_bss_result,
388 g_strdup(interface_name));
392 ERR("Fail to method: Get");
400 void netconfig_wifi_bssid_signal_scandone(const char *interface_name)
402 _netconfig_wifi_bssid_get_bss(interface_name);
404 netconfig_wifi_bssidscan_set_scanning(interface_name, FALSE);
405 netconfig_wifi_bssidscan_set_mode(interface_name, FALSE);
408 void netconfig_wifi_bssid_signal_scanaborted(const char *interface_name)
410 netconfig_wifi_bssidscan_set_aborted(interface_name, TRUE);
411 _netconfig_wifi_bssid_get_bss(interface_name);
413 netconfig_wifi_bssidscan_set_scanning(interface_name, FALSE);
414 netconfig_wifi_bssidscan_set_mode(interface_name, FALSE);
417 static void __netconfig_wifi_bssid_scan_request_reply(GObject *source_object,
418 GAsyncResult *res, gpointer user_data)
421 GDBusConnection *conn = NULL;
422 GError *error = NULL;
424 conn = G_DBUS_CONNECTION(source_object);
425 message = g_dbus_connection_call_finish(conn, res, &error);
427 if (message == NULL) {
429 ERR("Fail to request status [%d: %s]", error->code, error->message);
432 ERR("Fail to request bssid scan");
435 DBG("Successfully requested bssid scan");
436 g_variant_unref(message);
439 netconfig_gdbus_pending_call_unref();
442 static int __netconfig_wifi_bssid_request_scan(const char *interface_name, char *if_path)
444 GVariant *message = NULL;
445 GVariantBuilder *builder = NULL;
446 const char *key1 = "Type";
447 const char *val1 = "passive";
448 gboolean is_free_required = FALSE;
449 gboolean reply = FALSE;
451 if (if_path == NULL) {
452 if_path = netconfig_wifi_get_supplicant_interface_path(interface_name);
453 is_free_required = TRUE;
456 if (if_path == NULL) {
457 DBG("Fail to get wpa_supplicant DBus path");
461 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
462 g_variant_builder_add(builder, "{sv}", key1, g_variant_new_string(val1));
463 message = g_variant_new("(@a{sv})", g_variant_builder_end(builder));
464 g_variant_builder_unref(builder);
466 DBG("[net-config]: TizenMW-->WPAS: .Interface.Scan");
467 reply = netconfig_supplicant_invoke_dbus_method_nonblock(
470 SUPPLICANT_INTERFACE ".Interface",
473 (GAsyncReadyCallback) __netconfig_wifi_bssid_scan_request_reply,
481 netconfig_wifi_bssidscan_set_scanning(interface_name, TRUE);
484 if (is_free_required)
487 /* Clear bss_info_list for the next scan result */
488 __destroy_bssid_scan_data(interface_name);
490 netconfig_wifi_bssidscan_set_aborted(interface_name, FALSE);
495 static void __netconfig_wifi_interface_create_result(
496 GObject *source_object, GAsyncResult *res, gpointer user_data)
498 GVariant *message = NULL;
500 GDBusConnection *conn = NULL;
501 GError *error = NULL;
502 char *interface_name = user_data;
504 conn = G_DBUS_CONNECTION(source_object);
506 message = g_dbus_connection_call_finish(conn, res, &error);
508 g_variant_get(message, "(o)", &path);
511 __netconfig_wifi_bssid_request_scan(interface_name, path);
514 } else if (NULL != strstr(error->message, ".InterfaceExists")) {
515 INFO("Error Message %s %s", error->message, path);
516 g_variant_get(message, "(o)", &path);
518 __netconfig_wifi_bssid_request_scan(interface_name, path);
521 __netconfig_wifi_bssid_request_scan(interface_name, NULL);
525 ERR("Failed to create interface, Error: %d[%s]", error->code, error->message);
526 netconfig_wifi_bssidscan_set_mode(interface_name, FALSE);
527 wifi_power_driver_and_supplicant(interface_name, FALSE);
531 g_variant_unref(message);
532 g_free(interface_name);
533 netconfig_gdbus_pending_call_unref();
536 static int __netconfig_wifi_bssid_create_interface(const char *interface_name)
538 GVariant *message = NULL;
539 GVariantBuilder *builder = NULL;
540 const char *key = "Ifname";
541 gboolean reply = FALSE;
543 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
544 g_variant_builder_add(builder, "{sv}", key, g_variant_new_string(interface_name));
545 message = g_variant_new("(@a{sv})", g_variant_builder_end(builder));
546 g_variant_builder_unref(builder);
548 DBG("[net-config]: TizenMW-->WPAS: CreateInterface");
549 reply = netconfig_supplicant_invoke_dbus_method_nonblock(
552 SUPPLICANT_INTERFACE,
555 (GAsyncReadyCallback) __netconfig_wifi_interface_create_result,
556 g_strdup(interface_name));
559 ERR("Fail to CreateInterface");
564 static int __netconfig_wifi_bssid_scan(const char *interface_name)
567 wifi_tech_state_e wifi_tech_state;
569 if (netconfig_wifi_bssidscan_get_scanning(interface_name) == TRUE)
572 wifi_tech_state = wifi_state_get_technology_state(interface_name);
573 if (wifi_tech_state <= NETCONFIG_WIFI_TECH_OFF)
574 err = wifi_power_driver_and_supplicant(interface_name, TRUE);
576 if (err < 0 && err != -EALREADY)
579 netconfig_wifi_bssidscan_set_scanning(interface_name, TRUE);
581 DBG("BSSID scan requested");
582 if (wifi_tech_state >= NETCONFIG_WIFI_TECH_POWERED) {
583 if (netconfig_wifi_scan_get_scanning(interface_name) == TRUE)
586 netconfig_wifi_bgscan_start(interface_name, TRUE);
588 if (wifi_tech_state == NETCONFIG_WIFI_TECH_CONNECTED)
589 __netconfig_wifi_bssid_request_scan(interface_name, NULL);
591 err = __netconfig_wifi_bssid_create_interface(interface_name);
597 gboolean handle_request_bssid_scan(Wifi *wifi, GDBusMethodInvocation *context,
600 int err, enabled = 0;
601 wifi_tech_state_e tech_state;
603 g_return_val_if_fail(wifi != NULL, TRUE);
605 if (netconfig_is_wifi_tethering_on() == TRUE) {
606 ERR("Wi-Fi Tethering is enabled");
607 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_NO_SERVICE, "TetheringEnabled");
611 #if !defined TIZEN_WEARABLE
612 if (netconfig_wifi_bgscan_is_paused(ifname)) {
613 ERR("Scan is paused");
614 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_NO_SERVICE, "ScanPaused");
619 tech_state = wifi_state_get_technology_state(ifname);
620 if (tech_state <= NETCONFIG_WIFI_TECH_OFF) {
621 #if !defined TIZEN_WEARABLE
628 netconfig_error_permission_denied(context);
633 netconfig_wifi_bssidscan_set_mode(ifname, TRUE);
635 err = __netconfig_wifi_bssid_scan(ifname);
637 if (err == -EINPROGRESS)
638 netconfig_error_inprogress(context);
640 netconfig_error_wifi_driver_failed(context);
645 wifi_complete_request_bssid_scan(wifi, context);
649 gboolean handle_get_bssid_list(Wifi *wifi, GDBusMethodInvocation *context,
652 __create_bssid_scan_data(ifname);
653 _netconfig_wifi_bssid_get_bss(ifname);
655 wifi_complete_get_bssid_list(wifi, context);