Fix incorrect handling in multi-interface environment
[platform/upstream/connman.git] / src / device.c
index 2029871..5350282 100755 (executable)
@@ -38,6 +38,10 @@ static GSList *device_list = NULL;
 static gchar **device_filter = NULL;
 static gchar **nodevice_filter = NULL;
 
+#if defined TIZEN_EXT
+static DBusConnection *connection;
+#endif
+
 enum connman_pending_type {
        PENDING_NONE    = 0,
        PENDING_ENABLE  = 1,
@@ -72,11 +76,35 @@ struct connman_device {
        time_t last_user_selection_time;
        char *last_user_selection_ident;
        char *last_connected_ident;
+       GList *pending_reply_list; /* List of DBusMessage* for async reply to multiple
+                                   * device power dbus calls, which are made before
+                                   * connman_device_set_powered().
+                                   */
+       int max_scan_ssids;
+       bool is_5_0_ghz_supported;
+       unsigned int mac_policy;
+       unsigned int preassoc_mac_policy;
+       unsigned int random_mac_lifetime;
 #endif
 };
 
+#if defined TIZEN_EXT
+static void __clear_pending_trigger(gpointer data, gpointer user_data)
+{
+       DBusMessage *msg = (DBusMessage *)data;
+       dbus_message_unref(msg);
+}
+#endif
+
 static void clear_pending_trigger(struct connman_device *device)
 {
+#if defined TIZEN_EXT
+       if (device->pending_reply_list) {
+               g_list_foreach(device->pending_reply_list, __clear_pending_trigger, NULL);
+               g_list_free(device->pending_reply_list);
+               device->pending_reply_list = NULL;
+       }
+#endif
        if (device->pending_timeout > 0) {
                g_source_remove(device->pending_timeout);
                device->pending_timeout = 0;
@@ -184,12 +212,36 @@ static bool device_has_service_type(struct connman_device *device,
        return service_type == device_service_type;
 }
 
+#if defined TIZEN_EXT
+static void __device_pending_reset(gpointer data, gpointer user_data)
+{
+       DBusMessage *msg = (DBusMessage *)data;
+       DBusMessage *reply;
+
+       reply = __connman_error_failed(msg, ETIMEDOUT);
+       if (reply)
+               g_dbus_send_message(connection, reply);
+
+       dbus_message_unref(msg);
+}
+#endif
+
 static gboolean device_pending_reset(gpointer user_data)
 {
        struct connman_device *device = user_data;
 
        DBG("device %p", device);
 
+#if defined TIZEN_EXT
+       DBusMessage *reply;
+
+       /* Power request timed out, send ETIMEDOUT. */
+       if (device->pending_reply_list) {
+               g_list_foreach(device->pending_reply_list, __device_pending_reset, NULL);
+               g_list_free(device->pending_reply_list);
+               device->pending_reply_list = NULL;
+       }
+#endif
        /* Power request timedout, reset power pending state. */
        device->pending_timeout = 0;
        device->powered_pending = PENDING_NONE;
@@ -237,15 +289,22 @@ int __connman_device_enable(struct connman_device *device)
        if (err == -EALREADY) {
                /* If device is already powered, but connman is not updated */
                connman_device_set_powered(device, true);
+#ifdef TIZEN_EXT
+               if (device->type == CONNMAN_DEVICE_TYPE_WIFI) {
+                       device->driver->set_mac_policy(device, device->mac_policy);
+                       device->driver->set_preassoc_mac_policy(device, device->preassoc_mac_policy);
+                       device->driver->set_random_mac_lifetime(device, device->random_mac_lifetime);
+               }
+#endif /* TIZEN_EXT */
                goto done;
        }
        /*
         * if err == -EINPROGRESS, then the DBus call to the respective daemon
-        * was successful. We set a 4 sec timeout so if the daemon never
+        * was successful. We set a 10 sec timeout so if the daemon never
         * returns a reply, we would reset the pending request.
         */
        if (err == -EINPROGRESS)
-               device->pending_timeout = g_timeout_add_seconds(4,
+               device->pending_timeout = g_timeout_add_seconds(10,
                                        device_pending_reset, device);
 done:
        return err;
@@ -436,6 +495,57 @@ static void device_destruct(struct connman_device *device)
        g_free(device);
 }
 
+#if defined TIZEN_EXT
+static void device_send_changed(const char *ifname, enum connman_service_type type,
+                                                               const char *key, bool state)
+{
+       DBusMessage *signal;
+       DBusMessageIter iter, dict;
+       dbus_bool_t value = state;
+       const char *tech_path = connman_techonology_get_path(type);
+
+       if (!tech_path || !ifname)
+               return;
+
+       DBG("%s %s %s", ifname, key, state ? "TRUE" : "FALSE");
+
+       signal = dbus_message_new_signal(tech_path,
+                       CONNMAN_TECHNOLOGY_INTERFACE, "DeviceChanged");
+       if (!signal)
+               return;
+
+       dbus_message_iter_init_append(signal, &iter);
+
+       connman_dbus_dict_open(&iter, &dict);
+       connman_dbus_dict_append_basic(&dict, "Ifname",
+                                       DBUS_TYPE_STRING,
+                                       &ifname);
+       connman_dbus_dict_append_basic(&dict, key,
+                                       DBUS_TYPE_BOOLEAN,
+                                       &value);
+       connman_dbus_dict_close(&iter, &dict);
+
+       dbus_connection_send(connection, signal, NULL);
+       dbus_message_unref(signal);
+}
+
+static void __device_send_reply(gpointer data, gpointer user_data)
+{
+       DBusMessage *msg = (DBusMessage *)data;
+       g_dbus_send_reply(connection, msg, DBUS_TYPE_INVALID);
+       dbus_message_unref(msg);
+}
+
+static void device_send_reply(struct connman_device *device)
+{
+       if (device->pending_reply_list) {
+               g_list_foreach(device->pending_reply_list, __device_send_reply, NULL);
+               g_list_free(device->pending_reply_list);
+               device->pending_reply_list = NULL;
+       }
+}
+#endif
+
 /**
  * connman_device_create:
  * @node: device node name (for example an address)
@@ -583,6 +693,11 @@ void connman_device_set_interface(struct connman_device *device,
 void connman_device_set_ident(struct connman_device *device,
                                                        const char *ident)
 {
+#ifdef TIZEN_EXT
+       if (device->ident && device->powered)
+               return;
+       else
+#endif
        g_free(device->ident);
        device->ident = g_strdup(ident);
 }
@@ -611,6 +726,10 @@ int connman_device_set_powered(struct connman_device *device,
        if (device->powered == powered)
                return -EALREADY;
 
+#if defined TIZEN_EXT
+       device_send_reply(device);
+#endif
+
        clear_pending_trigger(device);
 
        device->powered_pending = PENDING_NONE;
@@ -619,6 +738,10 @@ int connman_device_set_powered(struct connman_device *device,
 
        type = __connman_device_get_service_type(device);
 
+#if defined TIZEN_EXT
+       device_send_changed(device->interface, type, "Powered", powered);
+#endif
+
        if (!device->powered) {
                __connman_technology_disabled(type);
                return 0;
@@ -1016,6 +1139,11 @@ int connman_device_set_string(struct connman_device *device,
        DBG("device %p key %s value %s", device, key, value);
 
        if (g_str_equal(key, "Address")) {
+#ifdef TIZEN_EXT
+               if (device->address && device->powered)
+                       return 0;
+               else
+#endif
                g_free(device->address);
                device->address = g_strdup(value);
        } else if (g_str_equal(key, "Name")) {
@@ -1044,6 +1172,9 @@ int connman_device_set_string(struct connman_device *device,
 const char *connman_device_get_string(struct connman_device *device,
                                                        const char *key)
 {
+#if defined TIZEN_EXT
+       if (!simplified_log)
+#endif
        DBG("device %p key %s", device, key);
 
        if (g_str_equal(key, "Address"))
@@ -1071,7 +1202,9 @@ int connman_device_add_network(struct connman_device *device,
                                        struct connman_network *network)
 {
        const char *identifier = connman_network_get_identifier(network);
-
+#if defined TIZEN_EXT
+       if (!simplified_log)
+#endif
        DBG("device %p network %p", device, network);
 
        if (!identifier)
@@ -1097,11 +1230,62 @@ int connman_device_add_network(struct connman_device *device,
 struct connman_network *connman_device_get_network(struct connman_device *device,
                                                        const char *identifier)
 {
+#if defined TIZEN_EXT
+       if (!simplified_log)
+#endif
        DBG("device %p identifier %s", device, identifier);
 
        return g_hash_table_lookup(device->networks, identifier);
 }
 
+#if defined TIZEN_EXT
+struct connman_network *connman_device_get_default_network(
+                                                       struct connman_device *device)
+{
+       return device->network;
+}
+
+void connman_device_set_pending_reply(struct connman_device *device,
+                                                       DBusMessage *msg)
+{
+       device->pending_reply_list = g_list_prepend(device->pending_reply_list, dbus_message_ref(msg));
+}
+
+void connman_device_send_connected_signal(struct connman_device *device,
+                                                       bool connected)
+{
+       enum connman_service_type type;
+
+       if (!device)
+               return;
+
+       type = __connman_device_get_service_type(device);
+       device_send_changed(device->interface, type, "Connected", connected);
+}
+
+void connman_device_set_max_scan_ssids(struct connman_device *device,
+                                                       int max_scan_ssids)
+{
+       device->max_scan_ssids = max_scan_ssids;
+}
+
+int connman_device_get_max_scan_ssids(struct connman_device *device)
+{
+       return device->max_scan_ssids;
+}
+
+void connman_device_set_wifi_5ghz_supported(struct connman_device *device,
+                                                       bool is_5_0_ghz_supported)
+{
+       device->is_5_0_ghz_supported = is_5_0_ghz_supported;
+}
+
+bool connman_device_get_wifi_5ghz_supported(struct connman_device *device)
+{
+       return device->is_5_0_ghz_supported;
+}
+#endif
+
 /**
  * connman_device_remove_network:
  * @device: device structure
@@ -1314,7 +1498,7 @@ static int device_specific_scan(enum connman_service_type type,
 }
 
 int __connman_device_request_specific_scan(enum connman_service_type type,
-                               int scan_type, GSList *specific_scan_list)
+                               const char *ifname, int scan_type, GSList *specific_scan_list)
 {
        bool success = false;
        int last_err = -ENOSYS;
@@ -1352,6 +1536,9 @@ int __connman_device_request_specific_scan(enum connman_service_type type,
                                continue;
                }
 
+               if (ifname && g_strcmp0(device->interface, ifname) != 0)
+                       continue;
+
                err = device_specific_scan(type, device, scan_type, specific_scan_list);
                if (err == 0 || err == -EINPROGRESS) {
                        success = true;
@@ -1367,6 +1554,58 @@ int __connman_device_request_specific_scan(enum connman_service_type type,
        return last_err;
 }
 
+int connman_device_request_device_scan(enum connman_service_type type,
+                               const char * ifname, bool force_full_scan)
+{
+       bool success = false;
+       int last_err = -ENOSYS;
+       GSList *list;
+       int err;
+
+       switch (type) {
+       case CONNMAN_SERVICE_TYPE_UNKNOWN:
+       case CONNMAN_SERVICE_TYPE_SYSTEM:
+       case CONNMAN_SERVICE_TYPE_ETHERNET:
+       case CONNMAN_SERVICE_TYPE_BLUETOOTH:
+       case CONNMAN_SERVICE_TYPE_CELLULAR:
+       case CONNMAN_SERVICE_TYPE_GPS:
+       case CONNMAN_SERVICE_TYPE_VPN:
+       case CONNMAN_SERVICE_TYPE_GADGET:
+               return -EOPNOTSUPP;
+       case CONNMAN_SERVICE_TYPE_WIFI:
+       case CONNMAN_SERVICE_TYPE_P2P:
+#if defined TIZEN_EXT_WIFI_MESH
+       case CONNMAN_SERVICE_TYPE_MESH:
+#endif
+               break;
+       }
+
+       for (list = device_list; list; list = list->next) {
+               struct connman_device *device = list->data;
+
+               if (!device_has_service_type(device, type))
+                       continue;
+
+               if (g_strcmp0(device->interface, ifname) != 0)
+                       continue;
+
+               err = device_scan(type, device, force_full_scan);
+
+               if (err == 0 || err == -EINPROGRESS) {
+                       success = true;
+               } else {
+                       last_err = err;
+                       DBG("device %p err %d", device, err);
+               }
+               break;
+       }
+
+       if (success)
+               return 0;
+
+       return last_err;
+}
+
 #if defined TIZEN_EXT_WIFI_MESH
 static int device_abort_scan(enum connman_service_type type,
                                struct connman_device *device)
@@ -1567,6 +1806,87 @@ void __connman_device_stop_scan(enum connman_service_type type)
 }
 
 #if defined TIZEN_EXT
+#define WIFI_MAC "/opt/etc/.mac.info"
+#define MAC_ADDR_LEN 18
+
+char *_get_wifi_addr(void)
+{
+       FILE *fp = NULL;
+       char* rv = 0;
+       char wifi_mac[MAC_ADDR_LEN + 1];
+       char *str;
+
+       fp = fopen(WIFI_MAC, "r");
+       if (!fp){
+               connman_error("[%s] not present", WIFI_MAC);
+               return NULL;
+       }
+
+       rv = fgets(wifi_mac, MAC_ADDR_LEN, fp);
+       if (!rv) {
+               connman_error("Failed to get wifi mac address");
+               fclose(fp);
+               return NULL;
+       }
+
+       str = g_try_malloc0(MAC_ADDR_LEN);
+       if (!str) {
+               connman_error("memory allocation failed");
+               fclose(fp);
+               return NULL;
+       }
+
+       snprintf(str, MAC_ADDR_LEN, "%c%c:%c%c:%c%c:%c%c:%c%c:%c%c",
+                       g_ascii_tolower(wifi_mac[0]), g_ascii_tolower(wifi_mac[1]),
+                       g_ascii_tolower(wifi_mac[3]), g_ascii_tolower(wifi_mac[4]),
+                       g_ascii_tolower(wifi_mac[6]), g_ascii_tolower(wifi_mac[7]),
+                       g_ascii_tolower(wifi_mac[9]), g_ascii_tolower(wifi_mac[10]),
+                       g_ascii_tolower(wifi_mac[12]), g_ascii_tolower(wifi_mac[13]),
+                       g_ascii_tolower(wifi_mac[15]), g_ascii_tolower(wifi_mac[16]));
+       fclose(fp);
+       return str;
+}
+
+char *_get_wifi_ident(void)
+{
+       FILE *fp = NULL;
+       char* rv = 0;
+       char wifi_mac[MAC_ADDR_LEN + 1];
+       char *str;
+
+       fp = fopen(WIFI_MAC, "r");
+       if (!fp){
+               connman_error("[%s] not present", WIFI_MAC);
+               return NULL;
+       }
+
+       rv = fgets(wifi_mac, MAC_ADDR_LEN, fp);
+       if (!rv) {
+               connman_error("Failed to get wifi mac address");
+               fclose(fp);
+               return NULL;
+       }
+
+       str = g_try_malloc0(MAC_ADDR_LEN);
+       if (!str) {
+               connman_error("memory allocation failed");
+               fclose(fp);
+               return NULL;
+       }
+
+       snprintf(str, MAC_ADDR_LEN, "%c%c%c%c%c%c%c%c%c%c%c%c",
+                       g_ascii_tolower(wifi_mac[0]), g_ascii_tolower(wifi_mac[1]),
+                       g_ascii_tolower(wifi_mac[3]), g_ascii_tolower(wifi_mac[4]),
+                       g_ascii_tolower(wifi_mac[6]), g_ascii_tolower(wifi_mac[7]),
+                       g_ascii_tolower(wifi_mac[9]), g_ascii_tolower(wifi_mac[10]),
+                       g_ascii_tolower(wifi_mac[12]), g_ascii_tolower(wifi_mac[13]),
+                       g_ascii_tolower(wifi_mac[15]), g_ascii_tolower(wifi_mac[16]));
+       fclose(fp);
+       return str;
+}
+#endif
+
+#if defined TIZEN_EXT
 char *index2ident(int index, const char *prefix)
 #else
 static char *index2ident(int index, const char *prefix)
@@ -1882,6 +2202,10 @@ int __connman_device_init(const char *device, const char *nodevice)
 {
        DBG("");
 
+#if defined TIZEN_EXT
+       connection = connman_dbus_get_connection();
+#endif
+
        if (device)
                device_filter = g_strsplit(device, ",", -1);
 
@@ -1899,4 +2223,86 @@ void __connman_device_cleanup(void)
 
        g_strfreev(nodevice_filter);
        g_strfreev(device_filter);
+
+#if defined TIZEN_EXT
+       dbus_connection_unref(connection);
+#endif
 }
+
+#ifdef TIZEN_EXT
+void connman_device_mac_policy_notify(struct connman_device *device,
+                                       int result, unsigned int policy)
+{
+       device->mac_policy = policy;
+       __connman_technology_notify_mac_policy_by_device(device, result, policy);
+}
+
+int connman_device_set_mac_policy(struct connman_device *device,
+                                       unsigned int policy)
+{
+       int err = 0;
+
+       if (!device || !device->driver || !device->driver->set_mac_policy)
+               return -EOPNOTSUPP;
+
+       device->mac_policy = policy;
+       err = device->driver->set_mac_policy(device, policy);
+       return err;
+}
+
+unsigned int connman_device_get_mac_policy(struct connman_device *device)
+{
+       return device->mac_policy;
+}
+
+void connman_device_preassoc_mac_policy_notify(struct connman_device *device,
+                                       int result, unsigned int policy)
+{
+       device->preassoc_mac_policy = policy;
+       __connman_technology_notify_preassoc_mac_policy_by_device(device, result, policy);
+}
+
+int connman_device_set_preassoc_mac_policy(struct connman_device *device,
+                                       unsigned int policy)
+{
+       int err = 0;
+
+       if (!device || !device->driver || !device->driver->set_preassoc_mac_policy)
+               return -EOPNOTSUPP;
+
+       device->preassoc_mac_policy = policy;
+       err = device->driver->set_preassoc_mac_policy(device, policy);
+       return err;
+}
+
+unsigned int connman_device_get_preassoc_mac_policy(struct connman_device *device)
+{
+       return device->preassoc_mac_policy;
+}
+
+void connman_device_random_mac_lifetime_notify(struct connman_device *device,
+                                       int result, unsigned int lifetime)
+{
+       device->random_mac_lifetime = lifetime;
+       __connman_technology_notify_random_mac_lifetime_by_device(device, result, lifetime);
+}
+
+int connman_device_set_random_mac_lifetime(struct connman_device *device,
+                                       unsigned int lifetime)
+{
+       int err = 0;
+
+       if (!device || !device->driver || !device->driver->set_random_mac_lifetime)
+               return -EOPNOTSUPP;
+
+       device->random_mac_lifetime = lifetime;
+       err = device->driver->set_random_mac_lifetime(device, lifetime);
+       return err;
+}
+
+unsigned int connman_device_get_random_mac_lifetime(struct connman_device *device)
+{
+       return device->random_mac_lifetime;
+}
+
+#endif