Diff between da92020b1f19fdc5d6c63b27241546f6ae32afbb and 4e5989f121f156afa6c2d2bf0009af9153097f58

Changed Files

File Additions Deletions Status
src/gatt-client.c +85 -12 modified

Full Patch

diff --git a/src/gatt-client.c b/src/gatt-client.c
index 9e4a8ef..02ef57e 100644
--- a/src/gatt-client.c
+++ b/src/gatt-client.c
@@ -89,6 +89,7 @@ struct descriptor {
 	char *path;
 
 	bool in_read;
+	bool in_write;
 };
 
 static gboolean descriptor_get_uuid(const GDBusPropertyTable *property,
@@ -198,9 +199,12 @@ static bool parse_value_arg(DBusMessage *msg, uint8_t **value,
 	return true;
 }
 
+typedef bool (*async_dbus_op_complete_t)(void *data);
+
 struct async_dbus_op {
 	DBusMessage *msg;
 	void *data;
+	async_dbus_op_complete_t complete;
 };
 
 static void async_dbus_op_free(void *data)
@@ -330,11 +334,9 @@ static void write_result_cb(bool success, bool reliable_error,
 	struct async_dbus_op *op = user_data;
 	DBusMessage *reply;
 
-	if (op->data) {
-		struct characteristic *chrc;
-
-		chrc = op->data;
-		chrc->in_write = false;
+	if (op->complete && !op->complete(op->data)) {
+		reply = btd_error_failed(op->msg, "Operation failed");
+		goto done;
 	}
 
 	if (!success) {
@@ -363,11 +365,11 @@ static void write_cb(bool success, uint8_t att_ecode, void *user_data)
 	write_result_cb(success, false, att_ecode, user_data);
 }
 
-
 static bool start_long_write(DBusMessage *msg, uint16_t handle,
 					struct bt_gatt_client *gatt,
 					bool reliable, const uint8_t *value,
-					size_t value_len, void *data)
+					size_t value_len, void *data,
+					async_dbus_op_complete_t complete)
 {
 	struct async_dbus_op *op;
 
@@ -377,6 +379,7 @@ static bool start_long_write(DBusMessage *msg, uint16_t handle,
 
 	op->msg = dbus_message_ref(msg);
 	op->data = data;
+	op->complete = complete;
 
 	if (bt_gatt_client_write_long_value(gatt, reliable, handle,
 							0, value, value_len,
@@ -392,7 +395,8 @@ static bool start_long_write(DBusMessage *msg, uint16_t handle,
 static bool start_write_request(DBusMessage *msg, uint16_t handle,
 					struct bt_gatt_client *gatt,
 					const uint8_t *value, size_t value_len,
-					void *data)
+					void *data,
+					async_dbus_op_complete_t complete)
 {
 	struct async_dbus_op *op;
 
@@ -402,6 +406,7 @@ static bool start_write_request(DBusMessage *msg, uint16_t handle,
 
 	op->msg = dbus_message_ref(msg);
 	op->data = data;
+	op->complete = complete;
 
 	if (bt_gatt_client_write_value(gatt, handle, value, value_len,
 							write_cb, op,
@@ -413,11 +418,63 @@ static bool start_write_request(DBusMessage *msg, uint16_t handle,
 	return false;
 }
 
+static bool desc_write_complete(void *data)
+{
+	struct descriptor *desc = data;
+
+	desc->in_write = false;
+
+	/*
+	 * The descriptor might have been unregistered during the read. Return
+	 * failure.
+	 */
+	return !!desc->chrc;
+}
+
 static DBusMessage *descriptor_write_value(DBusConnection *conn,
 					DBusMessage *msg, void *user_data)
 {
-	/* TODO: Implement */
-	return btd_error_failed(msg, "Not implemented");
+	struct descriptor *desc = user_data;
+	struct bt_gatt_client *gatt = desc->chrc->service->client->gatt;
+	uint8_t *value = NULL;
+	size_t value_len = 0;
+	bool result;
+	bt_uuid_t uuid;
+
+	if (desc->in_write)
+		return btd_error_in_progress(msg);
+
+	if (!parse_value_arg(msg, &value, &value_len))
+		return btd_error_invalid_args(msg);
+
+	/*
+	 * Don't allow writing to Client Characteristic Configuration
+	 * descriptors. We achieve this through the StartNotify and StopNotify
+	 * methods on GattCharacteristic1.
+	 */
+	bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
+	if (bt_uuid_cmp(&desc->uuid, &uuid))
+		return btd_error_not_permitted(msg, "Write not permitted");
+
+	/*
+	 * Based on the value length and the MTU, either use a write or a long
+	 * write.
+	 */
+	if (value_len <= (unsigned) bt_gatt_client_get_mtu(gatt) - 3)
+		result = start_write_request(msg, desc->handle, gatt, value,
+							value_len, desc,
+							desc_write_complete);
+	else
+		result = start_long_write(msg, desc->handle, gatt, false, value,
+							value_len, desc,
+							desc_write_complete);
+
+	if (!result)
+		return btd_error_failed(msg, "Failed to initiate write");
+
+	desc->in_write = true;
+
+	return NULL;
 }
 
 static const GDBusPropertyTable descriptor_properties[] = {
@@ -669,6 +726,19 @@ static DBusMessage *characteristic_read_value(DBusConnection *conn,
 	return btd_error_failed(msg, "Failed to send read request");
 }
 
+static bool chrc_write_complete(void *data)
+{
+	struct characteristic *chrc = data;
+
+	chrc->in_write = false;
+
+	/*
+	 * The characteristic might have been unregistered during the read.
+	 * Return failure.
+	 */
+	return !!chrc->service;
+}
+
 static DBusMessage *characteristic_write_value(DBusConnection *conn,
 					DBusMessage *msg, void *user_data)
 {
@@ -709,10 +779,12 @@ static DBusMessage *characteristic_write_value(DBusConnection *conn,
 		if (value_len <= (unsigned) mtu - 3)
 			result = start_write_request(msg, chrc->value_handle,
 							gatt, value,
-							value_len, chrc);
+							value_len, chrc,
+							chrc_write_complete);
 		else
 			result = start_long_write(msg, chrc->value_handle, gatt,
-						false, value, value_len, chrc);
+						false, value, value_len, chrc,
+						chrc_write_complete);
 
 		if (result)
 			goto done_async;
@@ -729,6 +801,7 @@ static DBusMessage *characteristic_write_value(DBusConnection *conn,
 
 done_async:
 	chrc->in_write = true;
+
 	return NULL;
 }