gsupplicant: Creating an helper function to compute bss security
[platform/upstream/connman.git] / gsupplicant / supplicant.c
index 183e341..8d87dae 100644 (file)
@@ -188,6 +188,7 @@ struct g_supplicant_bss {
        dbus_bool_t privacy;
        dbus_bool_t psk;
        dbus_bool_t ieee8021x;
+       unsigned int wps_capabilities;
 };
 
 struct _GSupplicantNetwork {
@@ -203,6 +204,7 @@ struct _GSupplicantNetwork {
        GSupplicantMode mode;
        GSupplicantSecurity security;
        dbus_bool_t wps;
+       unsigned int wps_capabilities;
        GHashTable *bss_table;
        GHashTable *config_table;
 };
@@ -743,6 +745,37 @@ unsigned int g_supplicant_interface_get_max_scan_ssids(
        return interface->max_scan_ssids;
 }
 
+static void set_network_enabled(DBusMessageIter *iter, void *user_data)
+{
+       dbus_bool_t enable = *(dbus_bool_t *)user_data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &enable);
+}
+
+int g_supplicant_interface_enable_selected_network(GSupplicantInterface *interface,
+                                                       dbus_bool_t enable)
+{
+       if (interface == NULL)
+               return -1;
+
+       if (interface->network_path == NULL)
+               return -1;
+
+       SUPPLICANT_DBG(" ");
+       return supplicant_dbus_property_set(interface->network_path,
+                               SUPPLICANT_INTERFACE ".Network",
+                               "Enabled", DBUS_TYPE_BOOLEAN_AS_STRING,
+                               set_network_enabled, NULL, &enable);
+}
+
+dbus_bool_t g_supplicant_interface_get_ready(GSupplicantInterface *interface)
+{
+       if (interface == NULL)
+               return FALSE;
+
+       return interface->ready;
+}
+
 GSupplicantInterface *g_supplicant_network_get_interface(
                                        GSupplicantNetwork *network)
 {
@@ -828,6 +861,39 @@ dbus_bool_t g_supplicant_network_get_wps(GSupplicantNetwork *network)
        return network->wps;
 }
 
