It is needed because in some cases we send few read requests to applications. Now all transactions data are overriden by last one, and if application wants to respond to previous requests, transaction data is not found. It happens when two devices will read attribute from one application in the same time or if device will read few values in time (i.e. read by type request or find by type value request). --- android/gatt.c | 77 ++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 27 deletions(-) diff --git a/android/gatt.c b/android/gatt.c index 429181f..f450eac 100644 --- a/android/gatt.c +++ b/android/gatt.c @@ -105,9 +105,6 @@ struct gatt_app { /* Valid for client applications */ struct queue *notifications; - - /* Transaction data valid for server application */ - struct pending_trans_data trans_id; }; struct element_id { @@ -174,6 +171,7 @@ struct gatt_device { struct app_connection { struct gatt_device *device; struct gatt_app *app; + struct queue *transactions; int32_t id; }; @@ -855,6 +853,7 @@ static void destroy_connection(void *data) connection_cleanup(conn->device); cleanup: + queue_destroy(conn->transactions, free); device_unref(conn->device); free(conn); } @@ -1304,9 +1303,15 @@ static struct app_connection *create_connection(struct gatt_device *device, new_conn->app = app; new_conn->id = last_conn_id++; + new_conn->transactions = queue_new(); + if (!new_conn->transactions) { + free(new_conn); + return NULL; + } + if (!queue_push_head(app_connections, new_conn)) { error("gatt: Cannot push client on the client queue!?"); - + queue_destroy(new_conn->transactions, free); free(new_conn); return NULL; } @@ -4167,26 +4172,35 @@ done: send_dev_pending_response(dev, opcode); } -static void set_trans_id(struct gatt_app *app, unsigned int id, int8_t opcode) +static struct pending_trans_data *conn_add_transact(struct app_connection *conn, + uint8_t opcode) { - app->trans_id.id = id; - app->trans_id.opcode = opcode; -} + struct pending_trans_data *transaction; + static int32_t trans_id = 1; -static void clear_trans_id(struct gatt_app *app) -{ - app->trans_id.id = 0; - app->trans_id.opcode = 0; + transaction = new0(struct pending_trans_data, 1); + if (!transaction) + return NULL; + + if (!queue_push_tail(conn->transactions, transaction)) { + free(transaction); + return NULL; + } + + transaction->id = trans_id++; + transaction->opcode = opcode; + + return transaction; } static void read_cb(uint16_t handle, uint16_t offset, uint8_t att_opcode, bdaddr_t *bdaddr, void *user_data) { + struct pending_trans_data *transaction; struct hal_ev_gatt_server_request_read ev; struct gatt_app *app; struct app_connection *conn; int32_t id = PTR_TO_INT(user_data); - static int32_t trans_id = 1; app = find_app_by_id(id); if (!app) { @@ -4203,14 +4217,16 @@ static void read_cb(uint16_t handle, uint16_t offset, uint8_t att_opcode, memset(&ev, 0, sizeof(ev)); /* Store the request data, complete callback and transaction id */ - set_trans_id(app, trans_id++, att_opcode); + transaction = conn_add_transact(conn, att_opcode); + if (!transaction) + goto failed; bdaddr2android(bdaddr, ev.bdaddr); ev.conn_id = conn->id; ev.attr_handle = handle; ev.offset = offset; ev.is_long = att_opcode == ATT_OP_READ_BLOB_REQ; - ev.trans_id = app->trans_id.id; + ev.trans_id = transaction->id; ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT, HAL_EV_GATT_SERVER_REQUEST_READ, @@ -4230,9 +4246,9 @@ static void write_cb(uint16_t handle, uint16_t offset, { uint8_t buf[IPC_MTU]; struct hal_ev_gatt_server_request_write *ev = (void *) buf; + struct pending_trans_data *transaction; struct gatt_app *app; int32_t id = PTR_TO_INT(user_data); - static int32_t trans_id = 1; struct app_connection *conn; app = find_app_by_id(id); @@ -4248,7 +4264,9 @@ static void write_cb(uint16_t handle, uint16_t offset, } /* Store the request data, complete callback and transaction id */ - set_trans_id(app, trans_id++, att_opcode); + transaction = conn_add_transact(conn, att_opcode); + if (!transaction) + goto failed; /* TODO figure it out */ if (att_opcode == ATT_OP_EXEC_WRITE_REQ) @@ -4261,7 +4279,7 @@ static void write_cb(uint16_t handle, uint16_t offset, ev->offset = offset; ev->conn_id = conn->id; - ev->trans_id = app->trans_id.id; + ev->trans_id = transaction->id; ev->is_prep = att_opcode == ATT_OP_PREP_WRITE_REQ; ev->need_rsp = att_opcode == ATT_OP_WRITE_REQ; @@ -4555,11 +4573,18 @@ reply: HAL_OP_GATT_SERVER_SEND_INDICATION, status); } +static bool match_trans_id(const void *data, const void *user_data) +{ + const struct pending_trans_data *transaction = data; + + return transaction->id == PTR_TO_UINT(user_data); +} + static void handle_server_send_response(const void *buf, uint16_t len) { const struct hal_cmd_gatt_server_send_response *cmd = buf; + struct pending_trans_data *transaction; struct app_connection *conn; - struct gatt_app *app; uint8_t status; DBG(""); @@ -4571,22 +4596,20 @@ static void handle_server_send_response(const void *buf, uint16_t len) goto reply; } - app = conn->app; - - if ((unsigned int)cmd->trans_id != app->trans_id.id) { - error("gatt: transaction ID mismatch (%d!=%d)", - cmd->trans_id, app->trans_id.id); - + transaction = queue_remove_if(conn->transactions, match_trans_id, + UINT_TO_PTR(cmd->trans_id)); + if (!transaction) { + error("gatt: transaction ID = %d not found", cmd->trans_id); status = HAL_STATUS_FAILED; goto reply; } - send_gatt_response(conn->app->trans_id.opcode, cmd->handle, cmd->offset, + send_gatt_response(transaction->opcode, cmd->handle, cmd->offset, cmd->status, cmd->len, cmd->data, &conn->device->bdaddr); /* Clean request data */ - clear_trans_id(app); + free(transaction); status = HAL_STATUS_SUCCESS; -- 1.9.3 -- To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html