gsupplicant network_path not freed while removing interface
[framework/connectivity/connman.git] / gsupplicant / supplicant.c
index 2670c94..cc32d56 100644 (file)
@@ -138,6 +138,7 @@ static GHashTable *bss_mapping;
 
 struct _GSupplicantInterface {
        char *path;
+       char *network_path;
        unsigned int keymgmt_capa;
        unsigned int authalg_capa;
        unsigned int proto_capa;
@@ -405,6 +406,7 @@ static void remove_interface(gpointer data)
        callback_interface_removed(interface);
 
        g_free(interface->path);
+       g_free(interface->network_path);
        g_free(interface->ifname);
        g_free(interface->driver);
        g_free(interface->bridge);
@@ -823,7 +825,7 @@ static void interface_network_added(DBusMessageIter *iter, void *user_data)
        }
 
        supplicant_dbus_property_get_all(path,
-                               SUPPLICANT_INTERFACE ".Interface.Network",
+                               SUPPLICANT_INTERFACE ".Network",
                                                network_property, network);
 }
 
@@ -1176,7 +1178,7 @@ static void interface_bss_added(DBusMessageIter *iter, void *user_data)
        }
 
        supplicant_dbus_property_get_all(path,
-                                       SUPPLICANT_INTERFACE ".Interface.BSS",
+                                       SUPPLICANT_INTERFACE ".BSS",
                                                        bss_property, bss);
 }
 
@@ -1300,6 +1302,45 @@ static void interface_property(const char *key, DBusMessageIter *iter,
                                key, dbus_message_iter_get_arg_type(iter));
 }
 