+dbus_bool_t g_supplicant_network_is_wps_active(GSupplicantNetwork *network)
+{
+       if (network == NULL)
+               return FALSE;
+
+       if (network->wps_capabilities & G_SUPPLICANT_WPS_CONFIGURED)
+               return TRUE;
+
+       return FALSE;
+}
+
+dbus_bool_t g_supplicant_network_is_wps_pbc(GSupplicantNetwork *network)
+{
+       if (network == NULL)
+               return FALSE;
+
+       if (network->wps_capabilities & G_SUPPLICANT_WPS_PBC)
+               return TRUE;
+
+       return FALSE;
+}
+
+dbus_bool_t g_supplicant_network_is_wps_advertizing(GSupplicantNetwork *network)
+{
+       if (network == NULL)
+               return FALSE;
+
+       if (network->wps_capabilities & G_SUPPLICANT_WPS_REGISTRAR)
+               return TRUE;
+
+       return FALSE;
+}
+
 static void merge_network(GSupplicantNetwork *network)
 {
        GString *str;
@@ -964,25 +1030,43 @@ static void interface_network_removed(DBusMessageIter *iter, void *user_data)
 
 static char *create_name(unsigned char *ssid, int ssid_len)
 {
-       char *name;
-       int i;
+       GString *string;
+       const gchar *remainder, *invalid;
+       int valid_bytes, remaining_bytes;
 
        if (ssid_len < 1 || ssid[0] == '\0')
-               name = NULL;
-       else
-               name = g_try_malloc0(ssid_len + 1);
-
-       if (name == NULL)
                return g_strdup("");
 
-       for (i = 0; i < ssid_len; i++) {
-               if (g_ascii_isprint(ssid[i]))
-                       name[i] = ssid[i];
-               else
-                       name[i] = ' ';
+       string = NULL;
+       remainder = (const gchar *)ssid;
+       remaining_bytes = ssid_len;
+
+       while (remaining_bytes != 0) {
+               if (g_utf8_validate(remainder, remaining_bytes,
+                                       &invalid) == TRUE) {
+                       break;
+               }
+
+               valid_bytes = invalid - remainder;
+
+               if (string == NULL)
+                       string = g_string_sized_new(remaining_bytes);
+
+               g_string_append_len(string, remainder, valid_bytes);
+
+               /* append U+FFFD REPLACEMENT CHARACTER */
+               g_string_append(string, "\357\277\275");
+
+               remaining_bytes -= valid_bytes + 1;
+               remainder = invalid + 1;
        }
 
-       return name;
+       if (string == NULL)
+               return g_strndup((const gchar *)ssid, ssid_len + 1);
+
+       g_string_append(string, remainder);
+
+       return g_string_free(string, FALSE);
 }
 
 static char *create_group(struct g_supplicant_bss *bss)
@@ -1012,7 +1096,7 @@ static char *create_group(struct g_supplicant_bss *bss)
        return g_string_free(str, FALSE);
 }
 
-static void add_bss_to_network(struct g_supplicant_bss *bss)
+static void add_or_replace_bss_to_network(struct g_supplicant_bss *bss)
 {
        GSupplicantInterface *interface = bss->interface;
        GSupplicantNetwork *network;
@@ -1048,9 +1132,12 @@ static void add_bss_to_network(struct g_supplicant_bss *bss)
        network->best_bss = bss;
 
        network->wps = FALSE;
-       if ((bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPS) != 0)
+       if ((bss->keymgmt & G_SUPPLICANT_KEYMGMT_WPS) != 0) {
                network->wps = TRUE;
 
+               network->wps_capabilities |= bss->wps_capabilities;
+       }
+
        network->bss_table = g_hash_table_new_full(g_str_hash, g_str_equal,
                                                        NULL, remove_bss);
 
@@ -1199,13 +1286,19 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data)
        const unsigned char WPS_OUI[] = { 0x00, 0x50, 0xf2, 0x04 };
        unsigned char *ie, *ie_end;
        DBusMessageIter array;
+       unsigned int value;
        int ie_len;
 
 #define WMM_WPA1_WPS_INFO 221
 #define WPS_INFO_MIN_LEN  6
 #define WPS_VERSION_TLV   0x104A
 #define WPS_STATE_TLV     0x1044
+#define WPS_METHODS_TLV   0x1012
+#define WPS_REGISTRAR_TLV 0x1041
 #define WPS_VERSION       0x10
+#define WPS_PBC           0x04
+#define WPS_PIN           0x00
+#define WPS_CONFIGURED    0x02
 
        dbus_message_iter_recurse(iter, &array);
        dbus_message_iter_get_fixed_array(&array, &ie, &ie_len);
@@ -1222,14 +1315,49 @@ static void bss_process_ies(DBusMessageIter *iter, void *user_data)
 
                SUPPLICANT_DBG("IE: match WPS_OUI");
 
-               if (get_tlv(&ie[6], ie[1],
-                               WPS_VERSION_TLV) == WPS_VERSION &&
-                       get_tlv(&ie[6], ie[1],
-                               WPS_STATE_TLV) != 0)
+               value = get_tlv(&ie[6], ie[1], WPS_STATE_TLV);
+               if (get_tlv(&ie[6], ie[1], WPS_VERSION_TLV) == WPS_VERSION &&
+                                                               value != 0) {
                        bss->keymgmt |= G_SUPPLICANT_KEYMGMT_WPS;
+
+                       if (value == WPS_CONFIGURED)
+                               bss->wps_capabilities |=
+                                       G_SUPPLICANT_WPS_CONFIGURED;
+               }
+
+               value = get_tlv(&ie[6], ie[1], WPS_METHODS_TLV);
+               if (value != 0) {
+                       if (GUINT16_FROM_BE(value) == WPS_PBC)
+                               bss->wps_capabilities |= G_SUPPLICANT_WPS_PBC;
+                       if (GUINT16_FROM_BE(value) == WPS_PIN)
+                               bss->wps_capabilities |= G_SUPPLICANT_WPS_PIN;
+               } else
+                       bss->wps_capabilities |=
+                               G_SUPPLICANT_WPS_PBC | G_SUPPLICANT_WPS_PIN;
+
+               /* If the AP sends this it means it's advertizing
+                * as a registrar and the WPS process is launched
+                * on its side */
+               if (get_tlv(&ie[6], ie[1], WPS_REGISTRAR_TLV) != 0)
+                       bss->wps_capabilities |= G_SUPPLICANT_WPS_REGISTRAR;
+
+               SUPPLICANT_DBG("WPS Methods 0x%x", bss->wps_capabilities);
        }
 }
 
