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.
28 #include "wifi-power.h"
29 #include "wifi-state.h"
30 #include "netsupplicant.h"
31 #include "wifi-background-scan.h"
33 #define NETCONFIG_SSID_LEN 32
34 #define NETCONFIG_BSSID_LEN 6
35 #define NETCONFIG_WPS_DBUS_REPLY_TIMEOUT (10 * 1000)
37 #define VCONF_WIFI_ALWAYS_ALLOW_SCANNING \
38 "file/private/wifi/always_allow_scanning"
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;
45 struct wps_bss_info_t {
46 unsigned char ssid[NETCONFIG_SSID_LEN + 1];
47 unsigned char bssid[NETCONFIG_BSSID_LEN + 1];
53 static GSList *wps_bss_info_list = NULL;
55 static void __netconfig_wps_set_mode(gboolean enable)
57 if (netconfig_is_wps_enabled == enable)
60 netconfig_is_wps_enabled = enable;
63 gboolean netconfig_wifi_is_wps_enabled(void)
65 return netconfig_is_wps_enabled;
68 static void __netconfig_wifi_wps_notify_scan_done(void)
71 DBusConnection *connection = NULL;
72 DBusMessageIter dict, type, array, value, iter;
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";
82 dbus_error_init(&error);
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);
91 signal = dbus_message_new_signal(NETCONFIG_WIFI_PATH,
92 NETCONFIG_WIFI_INTERFACE, sig_name);
94 dbus_connection_unref(connection);
98 dbus_message_iter_init_append(signal, &array);
99 dbus_message_iter_open_container(&array, DBUS_TYPE_ARRAY, "{sv}", &dict);
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;
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]);
115 DBG("BSS found; SSID %s, BSSID %s, RSSI %d MODE %d", ssid, bssid_str, rssi, mode);
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,
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);
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);
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);
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);
152 dbus_message_iter_close_container(&array, &dict);
154 dbus_connection_send(connection, signal, NULL);
156 dbus_message_unref(signal);
157 dbus_connection_unref(connection);
159 g_slist_free_full(wps_bss_info_list, g_free);
160 wps_bss_info_list = NULL;
161 wps_bss_list_count = 0;
164 static void __netconfig_wifi_wps_get_bss_info_result(
165 DBusPendingCall *call, void *data)
168 DBusMessageIter iter;
169 DBusMessageIter dict;
170 struct wps_bss_info_t *bss_info;
172 reply = dbus_pending_call_steal_reply(call);
174 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
177 if (dbus_message_iter_init(reply, &iter) == FALSE)
180 bss_info = g_try_new0(struct wps_bss_info_t, 1);
181 if (bss_info == NULL)
184 if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY) {
185 dbus_message_iter_recurse(&iter, &dict);
187 while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
188 DBusMessageIter entry, value;
191 dbus_message_iter_recurse(&dict, &entry);
193 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
196 dbus_message_iter_get_basic(&entry, &key);
197 dbus_message_iter_next(&entry);
199 if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
202 dbus_message_iter_recurse(&entry, &value);
205 if (g_strcmp0(key, "BSSID") == 0) {
206 DBusMessageIter array;
207 unsigned char *bssid;
210 dbus_message_iter_recurse(&value, &array);
211 dbus_message_iter_get_fixed_array(&array, &bssid, &bssid_len);
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;
220 dbus_message_iter_recurse(&value, &array);
221 dbus_message_iter_get_fixed_array(&array, &ssid, &ssid_len);
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;
227 memset(bss_info->ssid, 0, sizeof(bss_info->ssid));
228 bss_info->ssid_len = 0;
230 } else if (g_strcmp0(key, "Mode") == 0) {;
231 const char *mode = NULL;
233 dbus_message_iter_get_basic(&value, &mode);
238 if (g_str_equal(mode, "infrastructure") == TRUE)
240 else if (g_str_equal(mode, "ad-hoc") == TRUE)
245 } else if (g_strcmp0(key, "Signal") == 0) {
246 dbus_int16_t signal = 0;
248 dbus_message_iter_get_basic(&value, &signal);
250 bss_info->rssi = signal;
254 dbus_message_iter_next(&dict);
258 if (bss_info->ssid[0] == '\0')
261 wps_bss_info_list = g_slist_append(wps_bss_info_list, bss_info);
264 dbus_message_unref(reply);
266 dbus_pending_call_unref(call);
268 wps_bss_list_count--;
269 if (wps_bss_list_count <= 0) {
270 __netconfig_wifi_wps_notify_scan_done();
272 if (netconfig_is_wps_scan_aborted == FALSE)
273 netconfig_wifi_driver_and_supplicant(FALSE);
277 static void __netconfig_wifi_wps_get_bss_info(const char *path, int index)
279 gboolean reply = FALSE;
281 char *param_array[] = { NULL, NULL };
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);
289 ERR("Fail to invoke_dbus_method_nonblock GetAll");
295 static void __netconfig_wifi_wps_get_bsss_result(
296 DBusPendingCall *call, void *data)
299 DBusMessageIter iter;
302 reply = dbus_pending_call_steal_reply(call);
304 if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR)
307 if (dbus_message_iter_init(reply, &iter) == FALSE)
310 if (dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_VARIANT) {
311 DBusMessageIter variant, entry;
313 dbus_message_iter_recurse(&iter, &variant);
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);
322 dbus_message_iter_next(&entry);
328 dbus_message_unref(reply);
330 dbus_pending_call_unref(call);
333 static int _netconfig_wifi_wps_get_bsss(void)
335 gboolean reply = FALSE;
336 const char *if_path = NULL;
338 char param1[] = "string:BSSs";
339 char *param_array[] = { NULL, NULL, NULL };
341 if_path = netconfig_wifi_get_supplicant_interface();
342 if (if_path == NULL) {
343 DBG("Fail to get wpa_supplicant DBus path");
347 param0 = g_strdup_printf("string:%s", SUPPLICANT_IFACE_INTERFACE);
348 param_array[0] = param0;
349 param_array[1] = param1;
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);
355 ERR("Fail to invoke_dbus_method_nonblock Get");
367 void netconfig_wifi_wps_signal_scandone(void)
369 wps_bss_list_count = 0;
370 _netconfig_wifi_wps_get_bsss();
372 netconfig_is_device_scanning = FALSE;
374 __netconfig_wps_set_mode(FALSE);
377 void netconfig_wifi_wps_signal_scanaborted(void)
379 wps_bss_list_count = 0;
380 netconfig_is_wps_scan_aborted = TRUE;
381 _netconfig_wifi_wps_get_bsss();
383 netconfig_is_device_scanning = FALSE;
385 __netconfig_wps_set_mode(FALSE);
388 static int __netconfig_wifi_wps_request_scan(const char *if_path)
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";
400 if_path = netconfig_wifi_get_supplicant_interface();
402 if (if_path == NULL) {
403 DBG("Fail to get wpa_supplicant DBus path");
407 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
408 if (connection == NULL) {
409 ERR("Failed to get system bus");
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);
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);
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);
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);
435 dbus_message_iter_close_container(&entry, &value);
436 dbus_message_iter_close_container(&dict, &entry);
437 dbus_message_iter_close_container(&iter, &dict);
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");
444 dbus_message_unref(message);
445 dbus_connection_unref(connection);
450 dbus_pending_call_cancel(call);
451 dbus_message_unref(message);
452 dbus_connection_unref(connection);
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;
460 netconfig_is_wps_scan_aborted = FALSE;
465 static void __netconfig_wifi_interface_create_result(
466 DBusPendingCall *call, void *data)
468 DBusMessage *message;
469 DBusMessageIter iter;
470 const char *path = NULL;
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);
478 __netconfig_wifi_wps_request_scan(path);
480 DBG("Failed to create interface");
483 dbus_message_unref(message);
484 dbus_pending_call_unref(call);
487 static int __netconfig_wifi_wps_create_interface(void)
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;
497 connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
498 if (connection == NULL) {
499 ERR("Failed to get system bus");
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);
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,
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);
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");
532 dbus_message_unref(message);
533 dbus_connection_unref(connection);
538 dbus_pending_call_set_notify(call,
539 __netconfig_wifi_interface_create_result, NULL, NULL);
541 dbus_message_unref(message);
542 dbus_connection_unref(connection);
547 static int __netconfig_wifi_wps_scan(void)
550 enum netconfig_wifi_tech_state wifi_tech_state;
552 if (netconfig_is_device_scanning == TRUE)
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);
559 if (err < 0 && err != -EALREADY)
562 netconfig_is_device_scanning = TRUE;
564 if (wifi_tech_state >= NETCONFIG_WIFI_TECH_POWERED) {
565 if (netconfig_wifi_get_scanning() == TRUE)
568 netconfig_wifi_bgscan_start();
570 if (wifi_tech_state == NETCONFIG_WIFI_TECH_CONNECTED)
571 __netconfig_wifi_wps_request_scan(NULL);
573 err = __netconfig_wifi_wps_create_interface();
579 gboolean netconfig_iface_wifi_request_wps_scan(NetconfigWifi *wifi,
582 int err, enabled = 0;
583 enum netconfig_wifi_tech_state wifi_tech_state;
585 g_return_val_if_fail(wifi != NULL, FALSE);
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);
592 netconfig_error_permission_denied(error);
597 __netconfig_wps_set_mode(TRUE);
599 err = __netconfig_wifi_wps_scan();
601 if (err == -EINPROGRESS)
602 netconfig_error_inprogress(error);
604 netconfig_error_wifi_driver_failed(error);