+static void scan_network_update(DBusMessageIter *iter, void *user_data)
+{
+       GSupplicantInterface *interface = user_data;
+       GSupplicantNetwork *network;
+       char *path;
+
+       if (iter == NULL)
+               return;
+
+       dbus_message_iter_get_basic(iter, &path);
+
+       if (path == NULL)
+               return;
+
+       if (g_strcmp0(path, "/") == 0)
+               return;
+
+       /* Update the network details based on scan BSS data */
+       network = g_hash_table_lookup(interface->bss_mapping, path);
+       if (network != NULL)
+               callback_network_added(network);
+}
+
+static void scan_bss_data(const char *key, DBusMessageIter *iter,
+                               void *user_data)
+{
+       GSupplicantInterface *interface = user_data;
+
+       if (iter)
+               supplicant_dbus_array_foreach(iter, scan_network_update,
+                                               interface);
+
+       if (interface->scan_callback != NULL)
+               interface->scan_callback(0, interface, interface->scan_data);
+
+       interface->scan_callback = NULL;
+       interface->scan_data = NULL;
+}
+
 static GSupplicantInterface *interface_alloc(const char *path)
 {
        GSupplicantInterface *interface;
@@ -1415,6 +1456,11 @@ static void service_property(const char *key, DBusMessageIter *iter,
        } else if (g_strcmp0(key, "EapMethods") == 0) {
                supplicant_dbus_array_foreach(iter, eap_method, NULL);
                debug_strvalmap("EAP method", eap_method_map, eap_methods);
+       } else if (g_strcmp0(key, "Country") == 0) {
+               const char *country = NULL;
+
+               dbus_message_iter_get_basic(iter, &country);
+               SUPPLICANT_DBG("Country %s", country);
        } else
                SUPPLICANT_DBG("key %s type %c",
                                key, dbus_message_iter_get_arg_type(iter));
@@ -1511,18 +1557,23 @@ static void signal_scan_done(const char *path, DBusMessageIter *iter)
 
        dbus_message_iter_get_basic(iter, &success);
 
-       if (interface->scan_callback != NULL) {
-               int result = 0;
+       /*
+        * If scan is unsuccessful return -EIO else get the scanned BSSs
+        * and update the network details accordingly
+        */
+       if (success == FALSE) {
+               if (interface->scan_callback != NULL)
+                       interface->scan_callback(-EIO, interface,
+                                               interface->scan_data);
 
-               if (success == FALSE)
-                       result = -EIO;
+               interface->scan_callback = NULL;
+               interface->scan_data = NULL;
 
-               interface->scan_callback(result, interface,
-                                               interface->scan_data);
+               return;
        }
 
-       interface->scan_callback = NULL;
-       interface->scan_data = NULL;
+       supplicant_dbus_property_get(path, SUPPLICANT_INTERFACE ".Interface",
+                                       "BSSs", scan_bss_data, interface);
 }
 
 static void signal_bss_added(const char *path, DBusMessageIter *iter)
@@ -1619,7 +1670,7 @@ static struct {
        { SUPPLICANT_INTERFACE ".Interface", "NetworkAdded",      signal_network_added     },
        { SUPPLICANT_INTERFACE ".Interface", "NetworkRemoved",    signal_network_removed   },
 
-       { SUPPLICANT_INTERFACE ".Interface.BSS", "PropertiesChanged", signal_bss_changed   },
+       { SUPPLICANT_INTERFACE ".BSS", "PropertiesChanged", signal_bss_changed   },
 
        { }
 };
@@ -1654,6 +1705,69 @@ static DBusHandlerResult g_supplicant_filter(DBusConnection *conn,
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
 
+struct supplicant_regdom {
+       GSupplicantCountryCallback callback;
+       const void *user_data;
+};
+
+static void country_result(const char *error,
+                               DBusMessageIter *iter, void *user_data)
+{
+       struct supplicant_regdom *regdom = user_data;
+       char *alpha2;
+
+       SUPPLICANT_DBG("Country setting result");
+
+       if (user_data == NULL)
+               return;
+
+       if (error == NULL) {
+               alpha2 = (char *)regdom->user_data;
+       } else {
+               SUPPLICANT_DBG("Country setting failure %s", error);
+               alpha2 = NULL;
+       }
+
+       if (regdom->callback)
+               regdom->callback(alpha2);
+
+       g_free(regdom);
+}
+
+static void country_params(DBusMessageIter *iter, void *user_data)
+{
+       struct supplicant_regdom *regdom = user_data;
+       const char *country;
+
+       country = regdom->user_data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &country);
+}
+
+int g_supplicant_set_country(const char *alpha2,
+                               GSupplicantCountryCallback callback,
+                                       const void *user_data)
+{
+       struct supplicant_regdom *regdom;
+
+       SUPPLICANT_DBG("Country setting %s", alpha2);
+
+       if (system_available == FALSE)
+               return -EFAULT;
+
+       regdom = dbus_malloc0(sizeof(*regdom));
+       if (regdom == NULL)
+               return -ENOMEM;
+
+       regdom->callback = callback;
+       regdom->user_data = user_data;
+
+       return supplicant_dbus_property_set(SUPPLICANT_PATH, SUPPLICANT_INTERFACE,
+                                       "Country", DBUS_TYPE_STRING_AS_STRING,
+                                       country_params, country_result,
+                                               regdom);
+}
+
 struct interface_data {
        GSupplicantInterface *interface;
        GSupplicantInterfaceCallback callback;
@@ -1769,7 +1883,7 @@ static void interface_get_result(const char *error,
        SUPPLICANT_DBG("");
 
        if (error != NULL) {
-               g_warning("error %s", error);
+               SUPPLICANT_DBG("Interface not created yet");
                err = -EIO;
                goto create;
        }
@@ -1962,6 +2076,21 @@ int g_supplicant_interface_scan(GSupplicantInterface *interface,
        if (interface->scanning == TRUE)
                return -EALREADY;
 
+       switch (interface->state) {
+       case G_SUPPLICANT_STATE_AUTHENTICATING:
+       case G_SUPPLICANT_STATE_ASSOCIATING:
+       case G_SUPPLICANT_STATE_ASSOCIATED:
+       case G_SUPPLICANT_STATE_4WAY_HANDSHAKE:
+       case G_SUPPLICANT_STATE_GROUP_HANDSHAKE:
+               return -EBUSY;
+       case G_SUPPLICANT_STATE_UNKNOWN:
+       case G_SUPPLICANT_STATE_DISCONNECTED:
+       case G_SUPPLICANT_STATE_INACTIVE:
+       case G_SUPPLICANT_STATE_SCANNING:
+       case G_SUPPLICANT_STATE_COMPLETED:
+               break;
+       }
+
        data = dbus_malloc0(sizeof(*data));
        if (data == NULL)
                return -ENOMEM;
@@ -1978,39 +2107,53 @@ int g_supplicant_interface_scan(GSupplicantInterface *interface,
 static void interface_select_network_result(const char *error,
                                DBusMessageIter *iter, void *user_data)
 {
+       struct interface_connect_data *data = user_data;
+
        SUPPLICANT_DBG("");
+
+       dbus_free(data);
 }
 
 static void interface_select_network_params(DBusMessageIter *iter,
                                                        void *user_data)
 {
-       char *path = user_data;
+       struct interface_connect_data *data = user_data;
+       GSupplicantInterface *interface = data->interface;
 
-       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
+                                       &interface->network_path);
 }
 
 static void interface_add_network_result(const char *error,
                                DBusMessageIter *iter, void *user_data)
 {
        struct interface_connect_data *data = user_data;
-       char *path = NULL;
+       GSupplicantInterface *interface = data->interface;
+       const char *path;
 
        if (error != NULL)
-               goto done;
+               goto error;
 
        dbus_message_iter_get_basic(iter, &path);
        if (path == NULL)
-               goto done;
+               goto error;
 
        SUPPLICANT_DBG("PATH: %s", path);
 
+       g_free(interface->network_path);
+       interface->network_path = g_strdup(path);
+
        supplicant_dbus_method_call(data->interface->path,
                        SUPPLICANT_INTERFACE ".Interface", "SelectNetwork",
                        interface_select_network_params,
-                       interface_select_network_result, path);
+                       interface_select_network_result, data);
 
-done:
-       dbus_free(data);
+       return;
+
+error:
+       g_free(interface->network_path);
+       interface->network_path = NULL;
+       g_free(data);
 }
 
 static void add_network_security_wep(DBusMessageIter *dict,
@@ -2179,6 +2322,8 @@ static void add_network_security_peap(DBusMessageIter *dict,
 static void add_network_security_eap(DBusMessageIter *dict,
                                        GSupplicantSSID *ssid)
 {
+       char *eap_value;
+
        if (ssid->eap == NULL || ssid->identity == NULL)
                return;
 
@@ -2190,12 +2335,16 @@ static void add_network_security_eap(DBusMessageIter *dict,
        } else
                return;
 
+       eap_value = g_ascii_strup(ssid->eap, -1);
+
        supplicant_dbus_dict_append_basic(dict, "eap",
                                                DBUS_TYPE_STRING,
-                                               &ssid->eap);
+                                               &eap_value);
        supplicant_dbus_dict_append_basic(dict, "identity",
                                                DBUS_TYPE_STRING,
                                                &ssid->identity);
+
+       g_free(eap_value);
 }
 
 static void add_network_security(DBusMessageIter *dict, GSupplicantSSID *ssid)
@@ -2279,7 +2428,7 @@ int g_supplicant_interface_connect(GSupplicantInterface *interface,
        return -EINPROGRESS;
 }
 
-static void interface_disconnect_result(const char *error,
+static void network_remove_result(const char *error,
                                DBusMessageIter *iter, void *user_data)
 {
        struct interface_data *data = user_data;
@@ -2296,6 +2445,40 @@ static void interface_disconnect_result(const char *error,
        dbus_free(data);
 }
 
+static void network_remove_params(DBusMessageIter *iter, void *user_data)
+{
+       struct interface_data *data = user_data;
+       const char *path = data->interface->network_path;
+
+       SUPPLICANT_DBG("path %s", path);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+}
+
+static int network_remove(struct interface_data *data)
+{
+       GSupplicantInterface *interface = data->interface;
+
+       SUPPLICANT_DBG("");
+
+       return supplicant_dbus_method_call(interface->path,
+                       SUPPLICANT_INTERFACE ".Interface", "RemoveNetwork",
+                       network_remove_params, network_remove_result, data);
+}
+
+static void interface_disconnect_result(const char *error,
+                               DBusMessageIter *iter, void *user_data)
+{
+       struct interface_data *data = user_data;
+
+       SUPPLICANT_DBG("");
+
+       if (error != NULL && data->callback != NULL)
+               data->callback(-EIO, data->interface, data->user_data);
+
+       network_remove(data);
+}
+
 int g_supplicant_interface_disconnect(GSupplicantInterface *interface,
                                        GSupplicantInterfaceCallback callback,
                                                        void *user_data)
@@ -2337,11 +2520,26 @@ static const char *g_supplicant_rule2 = "type=signal,"
 static const char *g_supplicant_rule3 = "type=signal,"
                        "interface=" SUPPLICANT_INTERFACE ".Interface.WPS";
 static const char *g_supplicant_rule4 = "type=signal,"
-                       "interface=" SUPPLICANT_INTERFACE ".Interface.BSS";
+                       "interface=" SUPPLICANT_INTERFACE ".BSS";
 static const char *g_supplicant_rule5 = "type=signal,"
-                       "interface=" SUPPLICANT_INTERFACE ".Interface.Network";
-static const char *g_supplicant_rule6 = "type=signal,"
-                       "interface=" SUPPLICANT_INTERFACE ".Interface.Blob";
+                       "interface=" SUPPLICANT_INTERFACE ".Network";
+
+static void invoke_introspect_method(void)
+{
+       DBusMessage *message;
+
+       message = dbus_message_new_method_call(SUPPLICANT_SERVICE,
+                                       SUPPLICANT_PATH,
+                                       DBUS_INTERFACE_INTROSPECTABLE,
+                                       "Introspect");
+
+       if (message == NULL)
+               return;
+
+       dbus_message_set_no_reply(message, TRUE);
+       dbus_connection_send(connection, message, NULL);
+       dbus_message_unref(message);
+}
 
 int g_supplicant_register(const GSupplicantCallbacks *callbacks)
 {
@@ -2373,7 +2571,6 @@ int g_supplicant_register(const GSupplicantCallbacks *callbacks)
        dbus_bus_add_match(connection, g_supplicant_rule3, NULL);
        dbus_bus_add_match(connection, g_supplicant_rule4, NULL);
        dbus_bus_add_match(connection, g_supplicant_rule5, NULL);
-       dbus_bus_add_match(connection, g_supplicant_rule6, NULL);
        dbus_connection_flush(connection);
 
        if (dbus_bus_name_has_owner(connection,
@@ -2382,7 +2579,8 @@ int g_supplicant_register(const GSupplicantCallbacks *callbacks)
                supplicant_dbus_property_get_all(SUPPLICANT_PATH,
                                                SUPPLICANT_INTERFACE,
                                                service_property, NULL);
-       }
+       } else
+               invoke_introspect_method();
 
        return 0;
 }
@@ -2414,7 +2612,6 @@ void g_supplicant_unregister(const GSupplicantCallbacks *callbacks)
        SUPPLICANT_DBG("");
 
        if (connection != NULL) {
-               dbus_bus_remove_match(connection, g_supplicant_rule6, NULL);
                dbus_bus_remove_match(connection, g_supplicant_rule5, NULL);
                dbus_bus_remove_match(connection, g_supplicant_rule4, NULL);
                dbus_bus_remove_match(connection, g_supplicant_rule3, NULL);