gsupplicant: Set WPA ciphers
[platform/upstream/connman.git] / gsupplicant / supplicant.c
index 6cb691e..3dc5091 100644 (file)
@@ -162,6 +162,7 @@ struct _GSupplicantInterface {
        char *driver;
        char *bridge;
        struct _GSupplicantWpsCredentials wps_cred;
+       GSupplicantWpsState wps_state;
        GHashTable *network_table;
        GHashTable *net_mapping;
        GHashTable *bss_mapping;
@@ -243,6 +244,8 @@ static const char *mode2string(GSupplicantMode mode)
                return "managed";
        case G_SUPPLICANT_MODE_IBSS:
                return "adhoc";
+       case G_SUPPLICANT_MODE_MASTER:
+               return "ap";
        }
 
        return NULL;
@@ -611,6 +614,22 @@ static void interface_capability(const char *key, DBusMessageIter *iter,
                                key, dbus_message_iter_get_arg_type(iter));
 }
 
+static void set_apscan(DBusMessageIter *iter, void *user_data)
+{
+       unsigned int ap_scan = *(unsigned int *)user_data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &ap_scan);
+}
+
+int g_supplicant_interface_set_apscan(GSupplicantInterface *interface,
+                                                       unsigned int ap_scan)
+{
+       return supplicant_dbus_property_set(interface->path,
+                       SUPPLICANT_INTERFACE ".Interface",
+                               "ApScan", DBUS_TYPE_UINT32_AS_STRING,
+                                       set_apscan, NULL, &ap_scan);
+}
+
 void g_supplicant_interface_set_data(GSupplicantInterface *interface,
                                                                void *data)
 {
@@ -676,6 +695,23 @@ const void *g_supplicant_interface_get_wps_ssid(GSupplicantInterface *interface,
        return interface->wps_cred.ssid;
 }
 
+GSupplicantWpsState g_supplicant_interface_get_wps_state(
+                                       GSupplicantInterface *interface)
+{
+       if (interface == NULL)
+               return G_SUPPLICANT_WPS_STATE_UNKNOWN;
+
+       return interface->wps_state;
+}
+
+unsigned int g_supplicant_interface_get_mode(GSupplicantInterface *interface)
+{
+       if (interface == NULL)
+               return 0;
+
+       return interface->mode_capa;
+}
+
 GSupplicantInterface *g_supplicant_network_get_interface(
                                        GSupplicantNetwork *network)
 {
@@ -1867,6 +1903,47 @@ static void signal_wps_credentials(const char *path, DBusMessageIter *iter)
        supplicant_dbus_property_foreach(iter, wps_credentials, interface);
 }
 
+static void wps_event_args(const char *key, DBusMessageIter *iter,
+                       void *user_data)
+{
+       GSupplicantInterface *interface = user_data;
+
+       if (key == NULL || interface == NULL)
+               return;
+
+       SUPPLICANT_DBG("Arg Key %s", key);
+}
+
+static void signal_wps_event(const char *path, DBusMessageIter *iter)
+{
+       GSupplicantInterface *interface;
+       const char *name = NULL;
+
+       SUPPLICANT_DBG("");
+
+       interface = g_hash_table_lookup(interface_table, path);
+       if (interface == NULL)
+               return;
+
+       dbus_message_iter_get_basic(iter, &name);
+
+       SUPPLICANT_DBG("Name: %s", name);
+
+       if (g_strcmp0(name, "success") == 0)
+               interface->wps_state = G_SUPPLICANT_WPS_STATE_SUCCESS;
+       else if (g_strcmp0(name, "failed") == 0)
+               interface->wps_state = G_SUPPLICANT_WPS_STATE_FAIL;
+       else
+               interface->wps_state = G_SUPPLICANT_WPS_STATE_UNKNOWN;
+
+       if (!dbus_message_iter_has_next(iter))
+               return;
+
+       dbus_message_iter_next(iter);
+
+       supplicant_dbus_property_foreach(iter, wps_event_args, interface);
+}
+
 static struct {
        const char *interface;
        const char *member;
@@ -1889,6 +1966,7 @@ static struct {
        { SUPPLICANT_INTERFACE ".BSS", "PropertiesChanged", signal_bss_changed   },
 
        { SUPPLICANT_INTERFACE ".Interface.WPS", "Credentials", signal_wps_credentials },
+       { SUPPLICANT_INTERFACE ".Interface.WPS", "Event",       signal_wps_event       },
 
        { }
 };
@@ -1995,6 +2073,7 @@ struct interface_data {
 struct interface_create_data {
        const char *ifname;
        const char *driver;
+       const char *bridge;
        GSupplicantInterface *interface;
        GSupplicantInterfaceCallback callback;
        void *user_data;
@@ -2087,6 +2166,10 @@ static void interface_create_params(DBusMessageIter *iter, void *user_data)
                supplicant_dbus_dict_append_basic(&dict, "Driver",
                                        DBUS_TYPE_STRING, &data->driver);
 
+       if (data->bridge != NULL)
+               supplicant_dbus_dict_append_basic(&dict, "BridgeIfname",
+                                       DBUS_TYPE_STRING, &data->bridge);
+
        supplicant_dbus_dict_close(iter, &dict);
 }
 
@@ -2158,6 +2241,7 @@ static void interface_get_params(DBusMessageIter *iter, void *user_data)
 }
 
 int g_supplicant_interface_create(const char *ifname, const char *driver,
+                                       const char *bridge,
                                        GSupplicantInterfaceCallback callback,
                                                        void *user_data)
 {
@@ -2177,6 +2261,7 @@ int g_supplicant_interface_create(const char *ifname, const char *driver,
 
        data->ifname = ifname;
        data->driver = driver;
+       data->bridge = bridge;
        data->callback = callback;
        data->user_data = user_data;
 
@@ -2329,9 +2414,17 @@ static void interface_select_network_result(const char *error,
                                DBusMessageIter *iter, void *user_data)
 {
        struct interface_connect_data *data = user_data;
+       int err;
 
        SUPPLICANT_DBG("");
 
+       err = 0;
+       if (error != NULL)
+               err = -EIO;
+
+       if (data->callback != NULL)
+               data->callback(err, data->interface, data->user_data);
+
        g_free(data->ssid);
        dbus_free(data);
 }
@@ -2574,6 +2667,65 @@ static void add_network_security_eap(DBusMessageIter *dict,
        g_free(eap_value);
 }
 
+static void add_network_security_ciphers(DBusMessageIter *dict,
+                                               GSupplicantSSID *ssid)
+{
+       unsigned int p_cipher, g_cipher, i;
+       char *pairwise, *group;
+       char *pair_ciphers[4];
+       char *group_ciphers[5];
+
+       p_cipher = ssid->pairwise_cipher;
+       g_cipher = ssid->group_cipher;
+
+       if (p_cipher == 0 && g_cipher == 0)
+               return;
+
+       i = 0;
+
+       if (p_cipher & G_SUPPLICANT_PAIRWISE_CCMP)
+               pair_ciphers[i++] = "CCMP";
+
+       if (p_cipher & G_SUPPLICANT_PAIRWISE_TKIP)
+               pair_ciphers[i++] = "TKIP";
+
+       if (p_cipher & G_SUPPLICANT_PAIRWISE_NONE)
+               pair_ciphers[i++] = "NONE";
+
+       pair_ciphers[i] = NULL;
+
+       i = 0;
+
+       if (g_cipher & G_SUPPLICANT_GROUP_CCMP)
+               group_ciphers[i++] = "CCMP";
+
+       if (g_cipher & G_SUPPLICANT_GROUP_TKIP)
+               group_ciphers[i++] = "TKIP";
+
+       if (g_cipher & G_SUPPLICANT_GROUP_WEP104)
+               group_ciphers[i++] = "WEP104";
+
+       if (g_cipher & G_SUPPLICANT_GROUP_WEP40)
+               group_ciphers[i++] = "WEP40";
+
+       group_ciphers[i] = NULL;
+
+       pairwise = g_strjoinv(" ", pair_ciphers);
+       group = g_strjoinv(" ", group_ciphers);
+
+       SUPPLICANT_DBG("cipher %s %s", pairwise, group);
+
+       supplicant_dbus_dict_append_basic(dict, "pairwise",
+                                               DBUS_TYPE_STRING,
+                                               &pairwise);
+       supplicant_dbus_dict_append_basic(dict, "group",
+                                               DBUS_TYPE_STRING,
+                                               &group);
+
+       g_free(pairwise);
+       g_free(group);
+}
+
 static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid)
 {
        char *key_mgmt;
@@ -2595,21 +2747,50 @@ static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid)
                break;
        }
 
+       add_network_security_ciphers(dict, ssid);
+
        supplicant_dbus_dict_append_basic(dict, "key_mgmt",
                                DBUS_TYPE_STRING, &key_mgmt);
 }
 
+static void add_network_mode(DBusMessageIter *dict, GSupplicantSSID *ssid)
+{
+       dbus_uint32_t mode;
+
+       switch (ssid->mode) {
+       case G_SUPPLICANT_MODE_UNKNOWN:
+       case G_SUPPLICANT_MODE_INFRA:
+               mode = 0;
+               break;
+       case G_SUPPLICANT_MODE_IBSS:
+               mode = 1;
+               break;
+       case G_SUPPLICANT_MODE_MASTER:
+               mode = 2;
+               break;
+       }
+
+       supplicant_dbus_dict_append_basic(dict, "mode",
+                               DBUS_TYPE_UINT32, &mode);
+}
+
 static void interface_add_network_params(DBusMessageIter *iter, void *user_data)
 {
        DBusMessageIter dict;
-       dbus_uint32_t scan_ssid = 1;
        struct interface_connect_data *data = user_data;
        GSupplicantSSID *ssid = data->ssid;
 
        supplicant_dbus_dict_open(iter, &dict);
 
-       supplicant_dbus_dict_append_basic(&dict, "scan_ssid",
-                                        DBUS_TYPE_UINT32, &scan_ssid);
+       if (ssid->scan_ssid)
+               supplicant_dbus_dict_append_basic(&dict, "scan_ssid",
+                                        DBUS_TYPE_UINT32, &ssid->scan_ssid);
+
+       if (ssid->freq)
+               supplicant_dbus_dict_append_basic(&dict, "frequency",
+                                        DBUS_TYPE_UINT32, &ssid->freq);
+
+       add_network_mode(&dict, ssid);
 
        add_network_security(&dict, ssid);
 
@@ -2620,6 +2801,75 @@ static void interface_add_network_params(DBusMessageIter *iter, void *user_data)
        supplicant_dbus_dict_close(iter, &dict);
 }
 
+static void interface_wps_start_result(const char *error,
+                               DBusMessageIter *iter, void *user_data)
+{
+       struct interface_connect_data *data = user_data;
+
+       SUPPLICANT_DBG("");
+       if (error != NULL)
+               SUPPLICANT_DBG("error: %s", error);
+
+       g_free(data->ssid);
+       dbus_free(data);
+}
+
+static void interface_add_wps_params(DBusMessageIter *iter, void *user_data)
+{
+       struct interface_connect_data *data = user_data;
+       GSupplicantSSID *ssid = data->ssid;
+       const char *role = "enrollee", *type;
+       DBusMessageIter dict;
+
+       SUPPLICANT_DBG("");
+
+       supplicant_dbus_dict_open(iter, &dict);
+
+       supplicant_dbus_dict_append_basic(&dict, "Role",
+                                               DBUS_TYPE_STRING, &role);
+
+       type = "pbc";
+       if (ssid->pin_wps != NULL) {
+               type = "pin";
+               supplicant_dbus_dict_append_basic(&dict, "Pin",
+                                       DBUS_TYPE_STRING, &ssid->pin_wps);
+       }
+
+       supplicant_dbus_dict_append_basic(&dict, "Type",
+                                       DBUS_TYPE_STRING, &type);
+
+       supplicant_dbus_dict_close(iter, &dict);
+}
+
+static void wps_start(const char *error, DBusMessageIter *iter, void *user_data)
+{
+       struct interface_connect_data *data = user_data;
+
+       SUPPLICANT_DBG("");
+
+       if (error != NULL) {
+               SUPPLICANT_DBG("error: %s", error);
+               g_free(data->ssid);
+               dbus_free(data);
+               return;
+       }
+
+       supplicant_dbus_method_call(data->interface->path,
+                       SUPPLICANT_INTERFACE ".Interface.WPS", "Start",
+                       interface_add_wps_params,
+                       interface_wps_start_result, data);
+}
+
+static void wps_process_credentials(DBusMessageIter *iter, void *user_data)
+{
+       dbus_bool_t credentials = TRUE;
+
+       SUPPLICANT_DBG("");
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &credentials);
+}
+
+
 int g_supplicant_interface_connect(GSupplicantInterface *interface,
                                GSupplicantSSID *ssid,
                                GSupplicantInterfaceCallback callback,
@@ -2645,10 +2895,21 @@ int g_supplicant_interface_connect(GSupplicantInterface *interface,
        data->ssid = ssid;
        data->user_data = user_data;
 
-       ret = supplicant_dbus_method_call(interface->path,
+       if (ssid->use_wps == TRUE) {
+               g_free(interface->wps_cred.key);
+               memset(&interface->wps_cred, 0,
+                               sizeof(struct _GSupplicantWpsCredentials));
+
+               ret = supplicant_dbus_property_set(interface->path,
+                       SUPPLICANT_INTERFACE ".Interface.WPS",
+                       "ProcessCredentials", DBUS_TYPE_BOOLEAN_AS_STRING,
+                       wps_process_credentials, wps_start, data);
+       } else
+               ret = supplicant_dbus_method_call(interface->path,
                        SUPPLICANT_INTERFACE ".Interface", "AddNetwork",
                        interface_add_network_params,
                        interface_add_network_result, data);
+
        if (ret < 0)
                return ret;
 
@@ -2703,6 +2964,12 @@ static void interface_disconnect_result(const char *error,
        if (error != NULL && data->callback != NULL)
                data->callback(-EIO, data->interface, data->user_data);
 
+       /* If we are disconnecting from previous WPS successful
+        * association. i.e.: it did not went through AddNetwork,
+        * and interface->network_path was never set. */
+       if (data->interface->network_path == NULL)
+               return;
+
        network_remove(data);
 }