Add set of tags functions - bugfix: double free
authorOlivier Guiter <olivier.guiter@linux.intel.com>
Tue, 9 Oct 2012 12:52:25 +0000 (14:52 +0200)
committerOlivier Guiter <olivier.guiter@linux.intel.com>
Tue, 9 Oct 2012 12:52:25 +0000 (14:52 +0200)
bugfix: Fix a possible double free
tag: Add near_tag_get_blank function
tag: Dereference writing after reading new data
tag: Don't check presence while busy

include/tag.h
src/adapter.c
src/near.h
src/tag.c

index 54b9763..7a2ca6e 100644 (file)
@@ -79,6 +79,7 @@ struct near_tag;
 struct near_tag *near_tag_get_tag(uint32_t adapter_idx, uint32_t target_idx);
 void near_tag_set_ro(struct near_tag *tag, near_bool_t readonly);
 void near_tag_set_blank(struct near_tag *tag, near_bool_t blank);
+near_bool_t near_tag_get_blank(struct near_tag *tag);
 int near_tag_add_data(uint32_t adapter_idx, uint32_t target_idx,
                        uint8_t *data, size_t data_length);
 int near_tag_add_records(struct near_tag *tag, GList *records,
index e5f9e6a..ca80ed6 100644 (file)
@@ -499,6 +499,39 @@ static void tag_present_cb(uint32_t adapter_idx, uint32_t target_idx,
                                        check_presence, adapter);
 }
 
+void __near_adapter_start_check_presence(uint32_t adapter_idx,
+                                               uint32_t target_idx)
+{
+       struct near_adapter *adapter;
+
+       DBG("");
+
+       adapter = g_hash_table_lookup(adapter_hash,
+                       GINT_TO_POINTER(adapter_idx));
+       if (adapter == NULL)
+               return;
+
+       adapter->presence_timeout =
+                       g_timeout_add_seconds(CHECK_PRESENCE_PERIOD,
+                                       check_presence, adapter);
+}
+
+void __near_adapter_stop_check_presence(uint32_t adapter_idx,
+                                               uint32_t target_idx)
+{
+       struct near_adapter *adapter;
+
+       DBG("");
+
+       adapter = g_hash_table_lookup(adapter_hash,
+                       GINT_TO_POINTER(adapter_idx));
+       if (adapter == NULL)
+               return;
+
+       if (adapter->presence_timeout > 0)
+               g_source_remove(adapter->presence_timeout);
+}
+
 static const GDBusMethodTable adapter_methods[] = {
        { GDBUS_METHOD("GetProperties",
                                NULL, GDBUS_ARGS({"properties", "a{sv}"}),
index aee34be..3e0ccf6 100644 (file)
@@ -91,6 +91,8 @@ void __near_adapter_tags_changed(uint32_t adapter_idx);
 void __near_adapter_devices_changed(uint32_t adapter_idx);
 void __near_adapter_listen(struct near_device_driver *driver);
 void __near_adapter_list(DBusMessageIter *iter, void *user_data);
+void __near_adapter_start_check_presence(uint32_t adapter_idx, uint32_t target_idx);
+void __near_adapter_stop_check_presence(uint32_t adapter_idx, uint32_t target_idx);
 int __near_adapter_init(void);
 void __near_adapter_cleanup(void);
 
index b4aff76..2a46837 100644 (file)
--- a/src/tag.c
+++ b/src/tag.c
@@ -230,6 +230,18 @@ static DBusMessage *set_property(DBusConnection *conn,
 
 static void tag_read_cb(uint32_t adapter_idx, uint32_t target_idx, int status)
 {
+       struct near_tag *tag;
+
+       tag = near_tag_get_tag(adapter_idx, target_idx);
+
+       if (tag == NULL)
+               return;
+
+       dbus_message_unref(tag->write_msg);
+       tag->write_msg = NULL;
+
+       __near_adapter_start_check_presence(adapter_idx, target_idx);
+
        __near_adapter_tags_changed(adapter_idx);
 }
 
@@ -241,12 +253,14 @@ static void write_cb(uint32_t adapter_idx, uint32_t target_idx, int status)
 
        DBG("Write status %d", status);
 
-       conn = near_dbus_get_connection();
        tag = near_tag_get_tag(adapter_idx, target_idx);
-
-       if (conn == NULL || tag == NULL)
+       if (tag == NULL)
                return;
 
+       conn = near_dbus_get_connection();
+       if (conn == NULL)
+               goto out;
+
        if (status != 0) {
                reply = __near_error_failed(tag->write_msg, EINVAL);
                if (reply != NULL)
@@ -255,16 +269,26 @@ static void write_cb(uint32_t adapter_idx, uint32_t target_idx, int status)
                g_dbus_send_reply(conn, tag->write_msg, DBUS_TYPE_INVALID);
        }
 
-       dbus_message_unref(tag->write_msg);
-       tag->write_msg = NULL;
-
        near_ndef_records_free(tag->records);
        tag->n_records = 0;
        tag->records = NULL;
        g_free(tag->data);
+       tag->data = NULL;
 
-       if (status == 0)
+       if (status == 0) {
+               /*
+                * If writing succeeded,
+                * check presence will be restored after reading
+                */
                __near_tag_read(tag, tag_read_cb);
+               return;
+       }
+
+out:
+       dbus_message_unref(tag->write_msg);
+       tag->write_msg = NULL;
+
+       __near_adapter_start_check_presence(tag->adapter_idx, tag->target_idx);
 }
 
 static void format_cb(uint32_t adapter_idx, uint32_t target_idx, int status)
@@ -754,6 +778,11 @@ void near_tag_set_blank(struct near_tag *tag, near_bool_t blank)
        tag->blank = blank;
 }
 
+near_bool_t near_tag_get_blank(struct near_tag *tag)
+{
+       return tag->blank;
+}
+
 uint8_t *near_tag_get_data(struct near_tag *tag, size_t *data_length)
 {
        if (data_length == NULL)
@@ -908,6 +937,9 @@ int __near_tag_read(struct near_tag *tag, near_tag_io_cb cb)
 
        DBG("type 0x%x", tag->type);
 
+       /* Stop check presence while reading */
+       __near_adapter_stop_check_presence(tag->adapter_idx, tag->target_idx);
+
        for (list = driver_list; list; list = list->next) {
                struct near_tag_driver *driver = list->data;
 
@@ -936,21 +968,32 @@ int __near_tag_write(struct near_tag *tag,
                DBG("driver type 0x%x", driver->type);
 
                if (driver->type == tag->type) {
+                       /* Stop check presence while writing */
+                       __near_adapter_stop_check_presence(tag->adapter_idx,
+                                                               tag->target_idx);
+
                        if (tag->blank == TRUE && driver->format != NULL) {
                                DBG("Blank tag detected, formatting");
                                err = driver->format(tag->adapter_idx,
                                                tag->target_idx, format_cb);
-                               if (err < 0)
-                                       return err;
                        } else {
-                               return driver->write(tag->adapter_idx,
-                                               tag->target_idx, ndef,
-                                               cb);
+                               err = driver->write(tag->adapter_idx,
+                                                       tag->target_idx, ndef,
+                                                       cb);
                        }
+
+                       break;
                }
        }
 
-       return 0;
+       if (list == NULL)
+               err = -EOPNOTSUPP;
+
+       if (err < 0)
+               __near_adapter_start_check_presence(tag->adapter_idx,
+                                                       tag->target_idx);
+
+       return err;
 }
 
 int __near_tag_check_presence(struct near_tag *tag, near_tag_io_cb cb)