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.
26 #include "netsupplicant.h"
27 #include "wifi-ssid-scan.h"
28 #include "wifi-background-scan.h"
30 #define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
31 #define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
33 #define WIFI_KEYMGMT_NONE (1 << 0)
34 #define WIFI_KEYMGMT_IEEE8021X (1 << 1)
35 #define WIFI_KEYMGMT_WPA_NONE (1 << 2)
36 #define WIFI_KEYMGMT_WPA_PSK (1 << 3)
37 #define WIFI_KEYMGMT_WPA_PSK_256 (1 << 4)
38 #define WIFI_KEYMGMT_WPA_FT_PSK (1 << 5)
39 #define WIFI_KEYMGMT_WPA_FT_EAP (1 << 6)
40 #define WIFI_KEYMGMT_WPA_EAP (1 << 7)
41 #define WIFI_KEYMGMT_WPA_EAP_256 (1 << 8)
42 #define WIFI_KEYMGMT_WPS (1 << 9)
44 #define WIFI_PAIRWISE_NONE (1 << 0)
45 #define WIFI_PAIRWISE_TKIP (1 << 1)
46 #define WIFI_PAIRWISE_CCMP (1 << 2)
53 static strval_s wifi_keymgmt[] = {
54 { "none", WIFI_KEYMGMT_NONE },
55 { "ieee8021x", WIFI_KEYMGMT_IEEE8021X },
56 { "wpa-none", WIFI_KEYMGMT_WPA_NONE },
57 { "wpa-psk", WIFI_KEYMGMT_WPA_PSK },
58 { "wpa-psk-sha256", WIFI_KEYMGMT_WPA_PSK_256 },
59 { "wpa-ft-psk", WIFI_KEYMGMT_WPA_FT_PSK },
60 { "wpa-ft-eap", WIFI_KEYMGMT_WPA_FT_EAP },
61 { "wpa-eap", WIFI_KEYMGMT_WPA_EAP },
62 { "wpa-eap-sha256", WIFI_KEYMGMT_WPA_EAP_256 },
63 { "wps", WIFI_KEYMGMT_WPS },
67 static strval_s wifi_pairwise[] = {
68 { "none", WIFI_PAIRWISE_NONE },
69 { "tkip", WIFI_PAIRWISE_TKIP },
70 { "ccmp", WIFI_PAIRWISE_CCMP },
75 WIFI_SECURITY_UNKNOWN = 0x00,
80 WIFI_SECURITY_IEEE8021X,
84 unsigned char ssid[33];
85 unsigned char bssid[6];
86 wifi_security_e security;
87 unsigned int wpa_keymgmt;
88 unsigned int wpa_pairwise;
89 unsigned int rsn_keymgmt;
90 unsigned int rsn_pairwise;
91 gboolean rsn_selected;
97 static gboolean g_ssid_scan_state = FALSE;
98 static GSList *bss_info_list = NULL;
99 static guint ssid_scan_timer = 0;
100 static char *g_ssid = NULL;
102 static void __check_keymgmt(const char *str_keymgmt, unsigned int *key_info)
106 for (i = 0; wifi_keymgmt[i].str; i++) {
107 if (g_strcmp0(str_keymgmt, wifi_keymgmt[i].str) == 0) {
108 INFO("keymgmt : %s", str_keymgmt);
109 *key_info |= wifi_keymgmt[i].val;
115 static void __check_pairwise(const char *str_pairwise, unsigned int *pairwise_info)
119 for (i = 0; wifi_pairwise[i].str; i++) {
120 if (g_strcmp0(str_pairwise, wifi_pairwise[i].str) == 0) {
121 INFO("pairwise : %s", str_pairwise);
122 *pairwise_info |= wifi_pairwise[i].val;
128 static wifi_security_e __check_security(bss_info_t *bss_info)
130 gboolean ieee8021x = FALSE;
131 gboolean psk = FALSE;
132 gboolean ft_ieee8021x = FALSE;
133 gboolean ft_psk = FALSE;
134 unsigned int keymgmt = bss_info->rsn_keymgmt | bss_info->wpa_keymgmt;
136 if (keymgmt & (WIFI_KEYMGMT_WPA_EAP | WIFI_KEYMGMT_WPA_EAP_256))
138 else if (keymgmt & WIFI_KEYMGMT_WPA_FT_EAP)
141 if (keymgmt & (WIFI_KEYMGMT_WPA_PSK | WIFI_KEYMGMT_WPA_PSK_256))
143 else if (keymgmt & WIFI_KEYMGMT_WPA_FT_PSK)
146 if (ieee8021x || ft_ieee8021x)
147 bss_info->security = WIFI_SECURITY_IEEE8021X;
148 else if (psk || ft_psk)
149 bss_info->security = WIFI_SECURITY_PSK;
150 else if (bss_info->privacy)
151 bss_info->security = WIFI_SECURITY_WEP;
153 bss_info->security = WIFI_SECURITY_NONE;
155 if (bss_info->rsn_selected) {
156 unsigned int pairwise = bss_info->rsn_pairwise | bss_info->wpa_pairwise;
157 if ((pairwise & WIFI_PAIRWISE_CCMP) ||
158 (pairwise & (WIFI_PAIRWISE_CCMP | WIFI_PAIRWISE_TKIP)))
159 bss_info->security = WIFI_SECURITY_PSK2;
162 return bss_info->security;
165 static gboolean __ssid_scan_timeout(gpointer data)
167 wifi_ssid_scan_emit_scan_completed();
172 static void _start_ssid_scan_timer(void)
174 INFO("Wi-Fi SSID scan started");
175 g_ssid_scan_state = TRUE;
177 netconfig_start_timer_seconds(5, __ssid_scan_timeout, NULL, &ssid_scan_timer);
180 static void _stop_ssid_scan_timer(void)
182 INFO("Wi-Fi SSID scan finished");
183 g_ssid_scan_state = FALSE;
185 netconfig_stop_timer(&ssid_scan_timer);
188 static void _parse_wpa_message(GVariant *param, bss_info_t *bss_info)
194 g_variant_get(param, "a{sv}", &iter1);
195 while (g_variant_iter_loop(iter1, "{sv}", &key, &var)) {
196 if (g_strcmp0(key, "KeyMgmt") == 0) {
198 g_variant_get(var, "as", &iter2);
200 while (g_variant_iter_loop(iter2, "s", &str)) {
203 unsigned int key_info = 0;
204 __check_keymgmt(str, &key_info);
205 if (bss_info->rsn_selected)
206 bss_info->rsn_keymgmt = key_info;
208 bss_info->wpa_keymgmt = key_info;
210 g_variant_iter_free(iter2);
211 } else if (g_strcmp0(key, "Pairwise") == 0) {
213 g_variant_get(var, "as", &iter2);
215 while (g_variant_iter_loop(iter2, "s", &str)) {
218 unsigned int pairwise_info = 0;
219 __check_pairwise(str, &pairwise_info);
220 if (bss_info->rsn_selected)
221 bss_info->rsn_pairwise = pairwise_info;
223 bss_info->wpa_pairwise = pairwise_info;
225 g_variant_iter_free(iter2);
229 g_variant_iter_free(iter1);
234 static gboolean _request_ssid_scan(const char *object_path, const char *ssid)
236 /* TODO: Revise following code */
238 GDBusConnection *connection = NULL;
239 GVariant *reply = NULL;
240 GVariant *params = NULL;
241 GError *error = NULL;
242 GVariantBuilder *builder1 = NULL;
243 GVariantBuilder *builder2 = NULL;
244 GVariantBuilder *builder3 = NULL;
245 const gchar *key1 = "Type";
246 const gchar *val1 = "active";
247 const gchar *key2 = "SSIDs";
250 connection = netdbus_get_connection();
251 if (connection == NULL) {
252 DBG("Failed to get GDBusconnection");
256 builder1 = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
257 g_variant_builder_add(builder1, "{sv}", key1, g_variant_new_string(val1));
259 builder2 = g_variant_builder_new(G_VARIANT_TYPE("aay"));
260 builder3 = g_variant_builder_new(G_VARIANT_TYPE("ay"));
262 for (i = 0; i < strlen(ssid); i++)
263 g_variant_builder_add(builder3, "y", ssid[i]);
265 g_variant_builder_add(builder2, "@ay", g_variant_builder_end(builder3));
266 g_variant_builder_add(builder1, "{sv}", key2, g_variant_builder_end(builder2));
268 params = g_variant_new("(@a{sv})", g_variant_builder_end(builder1));
270 g_variant_builder_unref(builder1);
271 g_variant_builder_unref(builder2);
272 g_variant_builder_unref(builder3);
274 reply = g_dbus_connection_call_sync(
278 SUPPLICANT_INTERFACE ".Interface",
282 G_DBUS_CALL_FLAGS_NONE,
283 NETCONFIG_DBUS_REPLY_TIMEOUT,
284 netdbus_get_cancellable(),
289 ERR("Error!!! dbus_connection_send_with_reply_and_block() failed. "
290 "DBus error [%d: %s]", error->code, error->message);
293 ERR("Error!!! Failed to get properties");
301 g_ssid = g_strdup(ssid);
303 g_variant_unref(reply);
308 static void _emit_ssid_scan_completed(void)
310 GVariantBuilder *builder = NULL;
312 const char *prop_ssid = "ssid";
313 const char *prop_bssid = "bssid";
314 char bssid_buf[18] = {0,};
315 char *bssid_str = bssid_buf;
316 const char *prop_security = "security";
317 const char *prop_wps = "wps";
318 GVariantBuilder *rawssid_builder = NULL;
319 const char *prop_raw_ssid = "raw_ssid";
321 builder = g_variant_builder_new(G_VARIANT_TYPE("a{sv}"));
322 for (list = bss_info_list; list != NULL; list = list->next) {
323 bss_info_t *bss_info = (bss_info_t *)list->data;
324 if (bss_info && g_strcmp0((char *)bss_info->ssid, g_ssid) == 0) {
325 const gchar *ssid = (char *)bss_info->ssid;
326 int ssid_len = bss_info->ssid_len;
327 const gchar *bssid = (gchar *)&bss_info->bssid[0];
330 wifi_security_e security = __check_security(bss_info);
331 gboolean wps = bss_info->wps;
332 DBG("BSS found; SSID:%s security:%d WPS:%d", ssid, security, wps);
335 snprintf(bssid_str, sizeof(bssid_buf), MACSTR, MAC2STR(bssid));
336 DBG("BSSID: %s", bssid_str);
339 g_variant_builder_add(builder, "{sv}", prop_ssid, g_variant_new_string(ssid));
341 /* append raw SSID in bytes to the specific
342 scan completed signal here */
343 rawssid_builder = g_variant_builder_new(G_VARIANT_TYPE("ay"));
344 for (i = 0; i < ssid_len; i++)
345 g_variant_builder_add(rawssid_builder, "y", ssid[i]);
346 g_variant_builder_add(builder, "{sv}", prop_raw_ssid, g_variant_new("ay", rawssid_builder));
347 g_variant_builder_unref(rawssid_builder);
349 g_variant_builder_add(builder, "{sv}", prop_bssid,
350 g_variant_new_string(bssid));
351 g_variant_builder_add(builder, "{sv}", prop_security, g_variant_new_int32(security));
353 g_variant_builder_add(builder, "{sv}", prop_wps, g_variant_new_boolean(wps));
357 wifi_emit_specific_scan_completed((Wifi *)get_wifi_object(), g_variant_builder_end(builder));
360 g_variant_builder_unref(builder);
362 if (bss_info_list != NULL) {
363 g_slist_free_full(bss_info_list, g_free);
364 bss_info_list = NULL;
367 if (g_ssid != NULL) {
372 INFO("SpecificScanCompleted");
377 gboolean wifi_ssid_scan(const char *ssid)
380 static char *scan_ssid = NULL;
382 netconfig_wifi_bgscan_stop();
385 if (scan_ssid != NULL)
387 scan_ssid = g_strdup(ssid);
390 if (scan_ssid == NULL)
393 if_path = netconfig_wifi_get_supplicant_interface();
394 if (if_path == NULL) {
395 DBG("Fail to get wpa_supplicant DBus path");
399 if (netconfig_wifi_get_scanning() == TRUE) {
400 DBG("Wi-Fi scan in progress, %s scan will be delayed", scan_ssid);
405 g_slist_free_full(bss_info_list, g_free);
406 bss_info_list = NULL;
409 INFO("Start Wi-Fi scan with %s(%d)", scan_ssid, strlen(scan_ssid));
410 if (_request_ssid_scan(if_path, (const char *)scan_ssid) == TRUE) {
411 _start_ssid_scan_timer();
418 if (scan_ssid != NULL) {
423 netconfig_wifi_bgscan_start(FALSE);
428 gboolean wifi_ssid_scan_get_state(void)
430 return g_ssid_scan_state;
433 void wifi_ssid_scan_emit_scan_completed(void)
435 if (g_ssid_scan_state != TRUE)
438 _stop_ssid_scan_timer();
439 _emit_ssid_scan_completed();
440 netconfig_wifi_bgscan_start(FALSE);
443 void wifi_ssid_scan_add_bss(GVariant *message)
449 bss_info_t *bss_info;
451 if (g_ssid_scan_state != TRUE)
454 INFO("NEW BSS added");
456 if (message == NULL) {
457 DBG("Message does not have parameters");
462 INFO("Object path of BSS added is %s", path);
464 bss_info = g_try_new0(bss_info_t, 1);
465 if (bss_info == NULL)
468 g_variant_get(message, "(oa{sv})", &path, &iter);
469 while (g_variant_iter_loop(iter, "{sv}", &key, &value)) {
470 if (g_strcmp0(key, "SSID") == 0) {
473 ssid = g_variant_get_fixed_array(value, &ssid_len, sizeof(guchar));
474 if (ssid != NULL && ssid_len > 0 && ssid_len < 33) {
475 memcpy(bss_info->ssid, ssid, ssid_len);
476 bss_info->ssid_len = ssid_len;
478 memset(bss_info->ssid, 0, sizeof(bss_info->ssid));
479 bss_info->ssid_len = 0;
481 } else if (g_strcmp0(key, "Privacy") == 0) {
482 gboolean privacy = FALSE;
483 privacy = g_variant_get_boolean(value);
484 bss_info->privacy = privacy;
485 } else if (g_strcmp0(key, "RSN") == 0) {
486 bss_info->rsn_selected = TRUE;
487 _parse_wpa_message(value, bss_info);
488 } else if (g_strcmp0(key, "WPA") == 0) {
489 bss_info->rsn_selected = FALSE;
490 _parse_wpa_message(value, bss_info);
491 } else if (g_strcmp0(key, "IEs") == 0) {
494 ie = g_variant_get_fixed_array(value, &ie_len, sizeof(guchar));
495 DBG("The IE : %s", ie);
496 } else if (g_strcmp0(key, "BSSID") == 0) {
500 bssid = g_variant_get_fixed_array(value, &bssid_len, sizeof(guchar));
501 if (bssid != NULL && bssid_len == 6)
502 memcpy(bss_info->bssid, bssid, bssid_len);
506 g_variant_iter_free(iter);
510 if (bss_info->ssid[0] == '\0') {
515 if (bss_info->security == WIFI_SECURITY_UNKNOWN) {
516 if (bss_info->privacy == TRUE)
517 bss_info->security = WIFI_SECURITY_WEP;
519 bss_info->security = WIFI_SECURITY_NONE;
522 bss_info_list = g_slist_append(bss_info_list, bss_info);
525 gboolean handle_request_specific_scan(Wifi *wifi,
526 GDBusMethodInvocation *context, const gchar *ssid)
528 gboolean result = FALSE;
530 g_return_val_if_fail(wifi != NULL, FALSE);
531 g_return_val_if_fail(ssid != NULL, FALSE);
533 result = wifi_ssid_scan((const char *)ssid);
536 netconfig_error_dbus_method_return(context, NETCONFIG_ERROR_INTERNAL, "FailSpecificScan");
538 wifi_complete_request_specific_scan(wifi, context);