+static void bss_compute_security(struct g_supplicant_bss *bss)
+{
+       if (bss->ieee8021x == TRUE)
+               bss->security = G_SUPPLICANT_SECURITY_IEEE8021X;
+       else if (bss->psk == TRUE)
+               bss->security = G_SUPPLICANT_SECURITY_PSK;
+       else if (bss->privacy == TRUE)
+               bss->security = G_SUPPLICANT_SECURITY_WEP;
+       else
+               bss->security = G_SUPPLICANT_SECURITY_NONE;
+}
+
+
 static void bss_property(const char *key, DBusMessageIter *iter,
                                                        void *user_data)
 {
@@ -1241,16 +1369,9 @@ static void bss_property(const char *key, DBusMessageIter *iter,
        SUPPLICANT_DBG("key %s", key);
 
        if (key == NULL) {
-               if (bss->ieee8021x == TRUE)
-                       bss->security = G_SUPPLICANT_SECURITY_IEEE8021X;
-               else if (bss->psk == TRUE)
-                       bss->security = G_SUPPLICANT_SECURITY_PSK;
-               else if (bss->privacy == TRUE)
-                       bss->security = G_SUPPLICANT_SECURITY_WEP;
-               else
-                       bss->security = G_SUPPLICANT_SECURITY_NONE;
+               bss_compute_security(bss);
 
-               add_bss_to_network(bss);
+               add_or_replace_bss_to_network(bss);
                return;
        }
 
@@ -2635,10 +2756,15 @@ static int parse_supplicant_error(DBusMessageIter *iter)
        int err = -ECANCELED;
        char *key;
 
+       /* If the given passphrase is malformed wpa_s returns
+        * "invalid message format" but this error should be interpreted as
+        * invalid-key.
+        */
        while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
                dbus_message_iter_get_basic(iter, &key);
-               if (strncmp(key, "psk", 4) == 0 ||
-                       strncmp(key, "wep_key", 7) == 0) {
+               if (strncmp(key, "psk", 3) == 0 ||
+                               strncmp(key, "wep_key", 7) == 0 ||
+                               strcmp(key, "invalid message format") == 0) {
                        err = -ENOKEY;
                        break;
                }
@@ -3093,6 +3219,10 @@ static void interface_add_network_params(DBusMessageIter *iter, void *user_data)
                supplicant_dbus_dict_append_basic(&dict, "frequency",
                                         DBUS_TYPE_UINT32, &ssid->freq);
 
+       if (ssid->bgscan != NULL)
+               supplicant_dbus_dict_append_basic(&dict, "bgscan",
+                                       DBUS_TYPE_STRING, &ssid->bgscan);
+
        add_network_mode(&dict, ssid);
 
        add_network_security(&dict, ssid);
@@ -3430,7 +3560,7 @@ void g_supplicant_unregister(const GSupplicantCallbacks *callbacks)
                callback_system_killed();
 
        if (interface_table != NULL) {
-               g_hash_table_foreach(interface_table,   
+               g_hash_table_foreach(interface_table,
                                        unregister_remove_interface, NULL);
                g_hash_table_destroy(interface_table);
                interface_table = NULL;