Return-Path: MIME-Version: 1.0 In-Reply-To: <1415196669-582-2-git-send-email-luiz.dentz@gmail.com> References: <1415196669-582-1-git-send-email-luiz.dentz@gmail.com> <1415196669-582-2-git-send-email-luiz.dentz@gmail.com> Date: Wed, 5 Nov 2014 14:11:46 -0800 Message-ID: Subject: Re: [PATCH BlueZ 2/2] shared/gatt-db: Rework API From: Arman Uguray To: Luiz Augusto von Dentz Cc: BlueZ development Content-Type: text/plain; charset=UTF-8 Sender: linux-bluetooth-owner@vger.kernel.org List-ID: Hi Luiz, > On Wed, Nov 5, 2014 at 6:11 AM, Luiz Augusto von Dentz wrote: > From: Luiz Augusto von Dentz > > This rework the API to use gatt_db_attribute whenever possible which > simplify the code adn reduces the number of lookups. > --- > android/gatt.c | 603 +++++++++++++++++++++++++---------------------- > src/shared/gatt-db.c | 445 +++++++++++++++------------------- > src/shared/gatt-db.h | 87 ++++--- > src/shared/gatt-server.c | 37 ++- > 4 files changed, 582 insertions(+), 590 deletions(-) > > diff --git a/android/gatt.c b/android/gatt.c > index b3dd6d3..7a7be6d 100644 > --- a/android/gatt.c > +++ b/android/gatt.c > @@ -94,6 +94,8 @@ static const char *device_state_str[] = { > struct pending_trans_data { > unsigned int id; > uint8_t opcode; > + struct gatt_db_attribute *attrib; > + unsigned int serial_id; > }; > > struct gatt_app { > @@ -199,7 +201,7 @@ static struct queue *services_sdp = NULL; > static struct queue *listen_apps = NULL; > static struct gatt_db *gatt_db = NULL; > > -static uint16_t service_changed_handle = 0; > +static struct gatt_db_attribute *service_changed_attrib = NULL; > > static GIOChannel *le_io = NULL; > static GIOChannel *bredr_io = NULL; > @@ -676,7 +678,7 @@ enum pend_req_state { > }; > > struct pending_request { > - uint16_t handle; > + struct gatt_db_attribute *attrib; > int length; > uint8_t *value; > uint16_t offset; > @@ -998,11 +1000,16 @@ static void send_exchange_mtu_request(struct gatt_device *device) > static void notify_att_range_change(struct gatt_device *dev, > struct att_range *range) > { > + uint16_t handle; > uint16_t length = 0; > uint16_t ccc; > uint8_t *pdu; > size_t mtu; > > + handle = gatt_db_attribute_get_handle(service_changed_attrib); > + if (!handle) > + return; > + > ccc = bt_get_gatt_ccc(&dev->bdaddr); > if (!ccc) > return; > @@ -1011,14 +1018,12 @@ static void notify_att_range_change(struct gatt_device *dev, > > switch (ccc) { > case 0x0001: > - length = enc_notification(service_changed_handle, > - (uint8_t *) range, > + length = enc_notification(handle, (uint8_t *) range, > sizeof(*range), pdu, mtu); > break; > case 0x0002: > - length = enc_indication(service_changed_handle, > - (uint8_t *) range, sizeof(*range), pdu, > - mtu); > + length = enc_indication(handle, (uint8_t *) range, > + sizeof(*range), pdu, mtu); > break; > default: > /* 0xfff4 reserved for future use */ > @@ -1475,7 +1480,7 @@ static void connect_cb(GIOChannel *io, GError *gerr, gpointer user_data) > * constant all the time, thus they should be excluded from > * range indicating changes. > */ > - range.start = service_changed_handle + 2; > + range.start = gatt_db_attribute_get_handle(service_changed_attrib) + 2; > range.end = 0xffff; > > /* > @@ -4210,6 +4215,7 @@ static void handle_server_add_service(const void *buf, uint16_t len) > const struct hal_cmd_gatt_server_add_service *cmd = buf; > struct hal_ev_gatt_server_service_added ev; > struct gatt_app *server; > + struct gatt_db_attribute *service; > uint8_t status; > bt_uuid_t uuid; > > @@ -4225,9 +4231,14 @@ static void handle_server_add_service(const void *buf, uint16_t len) > > android2uuid(cmd->srvc_id.uuid, &uuid); > > - ev.srvc_handle = gatt_db_add_service(gatt_db, &uuid, > - cmd->srvc_id.is_primary, > + service = gatt_db_add_service(gatt_db, &uuid, cmd->srvc_id.is_primary, > cmd->num_handles); > + if (!service) { > + status = HAL_STATUS_FAILED; > + goto failed; > + } > + > + ev.srvc_handle = gatt_db_attribute_get_handle(service); > if (!ev.srvc_handle) { > status = HAL_STATUS_FAILED; > goto failed; > @@ -4252,6 +4263,7 @@ static void handle_server_add_included_service(const void *buf, uint16_t len) > const struct hal_cmd_gatt_server_add_inc_service *cmd = buf; > struct hal_ev_gatt_server_inc_srvc_added ev; > struct gatt_app *server; > + struct gatt_db_attribute *service, *include; > uint8_t status; > > DBG(""); > @@ -4264,10 +4276,20 @@ static void handle_server_add_included_service(const void *buf, uint16_t len) > goto failed; > } > > - ev.incl_srvc_handle = gatt_db_add_included_service(gatt_db, > - cmd->service_handle, > - cmd->included_handle); > - if (!ev.incl_srvc_handle) { > + service = gatt_db_get_attribute(gatt_db, cmd->service_handle); > + if (!service) { > + status = HAL_STATUS_FAILED; > + goto failed; > + } > + > + include = gatt_db_get_attribute(gatt_db, cmd->included_handle); > + if (!service) { > + status = HAL_STATUS_FAILED; > + goto failed; > + } > + > + service = gatt_db_service_add_included(service, include); > + if (!service) { > status = HAL_STATUS_FAILED; > goto failed; > } > @@ -4360,8 +4382,11 @@ static void send_dev_complete_response(struct gatt_device *device, > val = queue_pop_head(temp); > while (val) { > uint8_t *value = adl->data[iterator++]; > + uint16_t handle; > > - put_le16(val->handle, value); > + handle = gatt_db_attribute_get_handle(val->attrib); > + > + put_le16(handle, value); > memcpy(&value[2], val->value, val->length); > > destroy_pending_request(val); > @@ -4426,12 +4451,13 @@ static void send_dev_complete_response(struct gatt_device *device, > val = queue_pop_head(temp); > while (val) { > uint8_t *value = adl->data[iterator++]; > - uint16_t end_handle; > + uint16_t start_handle, end_handle; > > - end_handle = gatt_db_get_end_handle(gatt_db, > - val->handle); > + gatt_db_attribute_get_service_handles(val->attrib, > + &start_handle, > + &end_handle); > > - put_le16(val->handle, value); > + put_le16(start_handle, value); > put_le16(end_handle, &value[2]); > memcpy(&value[4], val->value, val->length); > > @@ -4471,14 +4497,17 @@ static void send_dev_complete_response(struct gatt_device *device, > break; > } > > - range->start = val->handle; > + range->start = gatt_db_attribute_get_handle( > + val->attrib); > range->end = range->start; > > - /* Get proper end handle if its group type */ > - type = gatt_db_get_attribute_type(gatt_db, val->handle); > + type = gatt_db_attribute_get_type(val->attrib); > if (is_service(type)) > - range->end = gatt_db_get_end_handle(gatt_db, > - val->handle); > + range->end = > + gatt_db_attribute_get_service_handles( > + val->attrib, > + NULL, > + &range->end); > > list = g_slist_append(list, range); > > @@ -4515,17 +4544,22 @@ static void send_dev_complete_response(struct gatt_device *device, > len = enc_write_resp(rsp); > destroy_pending_request(val); > break; > - case ATT_OP_PREP_WRITE_REQ: > + case ATT_OP_PREP_WRITE_REQ: { > + uint16_t handle; > + > val = queue_pop_head(device->pending_requests); > if (val->error) { > error = val->error; > goto done; > } > > - len = enc_prep_write_resp(val->handle, val->offset, val->value, > + handle = gatt_db_attribute_get_handle(val->attrib); > + > + len = enc_prep_write_resp(handle, val->offset, val->value, > val->length, rsp, mtu); > destroy_pending_request(val); > break; > + } > default: > break; > } > @@ -4545,12 +4579,11 @@ struct request_processing_data { > struct gatt_device *device; > }; > > -static bool match_dev_request_by_handle(const void *data, const void *user_data) > +static bool match_dev_request_by_attrib(const void *data, const void *user_data) > { > const struct pending_request *handle_data = data; > - uint16_t handle = PTR_TO_UINT(user_data); > > - return handle_data->handle == handle; > + return handle_data->attrib == user_data; > } > > static uint8_t check_device_permissions(struct gatt_device *device, > @@ -4623,11 +4656,12 @@ static uint8_t check_device_permissions(struct gatt_device *device, > return 0; > } > > -static void fill_gatt_response(struct pending_request *request, uint16_t handle, > +static void fill_gatt_response(struct pending_request *request, > + struct gatt_db_attribute *attrib, > uint16_t offset, uint8_t status, > uint16_t len, const uint8_t *data) > { > - request->handle = handle; > + request->attrib = attrib; > request->offset = offset; > request->length = len; > request->state = REQUEST_DONE; > @@ -4646,38 +4680,49 @@ static void fill_gatt_response(struct pending_request *request, uint16_t handle, > memcpy(request->value, data, len); > } > > -static void fill_gatt_response_by_handle(uint16_t handle, uint16_t offset, > - uint8_t status, uint16_t len, > - const uint8_t *data, > - struct gatt_device *dev) > +static uint8_t err_to_att(int err) > { > - struct pending_request *entry; > + if (!err || (err > 0 && err < UINT8_MAX)) > + return err; > > - entry = queue_find(dev->pending_requests, match_dev_request_by_handle, > - UINT_TO_PTR(handle)); > - if (!entry) { > - error("gatt: No pending response! Bogus android response?"); > - return; > + switch (err) { > + case -ENOENT: > + return ATT_ECODE_INVALID_HANDLE; > + case -ENOMEM: > + return ATT_ECODE_INSUFF_RESOURCES; > + default: > + return ATT_ECODE_UNLIKELY; > } > +} > + > +static void attribute_read_cb(struct gatt_db_attribute *attrib, int err, > + const uint8_t *value, size_t length, > + void *user_data) > +{ > + struct pending_request *resp_data = user_data; > + uint8_t error = err_to_att(err); > > - fill_gatt_response(entry, handle, offset, status, len, data); > + fill_gatt_response(resp_data, attrib, resp_data->offset, error, length, > + value); > } > > static void read_requested_attributes(void *data, void *user_data) > { > struct pending_request *resp_data = data; > struct request_processing_data *process_data = user_data; > + struct gatt_db_attribute *attrib; > uint32_t permissions; > - uint8_t *value = NULL, error; > - int value_len = 0; > + uint8_t error; > > - if (!gatt_db_get_attribute_permissions(gatt_db, resp_data->handle, > - &permissions)) { > + attrib = resp_data->attrib; > + if (!attrib) { > resp_data->error = ATT_ECODE_ATTR_NOT_FOUND; > resp_data->state = REQUEST_DONE; > return; > } > > + gatt_db_attribute_get_permissions(attrib, &permissions); > + > /* > * Check if it is attribute we didn't declare permissions, like service > * declaration or included service. Set permissions to read only > @@ -4696,18 +4741,9 @@ static void read_requested_attributes(void *data, void *user_data) > > resp_data->state = REQUEST_PENDING; > > - if (!gatt_db_read(gatt_db, resp_data->handle, > - resp_data->offset, > - process_data->opcode, > - &process_data->device->bdaddr, > - &value, &value_len)) > - error = ATT_ECODE_UNLIKELY; > - > - /* We have value here already if no callback will be called */ > - if (value_len >= 0) > - fill_gatt_response(resp_data, resp_data->handle, > - resp_data->offset, error, value_len, > - value); > + gatt_db_attribute_read(attrib, resp_data->offset, process_data->opcode, > + &process_data->device->bdaddr, > + attribute_read_cb, resp_data); > } > > static void process_dev_pending_requests(struct gatt_device *device, > @@ -4729,7 +4765,9 @@ static void process_dev_pending_requests(struct gatt_device *device, > } > > static struct pending_trans_data *conn_add_transact(struct app_connection *conn, > - uint8_t opcode) > + uint8_t opcode, > + struct gatt_db_attribute *attrib, > + unsigned int serial_id) > { > struct pending_trans_data *transaction; > static int32_t trans_id = 1; > @@ -4745,21 +4783,25 @@ static struct pending_trans_data *conn_add_transact(struct app_connection *conn, > > transaction->id = trans_id++; > transaction->opcode = opcode; > + transaction->attrib = attrib; > + transaction->serial_id = serial_id; > > return transaction; > } > > -static void read_cb(uint16_t handle, uint16_t offset, uint8_t att_opcode, > - bdaddr_t *bdaddr, void *user_data) > +static void read_cb(struct gatt_db_attribute *attrib, unsigned int id, > + uint16_t offset, uint8_t 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); > - struct gatt_device *dev; > + int32_t app_id = PTR_TO_INT(user_data); > > - app = find_app_by_id(id); > + DBG("id %u", id); > + > + app = find_app_by_id(app_id); > if (!app) { > error("gatt: read_cb, cound not found app id"); > goto failed; > @@ -4774,15 +4816,15 @@ 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 */ > - transaction = conn_add_transact(conn, att_opcode); > + transaction = conn_add_transact(conn, opcode, attrib, id); > if (!transaction) > goto failed; > > bdaddr2android(bdaddr, ev.bdaddr); > ev.conn_id = conn->id; > - ev.attr_handle = handle; > + ev.attr_handle = gatt_db_attribute_get_handle(attrib); > ev.offset = offset; > - ev.is_long = att_opcode == ATT_OP_READ_BLOB_REQ; > + ev.is_long = opcode == ATT_OP_READ_BLOB_REQ; > ev.trans_id = transaction->id; > > ipc_send_notif(hal_ipc, HAL_SERVICE_ID_GATT, > @@ -4792,26 +4834,23 @@ static void read_cb(uint16_t handle, uint16_t offset, uint8_t att_opcode, > return; > > failed: > - dev = find_device_by_addr(bdaddr); > - if (dev) > - fill_gatt_response_by_handle(handle, 0, ATT_ECODE_UNLIKELY, 0, > - NULL, dev); > + gatt_db_attribute_read_result(attrib, id, -ENOENT, NULL, 0); > } > > -static void write_cb(uint16_t handle, uint16_t offset, > - const uint8_t *value, size_t len, > - uint8_t att_opcode, bdaddr_t *bdaddr, > - void *user_data) > +static void write_cb(struct gatt_db_attribute *attrib, unsigned int id, > + uint16_t offset, const uint8_t *value, size_t len, > + uint8_t opcode, bdaddr_t *bdaddr, void *user_data) > { > 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); > + int32_t app_id = PTR_TO_INT(user_data); > struct app_connection *conn; > - struct gatt_device *dev; > > - app = find_app_by_id(id); > + DBG("id %u", id); > + > + app = find_app_by_id(app_id); > if (!app) { > error("gatt: write_cb could not found app id"); > goto failed; > @@ -4827,27 +4866,26 @@ static void write_cb(uint16_t handle, uint16_t offset, > * Remember that this application has ongoing prep write > * Need it later to find out where to send execute write > */ > - if (att_opcode == ATT_OP_PREP_WRITE_REQ) > + if (opcode == ATT_OP_PREP_WRITE_REQ) > conn->wait_execute_write = true; > > /* Store the request data, complete callback and transaction id */ > - transaction = conn_add_transact(conn, att_opcode); > + transaction = conn_add_transact(conn, opcode, attrib, id); > if (!transaction) > goto failed; > > memset(ev, 0, sizeof(*ev)); > > bdaddr2android(bdaddr, &ev->bdaddr); > - ev->attr_handle = handle; > + ev->attr_handle = gatt_db_attribute_get_handle(attrib); > ev->offset = offset; > > ev->conn_id = conn->id; > ev->trans_id = transaction->id; > > - ev->is_prep = att_opcode == ATT_OP_PREP_WRITE_REQ; > + ev->is_prep = opcode == ATT_OP_PREP_WRITE_REQ; > > - if (att_opcode == ATT_OP_WRITE_REQ || > - att_opcode == ATT_OP_PREP_WRITE_REQ) > + if (opcode == ATT_OP_WRITE_REQ || opcode == ATT_OP_PREP_WRITE_REQ) > ev->need_rsp = 0x01; > > ev->length = len; > @@ -4859,10 +4897,7 @@ static void write_cb(uint16_t handle, uint16_t offset, > return; > > failed: > - dev = find_device_by_addr(bdaddr); > - if (dev) > - fill_gatt_response_by_handle(handle, 0, ATT_ECODE_UNLIKELY, 0, > - NULL, dev); > + gatt_db_attribute_write_result(attrib, id, ATT_ECODE_UNLIKELY); > } > > static uint32_t android_to_gatt_permissions(int32_t hal_permissions) > @@ -4904,6 +4939,7 @@ static void handle_server_add_characteristic(const void *buf, uint16_t len) > const struct hal_cmd_gatt_server_add_characteristic *cmd = buf; > struct hal_ev_gatt_server_characteristic_added ev; > struct gatt_app *server; > + struct gatt_db_attribute *attrib; > bt_uuid_t uuid; > uint8_t status; > uint32_t permissions; > @@ -4919,22 +4955,28 @@ static void handle_server_add_characteristic(const void *buf, uint16_t len) > goto failed; > } > > + attrib = gatt_db_get_attribute(gatt_db, cmd->service_handle); > + if (!attrib) { > + status = HAL_STATUS_FAILED; > + goto failed; > + } > + > android2uuid(cmd->uuid, &uuid); > permissions = android_to_gatt_permissions(cmd->permissions); > > - ev.char_handle = gatt_db_add_characteristic(gatt_db, > - cmd->service_handle, > + attrib = gatt_db_service_add_characteristic(attrib, > &uuid, permissions, > cmd->properties, > read_cb, write_cb, > INT_TO_PTR(app_id)); > - if (!ev.char_handle) > + if (!attrib) > status = HAL_STATUS_FAILED; > else > status = HAL_STATUS_SUCCESS; > > failed: > ev.srvc_handle = cmd->service_handle; > + ev.char_handle = gatt_db_attribute_get_handle(attrib); > ev.status = status; > ev.server_if = app_id; > ev.status = status == HAL_STATUS_SUCCESS ? GATT_SUCCESS : GATT_FAILURE; > @@ -4952,6 +4994,7 @@ static void handle_server_add_descriptor(const void *buf, uint16_t len) > const struct hal_cmd_gatt_server_add_descriptor *cmd = buf; > struct hal_ev_gatt_server_descriptor_added ev; > struct gatt_app *server; > + struct gatt_db_attribute *attrib; > bt_uuid_t uuid; > uint8_t status; > uint32_t permissions; > @@ -4970,12 +5013,16 @@ static void handle_server_add_descriptor(const void *buf, uint16_t len) > android2uuid(cmd->uuid, &uuid); > permissions = android_to_gatt_permissions(cmd->permissions); > > - ev.descr_handle = gatt_db_add_char_descriptor(gatt_db, > - cmd->service_handle, > - &uuid, permissions, > + attrib = gatt_db_get_attribute(gatt_db, cmd->service_handle); > + if (!attrib) { > + status = HAL_STATUS_FAILED; > + goto failed; > + } > + > + attrib = gatt_db_service_add_descriptor(attrib, &uuid, permissions, > read_cb, write_cb, > INT_TO_PTR(app_id)); > - if (!ev.descr_handle) > + if (!attrib) > status = HAL_STATUS_FAILED; > else > status = HAL_STATUS_SUCCESS; > @@ -4996,9 +5043,9 @@ failed: > static void notify_service_change(void *data, void *user_data) > { > struct att_range range; > + struct gatt_db_attribute *attrib = user_data; > > - range.start = PTR_TO_UINT(user_data); > - range.end = gatt_db_get_end_handle(gatt_db, range.start); > + gatt_db_attribute_get_service_handles(attrib, &range.start, &range.end); > > /* In case of db error */ > if (!range.end) > @@ -5105,13 +5152,18 @@ static struct service_sdp *new_service_sdp_record(int32_t service_handle) > { > bt_uuid_t uuid; > struct service_sdp *s; > + struct gatt_db_attribute *attrib; > uint16_t end_handle; > > - end_handle = gatt_db_get_end_handle(gatt_db, service_handle); > + attrib = gatt_db_get_attribute(gatt_db, service_handle); > + if (!attrib) > + return NULL; > + > + gatt_db_attribute_get_service_handles(attrib, NULL, &end_handle); > if (!end_handle) > return NULL; > > - if (!gatt_db_get_service_uuid(gatt_db, service_handle, &uuid)) > + if (!gatt_db_attribute_get_service_uuid(attrib, &uuid)) > return NULL; > > s = new0(struct service_sdp, 1); > @@ -5177,6 +5229,7 @@ static void handle_server_start_service(const void *buf, uint16_t len) > const struct hal_cmd_gatt_server_start_service *cmd = buf; > struct hal_ev_gatt_server_service_started ev; > struct gatt_app *server; > + struct gatt_db_attribute *attrib; > uint8_t status; > > DBG(""); > @@ -5204,7 +5257,13 @@ static void handle_server_start_service(const void *buf, uint16_t len) > goto failed; > } > > - if (!gatt_db_service_set_active(gatt_db, cmd->service_handle, true)) { > + attrib = gatt_db_get_attribute(gatt_db, cmd->service_handle); > + if (!attrib) { > + status = HAL_STATUS_FAILED; > + goto failed; > + } > + > + if (!gatt_db_service_set_active(attrib, true)) { > /* > * no need to clean SDP since this can fail only if service > * handle is invalid in which case add_sdp_record() also fails > @@ -5213,8 +5272,7 @@ static void handle_server_start_service(const void *buf, uint16_t len) > goto failed; > } > > - queue_foreach(gatt_devices, notify_service_change, > - UINT_TO_PTR(cmd->service_handle)); > + queue_foreach(gatt_devices, notify_service_change, attrib); > > status = HAL_STATUS_SUCCESS; > > @@ -5235,6 +5293,7 @@ static void handle_server_stop_service(const void *buf, uint16_t len) > const struct hal_cmd_gatt_server_stop_service *cmd = buf; > struct hal_ev_gatt_server_service_stopped ev; > struct gatt_app *server; > + struct gatt_db_attribute *attrib; > uint8_t status; > > DBG(""); > @@ -5247,7 +5306,13 @@ static void handle_server_stop_service(const void *buf, uint16_t len) > goto failed; > } > > - if (!gatt_db_service_set_active(gatt_db, cmd->service_handle, false)) { > + attrib = gatt_db_get_attribute(gatt_db, cmd->service_handle); > + if (!attrib) { > + status = HAL_STATUS_FAILED; > + goto failed; > + } > + > + if (!gatt_db_service_set_active(attrib, false)) { > status = HAL_STATUS_FAILED; > goto failed; > } > @@ -5256,8 +5321,7 @@ static void handle_server_stop_service(const void *buf, uint16_t len) > > status = HAL_STATUS_SUCCESS; > > - queue_foreach(gatt_devices, notify_service_change, > - UINT_TO_PTR(cmd->service_handle)); > + queue_foreach(gatt_devices, notify_service_change, attrib); > > failed: > ev.status = status == HAL_STATUS_SUCCESS ? GATT_SUCCESS : GATT_FAILURE; > @@ -5276,6 +5340,7 @@ static void handle_server_delete_service(const void *buf, uint16_t len) > const struct hal_cmd_gatt_server_delete_service *cmd = buf; > struct hal_ev_gatt_server_service_deleted ev; > struct gatt_app *server; > + struct gatt_db_attribute *attrib; > uint8_t status; > > DBG(""); > @@ -5288,7 +5353,13 @@ static void handle_server_delete_service(const void *buf, uint16_t len) > goto failed; > } > > - if (!gatt_db_remove_service(gatt_db, cmd->service_handle)) { > + attrib = gatt_db_get_attribute(gatt_db, cmd->service_handle); > + if (!attrib) { > + status = HAL_STATUS_FAILED; > + goto failed; > + } > + > + if (!gatt_db_remove_service(gatt_db, attrib)) { > status = HAL_STATUS_FAILED; > goto failed; > } > @@ -5377,7 +5448,6 @@ 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; > - uint16_t handle = cmd->handle; > struct app_connection *conn; > uint8_t status; > > @@ -5405,17 +5475,22 @@ static void handle_server_send_response(const void *buf, uint16_t len) > if (pending_execute_write()) > goto done; > > - /* Make sure handle is 0. We need it to find pending request */ > - handle = 0; > - > /* > * FIXME: Handle situation when not all server applications > * respond with a success. > */ > } > > - fill_gatt_response_by_handle(handle, cmd->offset, cmd->status, cmd->len, > - cmd->data, conn->device); > + if (transaction->opcode < ATT_OP_WRITE_REQ) > + gatt_db_attribute_read_result(transaction->attrib, > + transaction->serial_id, > + cmd->status, > + cmd->data, cmd->len); > + else > + gatt_db_attribute_write_result(transaction->attrib, > + transaction->serial_id, > + cmd->status); > + > send_dev_complete_response(conn->device, transaction->opcode); > > done: > @@ -5564,7 +5639,7 @@ static uint8_t read_by_group_type(const uint8_t *cmd, uint16_t cmd_len, > } > > while (queue_peek_head(q)) { > - uint16_t handle = PTR_TO_UINT(queue_pop_head(q)); > + struct gatt_db_attribute *attrib = queue_pop_head(q); > struct pending_request *entry; > > entry = new0(struct pending_request, 1); > @@ -5573,7 +5648,7 @@ static uint8_t read_by_group_type(const uint8_t *cmd, uint16_t cmd_len, > return ATT_ECODE_UNLIKELY; > } > > - entry->handle = handle; > + entry->attrib = attrib; > entry->state = REQUEST_INIT; > > if (!queue_push_tail(device->pending_requests, entry)) { > @@ -5621,7 +5696,7 @@ static uint8_t read_by_type(const uint8_t *cmd, uint16_t cmd_len, > > while (queue_peek_head(q)) { > struct pending_request *data; > - uint16_t handle = PTR_TO_UINT(queue_pop_head(q)); > + struct gatt_db_attribute *attrib = queue_pop_head(q); > > data = new0(struct pending_request, 1); > if (!data) { > @@ -5630,7 +5705,7 @@ static uint8_t read_by_type(const uint8_t *cmd, uint16_t cmd_len, > } > > data->state = REQUEST_INIT; > - data->handle = handle; > + data->attrib = attrib; > queue_push_tail(device->pending_requests, data); > } > > @@ -5644,6 +5719,7 @@ static uint8_t read_by_type(const uint8_t *cmd, uint16_t cmd_len, > static uint8_t read_request(const uint8_t *cmd, uint16_t cmd_len, > struct gatt_device *dev) > { > + struct gatt_db_attribute *attrib; > uint16_t handle; > uint16_t len; > uint16_t offset; > @@ -5668,7 +5744,8 @@ static uint8_t read_request(const uint8_t *cmd, uint16_t cmd_len, > return ATT_ECODE_REQ_NOT_SUPP; > } > > - if (handle == 0) > + attrib = gatt_db_get_attribute(gatt_db, handle); > + if (attrib == 0) > return ATT_ECODE_INVALID_HANDLE; > > data = new0(struct pending_request, 1); > @@ -5676,7 +5753,7 @@ static uint8_t read_request(const uint8_t *cmd, uint16_t cmd_len, > return ATT_ECODE_INSUFF_RESOURCES; > > data->offset = offset; > - data->handle = handle; > + data->attrib = attrib; > data->state = REQUEST_INIT; > if (!queue_push_tail(dev->pending_requests, data)) { > free(data); > @@ -5775,14 +5852,16 @@ static uint8_t find_info_handle(const uint8_t *cmd, uint16_t cmd_len, > while (queue_peek_head(q)) { > uint8_t *value; > const bt_uuid_t *type; > - uint16_t handle = PTR_TO_UINT(queue_pop_head(q)); > + struct gatt_db_attribute *attrib = queue_pop_head(q); > + uint16_t handle; > > - type = gatt_db_get_attribute_type(gatt_db, handle); > + type = gatt_db_attribute_get_type(attrib); > if (!type) > break; > > value = adl->data[iterator++]; > > + handle = gatt_db_attribute_get_handle(attrib); > put_le16(handle, value); > memcpy(&value[2], &type->value.u16, bt_uuid_len(type)); > } > @@ -5805,7 +5884,6 @@ static uint8_t find_by_type_request(const uint8_t *cmd, uint16_t cmd_len, > uint8_t search_value[cmd_len]; > size_t search_vlen; > uint16_t start, end; > - uint16_t handle; > struct queue *q; > bt_uuid_t uuid; > uint16_t len; > @@ -5826,8 +5904,8 @@ static uint8_t find_by_type_request(const uint8_t *cmd, uint16_t cmd_len, > > gatt_db_find_by_type(gatt_db, start, end, &uuid, q); > > - handle = PTR_TO_UINT(queue_pop_head(q)); > - while (handle) { > + while (queue_peek_head(q)) { > + struct gatt_db_attribute *attrib = queue_pop_head(q); > struct pending_request *data; > > data = new0(struct pending_request, 1); > @@ -5844,13 +5922,11 @@ static uint8_t find_by_type_request(const uint8_t *cmd, uint16_t cmd_len, > } > > data->state = REQUEST_INIT; > - data->handle = handle; > + data->attrib = attrib; > data->filter_vlen = search_vlen; > memcpy(data->filter_value, search_value, search_vlen); > > queue_push_tail(device->pending_requests, data); > - > - handle = PTR_TO_UINT(queue_pop_head(q)); > } > > queue_destroy(q, NULL); > @@ -5864,6 +5940,7 @@ static void write_cmd_request(const uint8_t *cmd, uint16_t cmd_len, > struct gatt_device *dev) > { > uint8_t value[cmd_len]; > + struct gatt_db_attribute *attrib; > uint32_t permissions; > uint16_t handle; > uint16_t len; > @@ -5876,13 +5953,18 @@ static void write_cmd_request(const uint8_t *cmd, uint16_t cmd_len, > if (handle == 0) > return; > > - if (!gatt_db_get_attribute_permissions(gatt_db, handle, &permissions)) > + attrib = gatt_db_get_attribute(gatt_db, handle); > + if (!attrib) > + return; > + > + if (!gatt_db_attribute_get_permissions(attrib, &permissions)) > return; > > if (check_device_permissions(dev, cmd[0], permissions)) > return; > > - gatt_db_write(gatt_db, handle, 0, value, vlen, cmd[0], &dev->bdaddr); > + gatt_db_attribute_write(attrib, 0, value, vlen, cmd[0], &dev->bdaddr, > + NULL, NULL); > } > > static void write_signed_cmd_request(const uint8_t *cmd, uint16_t cmd_len, > @@ -5890,6 +5972,7 @@ static void write_signed_cmd_request(const uint8_t *cmd, uint16_t cmd_len, > { > uint8_t value[ATT_DEFAULT_LE_MTU]; > uint8_t s[ATT_SIGNATURE_LEN]; > + struct gatt_db_attribute *attrib; > uint32_t permissions; > uint16_t handle; > uint16_t len; > @@ -5919,9 +6002,12 @@ static void write_signed_cmd_request(const uint8_t *cmd, uint16_t cmd_len, > if (handle == 0) > return; > > - if (!gatt_db_get_attribute_permissions(gatt_db, handle, &permissions)) > + attrib = gatt_db_get_attribute(gatt_db, handle); > + if (!attrib) > return; > > + gatt_db_attribute_get_permissions(attrib, &permissions); > + > if (check_device_permissions(dev, cmd[0], permissions)) > return; > > @@ -5949,16 +6035,28 @@ static void write_signed_cmd_request(const uint8_t *cmd, uint16_t cmd_len, > } > /* Signature OK, proceed with write */ > bt_update_sign_counter(&dev->bdaddr, REMOTE_CSRK, r_sign_cnt); > - gatt_db_write(gatt_db, handle, 0, value, vlen, cmd[0], > - &dev->bdaddr); > + gatt_db_attribute_write(attrib, 0, value, vlen, cmd[0], > + &dev->bdaddr, NULL, NULL); > } > } > > +static void attribute_write_cb(struct gatt_db_attribute *attrib, int err, > + void *user_data) > +{ > + struct pending_request *data = user_data; > + uint8_t error = err_to_att(err); > + > + DBG(""); > + > + fill_gatt_response(data, attrib, data->offset, error, 0, NULL); > +} > + > static uint8_t write_req_request(const uint8_t *cmd, uint16_t cmd_len, > struct gatt_device *dev) > { > uint8_t value[cmd_len]; > struct pending_request *data; > + struct gatt_db_attribute *attrib; > uint32_t permissions; > uint16_t handle; > uint16_t len; > @@ -5972,9 +6070,12 @@ static uint8_t write_req_request(const uint8_t *cmd, uint16_t cmd_len, > if (handle == 0) > return ATT_ECODE_INVALID_HANDLE; > > - if (!gatt_db_get_attribute_permissions(gatt_db, handle, &permissions)) > + attrib = gatt_db_get_attribute(gatt_db, handle); > + if (!attrib) > return ATT_ECODE_ATTR_NOT_FOUND; > > + gatt_db_attribute_get_permissions(attrib, &permissions); > + > error = check_device_permissions(dev, cmd[0], permissions); > if (error) > return error; > @@ -5983,7 +6084,7 @@ static uint8_t write_req_request(const uint8_t *cmd, uint16_t cmd_len, > if (!data) > return ATT_ECODE_INSUFF_RESOURCES; > > - data->handle = handle; > + data->attrib = attrib; > data->state = REQUEST_PENDING; > > if (!queue_push_tail(dev->pending_requests, data)) { > @@ -5991,8 +6092,9 @@ static uint8_t write_req_request(const uint8_t *cmd, uint16_t cmd_len, > return ATT_ECODE_INSUFF_RESOURCES; > } > > - if (!gatt_db_write(gatt_db, handle, 0, value, vlen, cmd[0], > - &dev->bdaddr)) { > + if (!gatt_db_attribute_write(attrib, 0, value, vlen, cmd[0], > + &dev->bdaddr, attribute_write_cb, > + data)) { > queue_remove(dev->pending_requests, data); > free(data); > return ATT_ECODE_UNLIKELY; > @@ -6008,6 +6110,7 @@ static uint8_t write_prep_request(const uint8_t *cmd, uint16_t cmd_len, > { > uint8_t value[cmd_len]; > struct pending_request *data; > + struct gatt_db_attribute *attrib; > uint32_t permissions; > uint16_t handle; > uint16_t offset; > @@ -6023,9 +6126,12 @@ static uint8_t write_prep_request(const uint8_t *cmd, uint16_t cmd_len, > if (handle == 0) > return ATT_ECODE_INVALID_HANDLE; > > - if (!gatt_db_get_attribute_permissions(gatt_db, handle, &permissions)) > + attrib = gatt_db_get_attribute(gatt_db, handle); > + if (!attrib) > return ATT_ECODE_ATTR_NOT_FOUND; > > + gatt_db_attribute_get_permissions(attrib, &permissions); > + > error = check_device_permissions(dev, cmd[0], permissions); > if (error) > return error; > @@ -6034,7 +6140,7 @@ static uint8_t write_prep_request(const uint8_t *cmd, uint16_t cmd_len, > if (!data) > return ATT_ECODE_INSUFF_RESOURCES; > > - data->handle = handle; > + data->attrib = attrib; > data->offset = offset; > data->state = REQUEST_PENDING; > > @@ -6043,8 +6149,8 @@ static uint8_t write_prep_request(const uint8_t *cmd, uint16_t cmd_len, > return ATT_ECODE_INSUFF_RESOURCES; > } > > - if (!gatt_db_write(gatt_db, handle, offset, value, vlen, cmd[0], > - &dev->bdaddr)) > + if (!gatt_db_attribute_write(attrib, 0, value, vlen, cmd[0], > + &dev->bdaddr, attribute_write_cb, data)) > return ATT_ECODE_UNLIKELY; > > return 0; > @@ -6061,7 +6167,7 @@ static void send_server_write_execute_notify(void *data, void *user_data) > > ev->conn_id = conn->id; > > - transaction = conn_add_transact(conn, ATT_OP_EXEC_WRITE_REQ); > + transaction = conn_add_transact(conn, ATT_OP_EXEC_WRITE_REQ, NULL, 0); > if (!transaction) { > conn->wait_execute_write = false; > return; > @@ -6258,12 +6364,12 @@ drop: > } > > struct gap_srvc_handles { > - uint16_t srvc; > + struct gatt_db_attribute *srvc; > > /* Characteristics */ > - uint16_t dev_name; > - uint16_t appear; > - uint16_t priv; > + struct gatt_db_attribute *dev_name; > + struct gatt_db_attribute *appear; > + struct gatt_db_attribute *priv; > }; > > static struct gap_srvc_handles gap_srvc_data; > @@ -6271,8 +6377,9 @@ static struct gap_srvc_handles gap_srvc_data; > #define APPEARANCE_GENERIC_PHONE 0x0040 > #define PERIPHERAL_PRIVACY_DISABLE 0x00 > > -static void gap_read_cb(uint16_t handle, uint16_t offset, uint8_t att_opcode, > - bdaddr_t *bdaddr, void *user_data) > +static void gap_read_cb(struct gatt_db_attribute *attrib, unsigned int id, > + uint16_t offset, uint8_t opcode, bdaddr_t *bdaddr, > + void *user_data) > { > struct pending_request *entry; > struct gatt_device *dev; > @@ -6285,12 +6392,12 @@ static void gap_read_cb(uint16_t handle, uint16_t offset, uint8_t att_opcode, > return; > } > > - entry = queue_find(dev->pending_requests, match_dev_request_by_handle, > - UINT_TO_PTR(handle)); > + entry = queue_find(dev->pending_requests, match_dev_request_by_attrib, > + attrib); > if (!entry) > return; > > - if (handle == gap_srvc_data.dev_name) { > + if (attrib == gap_srvc_data.dev_name) { > const char *name = bt_get_adapter_name(); > > entry->value = malloc0(strlen(name)); > @@ -6301,7 +6408,7 @@ static void gap_read_cb(uint16_t handle, uint16_t offset, uint8_t att_opcode, > > entry->length = strlen(name); > memcpy(entry->value, bt_get_adapter_name(), entry->length); > - } else if (handle == gap_srvc_data.appear) { > + } else if (attrib == gap_srvc_data.appear) { > entry->value = malloc0(2); > if (!entry->value) { > entry->error = ATT_ECODE_INSUFF_RESOURCES; > @@ -6310,7 +6417,7 @@ static void gap_read_cb(uint16_t handle, uint16_t offset, uint8_t att_opcode, > > put_le16(APPEARANCE_GENERIC_PHONE, entry->value); > entry->length = sizeof(uint8_t) * 2; > - } else if (handle == gap_srvc_data.priv) { > + } else if (attrib == gap_srvc_data.priv) { > entry->value = malloc0(1); > if (!entry->value) { > entry->error = ATT_ECODE_INSUFF_RESOURCES; > @@ -6341,7 +6448,7 @@ static void register_gap_service(void) > /* Device name characteristic */ > bt_uuid16_create(&uuid, GATT_CHARAC_DEVICE_NAME); > gap_srvc_data.dev_name = > - gatt_db_add_characteristic(gatt_db, gap_srvc_data.srvc, > + gatt_db_service_add_characteristic(gap_srvc_data.srvc, > &uuid, GATT_PERM_READ, > GATT_CHR_PROP_READ, > gap_read_cb, NULL, > @@ -6350,7 +6457,7 @@ static void register_gap_service(void) > /* Appearance */ > bt_uuid16_create(&uuid, GATT_CHARAC_APPEARANCE); > gap_srvc_data.appear = > - gatt_db_add_characteristic(gatt_db, gap_srvc_data.srvc, > + gatt_db_service_add_characteristic(gap_srvc_data.srvc, > &uuid, GATT_PERM_READ, > GATT_CHR_PROP_READ, > gap_read_cb, NULL, > @@ -6359,29 +6466,28 @@ static void register_gap_service(void) > /* Pripheral privacy flag */ > bt_uuid16_create(&uuid, GATT_CHARAC_PERIPHERAL_PRIV_FLAG); > gap_srvc_data.priv = > - gatt_db_add_characteristic(gatt_db, gap_srvc_data.srvc, > + gatt_db_service_add_characteristic(gap_srvc_data.srvc, > &uuid, GATT_PERM_READ, > GATT_CHR_PROP_READ, > gap_read_cb, NULL, > NULL); > > - gatt_db_service_set_active(gatt_db, gap_srvc_data.srvc , true); > + gatt_db_service_set_active(gap_srvc_data.srvc , true); > > /* SDP */ > bt_uuid16_create(&uuid, 0x1800); > - start = gap_srvc_data.srvc; > - end = gatt_db_get_end_handle(gatt_db, gap_srvc_data.srvc); > + gatt_db_attribute_get_service_handles(gap_srvc_data.srvc, &start, &end); > gap_sdp_handle = add_sdp_record(&uuid, start, end, > "Generic Access Profile"); > if (!gap_sdp_handle) > error("gatt: Failed to register GAP SDP record"); > } > > -static void device_info_read_cb(uint16_t handle, uint16_t offset, > - uint8_t att_opcode, bdaddr_t *bdaddr, > +static void device_info_read_cb(struct gatt_db_attribute *attrib, > + unsigned int id, uint16_t offset, > + uint8_t opcode, bdaddr_t *bdaddr, > void *user_data) > { > - struct pending_request *entry; > struct gatt_device *dev; > char *buf = user_data; > > @@ -6391,31 +6497,16 @@ static void device_info_read_cb(uint16_t handle, uint16_t offset, > return; > } > > - entry = queue_find(dev->pending_requests, match_dev_request_by_handle, > - UINT_TO_PTR(handle)); > - if (!entry) > - return; > - > - entry->value = malloc0(strlen(buf)); > - if (!entry->value) { > - entry->error = ATT_ECODE_UNLIKELY; > - goto done; > - } > - > - entry->length = strlen(buf); > - memcpy(entry->value, buf, entry->length); > - entry->offset = offset; > - > -done: > - entry->state = REQUEST_DONE; > + gatt_db_attribute_read_result(attrib, id, 0, user_data, strlen(buf)); > } > > -static void device_info_read_system_id_cb(uint16_t handle, uint16_t offset, > - uint8_t att_opcode, bdaddr_t *bdaddr, > +static void device_info_read_system_id_cb(struct gatt_db_attribute *attrib, > + unsigned int id, uint16_t offset, > + uint8_t opcode, bdaddr_t *bdaddr, > void *user_data) > { > - struct pending_request *entry; > struct gatt_device *dev; > + uint8_t pdu[8]; > > dev = find_device_by_addr(bdaddr); > if (!dev) { > @@ -6423,31 +6514,18 @@ static void device_info_read_system_id_cb(uint16_t handle, uint16_t offset, > return; > } > > - entry = queue_find(dev->pending_requests, match_dev_request_by_handle, > - UINT_TO_PTR(handle)); > - if (!entry) > - return; > - > - entry->value = malloc0(sizeof(uint64_t)); > - if (!entry->value) { > - entry->error = ATT_ECODE_UNLIKELY; > - goto done; > - } > - > - entry->length = sizeof(uint64_t); > - put_le64(bt_config_get_system_id(), entry->value); > - entry->offset = offset; > + put_le64(bt_config_get_system_id(), pdu); > > -done: > - entry->state = REQUEST_DONE; > + gatt_db_attribute_read_result(attrib, id, 0, pdu, sizeof(pdu)); > } > > -static void device_info_read_pnp_id_cb(uint16_t handle, uint16_t offset, > - uint8_t att_opcode, bdaddr_t *bdaddr, > +static void device_info_read_pnp_id_cb(struct gatt_db_attribute *attrib, > + unsigned int id, uint16_t offset, > + uint8_t opcode, bdaddr_t *bdaddr, > void *user_data) > { > - struct pending_request *entry; > struct gatt_device *dev; > + uint8_t pdu[7]; > > dev = find_device_by_addr(bdaddr); > if (!dev) { > @@ -6455,34 +6533,19 @@ static void device_info_read_pnp_id_cb(uint16_t handle, uint16_t offset, > return; > } > > - entry = queue_find(dev->pending_requests, match_dev_request_by_handle, > - UINT_TO_PTR(handle)); > - if (!entry) > - return; > - > - entry->value = malloc0(sizeof(uint8_t) + 3 * sizeof(uint16_t)); > - if (!entry->value) { > - entry->error = ATT_ECODE_UNLIKELY; > - goto done; > - } > - > - entry->length = sizeof(uint8_t) + 3 * sizeof(uint16_t); > - > - entry->value[0] = bt_config_get_pnp_source(); > - put_le16(bt_config_get_pnp_vendor(), entry->value + 1); > - put_le16(bt_config_get_pnp_product(), entry->value + 3); > - put_le16(bt_config_get_pnp_version(), entry->value + 5); > - > - entry->offset = offset; > + pdu[0] = bt_config_get_pnp_source(); > + put_le16(bt_config_get_pnp_vendor(), &pdu[1]); > + put_le16(bt_config_get_pnp_product(), &pdu[3]); > + put_le16(bt_config_get_pnp_version(), &pdu[5]); > > -done: > - entry->state = REQUEST_DONE; > + gatt_db_attribute_read_result(attrib, id, 0, pdu, sizeof(pdu)); > } > > static void register_device_info_service(void) > { > bt_uuid_t uuid; > - uint16_t srvc_handle, end_handle; > + struct gatt_db_attribute *service; > + uint16_t start_handle, end_handle; > const char *data; > uint32_t enc_perm = GATT_PERM_READ | GATT_PERM_READ_ENCRYPTED; > > @@ -6490,13 +6553,13 @@ static void register_device_info_service(void) > > /* Device Information Service */ > bt_uuid16_create(&uuid, 0x180a); > - srvc_handle = gatt_db_add_service(gatt_db, &uuid, true, 15); > + service = gatt_db_add_service(gatt_db, &uuid, true, 15); > > /* User data are not const hence (void *) cast is used */ > data = bt_config_get_name(); > if (data) { > bt_uuid16_create(&uuid, GATT_CHARAC_MODEL_NUMBER_STRING); > - gatt_db_add_characteristic(gatt_db, srvc_handle, &uuid, > + gatt_db_service_add_characteristic(service, &uuid, > GATT_PERM_READ, > GATT_CHR_PROP_READ, > device_info_read_cb, NULL, > @@ -6506,7 +6569,7 @@ static void register_device_info_service(void) > data = bt_config_get_serial(); > if (data) { > bt_uuid16_create(&uuid, GATT_CHARAC_SERIAL_NUMBER_STRING); > - gatt_db_add_characteristic(gatt_db, srvc_handle, &uuid, > + gatt_db_service_add_characteristic(service, &uuid, > enc_perm, GATT_CHR_PROP_READ, > device_info_read_cb, NULL, > (void *) data); > @@ -6514,7 +6577,7 @@ static void register_device_info_service(void) > > if (bt_config_get_system_id()) { > bt_uuid16_create(&uuid, GATT_CHARAC_SYSTEM_ID); > - gatt_db_add_characteristic(gatt_db, srvc_handle, &uuid, > + gatt_db_service_add_characteristic(service, &uuid, > enc_perm, GATT_CHR_PROP_READ, > device_info_read_system_id_cb, > NULL, NULL); > @@ -6523,7 +6586,7 @@ static void register_device_info_service(void) > data = bt_config_get_fw_rev(); > if (data) { > bt_uuid16_create(&uuid, GATT_CHARAC_FIRMWARE_REVISION_STRING); > - gatt_db_add_characteristic(gatt_db, srvc_handle, &uuid, > + gatt_db_service_add_characteristic(service, &uuid, > GATT_PERM_READ, > GATT_CHR_PROP_READ, > device_info_read_cb, NULL, > @@ -6533,7 +6596,7 @@ static void register_device_info_service(void) > data = bt_config_get_hw_rev(); > if (data) { > bt_uuid16_create(&uuid, GATT_CHARAC_HARDWARE_REVISION_STRING); > - gatt_db_add_characteristic(gatt_db, srvc_handle, &uuid, > + gatt_db_service_add_characteristic(service, &uuid, > GATT_PERM_READ, > GATT_CHR_PROP_READ, > device_info_read_cb, NULL, > @@ -6541,14 +6604,14 @@ static void register_device_info_service(void) > } > > bt_uuid16_create(&uuid, GATT_CHARAC_SOFTWARE_REVISION_STRING); > - gatt_db_add_characteristic(gatt_db, srvc_handle, &uuid, GATT_PERM_READ, > + gatt_db_service_add_characteristic(service, &uuid, GATT_PERM_READ, > GATT_CHR_PROP_READ, device_info_read_cb, > NULL, VERSION); > > data = bt_config_get_vendor(); > if (data) { > bt_uuid16_create(&uuid, GATT_CHARAC_MANUFACTURER_NAME_STRING); > - gatt_db_add_characteristic(gatt_db, srvc_handle, &uuid, > + gatt_db_service_add_characteristic(service, &uuid, > GATT_PERM_READ, > GATT_CHR_PROP_READ, > device_info_read_cb, NULL, > @@ -6557,31 +6620,31 @@ static void register_device_info_service(void) > > if (bt_config_get_pnp_source()) { > bt_uuid16_create(&uuid, GATT_CHARAC_PNP_ID); > - gatt_db_add_characteristic(gatt_db, srvc_handle, &uuid, > + gatt_db_service_add_characteristic(service, &uuid, > GATT_PERM_READ, > GATT_CHR_PROP_READ, > device_info_read_pnp_id_cb, > NULL, NULL); > } > > - gatt_db_service_set_active(gatt_db, srvc_handle, true); > + gatt_db_service_set_active(service, true); > > /* SDP */ > bt_uuid16_create(&uuid, 0x180a); > - end_handle = gatt_db_get_end_handle(gatt_db, srvc_handle); > - dis_sdp_handle = add_sdp_record(&uuid, srvc_handle, end_handle, > + gatt_db_attribute_get_service_handles(service, &start_handle, > + &end_handle); > + dis_sdp_handle = add_sdp_record(&uuid, start_handle, end_handle, > "Device Information Service"); > if (!dis_sdp_handle) > error("gatt: Failed to register DIS SDP record"); > } > > -static void gatt_srvc_change_write_cb(uint16_t handle, uint16_t offset, > - const uint8_t *val, size_t len, > - uint8_t att_opcode, > - bdaddr_t *bdaddr, > - void *user_data) > +static void gatt_srvc_change_write_cb(struct gatt_db_attribute *attrib, > + unsigned int id, uint16_t offset, > + const uint8_t *value, size_t len, > + uint8_t opcode, bdaddr_t *bdaddr, > + void *user_data) > { > - struct pending_request *entry; > struct gatt_device *dev; > > dev = find_device_by_addr(bdaddr); > @@ -6590,29 +6653,25 @@ static void gatt_srvc_change_write_cb(uint16_t handle, uint16_t offset, > return; > } > > - entry = queue_find(dev->pending_requests, match_dev_request_by_handle, > - UINT_TO_PTR(handle)); > - if (!entry) > - return; > - > - entry->state = REQUEST_DONE; > - > if (!bt_device_is_bonded(bdaddr)) { > - entry->error = ATT_ECODE_AUTHORIZATION; > + gatt_db_attribute_write_result(attrib, id, > + ATT_ECODE_AUTHORIZATION); > return; > } > > /* Set services changed indication value */ > - bt_store_gatt_ccc(bdaddr, *val); > + bt_store_gatt_ccc(bdaddr, *value); > + > + gatt_db_attribute_write_result(attrib, id, 0); > } > > -static void gatt_srvc_change_read_cb(uint16_t handle, uint16_t offset, > - uint8_t att_opcode, bdaddr_t *bdaddr, > +static void gatt_srvc_change_read_cb(struct gatt_db_attribute *attrib, > + unsigned int id, uint16_t offset, > + uint8_t opcode, bdaddr_t *bdaddr, > void *user_data) > { > - struct pending_request *entry; > struct gatt_device *dev; > - uint16_t ccc = 0; > + uint8_t pdu[2]; > > dev = find_device_by_addr(bdaddr); > if (!dev) { > @@ -6620,53 +6679,41 @@ static void gatt_srvc_change_read_cb(uint16_t handle, uint16_t offset, > return; > } > > - entry = queue_find(dev->pending_requests, match_dev_request_by_handle, > - UINT_TO_PTR(handle)); > - if (!entry) > - return; > - > - ccc = bt_get_gatt_ccc(&dev->bdaddr); > - entry->state = REQUEST_DONE; > - > - entry->value = new0(uint8_t, 2); > - if (!entry->value) { > - entry->error = ATT_ECODE_INSUFF_RESOURCES; > - > - return; > - } > + put_le16(bt_get_gatt_ccc(&dev->bdaddr), pdu); > > - entry->length = sizeof(uint16_t); > - memcpy(entry->value, &ccc, sizeof(ccc)); > + gatt_db_attribute_read_result(attrib, id, 0, pdu, sizeof(pdu)); > } > > static void register_gatt_service(void) > { > - uint16_t srvc_handle, end_handle; > + struct gatt_db_attribute *service; > + uint16_t start_handle, end_handle; > bt_uuid_t uuid; > > DBG(""); > > bt_uuid16_create(&uuid, 0x1801); > - srvc_handle = gatt_db_add_service(gatt_db, &uuid, true, 4); > + service = gatt_db_add_service(gatt_db, &uuid, true, 4); > > bt_uuid16_create(&uuid, GATT_CHARAC_SERVICE_CHANGED); > - service_changed_handle = gatt_db_add_characteristic(gatt_db, > - srvc_handle, &uuid, GATT_PERM_NONE, > - GATT_CHR_PROP_INDICATE, NULL, NULL, > - NULL); > + service_changed_attrib = gatt_db_service_add_characteristic(service, > + &uuid, GATT_PERM_NONE, > + GATT_CHR_PROP_INDICATE, > + NULL, NULL, NULL); > > bt_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID); > - gatt_db_add_char_descriptor(gatt_db, srvc_handle, &uuid, > + gatt_db_service_add_descriptor(service, &uuid, > GATT_PERM_READ | GATT_PERM_WRITE, > gatt_srvc_change_read_cb, > gatt_srvc_change_write_cb, NULL); > > - gatt_db_service_set_active(gatt_db, srvc_handle, true); > + gatt_db_service_set_active(service, true); > > /* SDP */ > bt_uuid16_create(&uuid, 0x1801); > - end_handle = gatt_db_get_end_handle(gatt_db, srvc_handle); > - gatt_sdp_handle = add_sdp_record(&uuid, srvc_handle, end_handle, > + gatt_db_attribute_get_service_handles(service, &start_handle, > + &end_handle); > + gatt_sdp_handle = add_sdp_record(&uuid, start_handle, end_handle, > "Generic Attribute Profile"); > > if (!gatt_sdp_handle) > diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c > index 5855f5d..bab1202 100644 > --- a/src/shared/gatt-db.c > +++ b/src/shared/gatt-db.c > @@ -45,6 +45,18 @@ struct gatt_db { > struct queue *services; > }; > > +struct pending_read { > + unsigned int id; > + gatt_db_attribute_read_t func; > + void *user_data; > +}; > + > +struct pending_write { > + unsigned int id; > + gatt_db_attribute_write_t func; > + void *user_data; > +}; > + > struct gatt_db_attribute { > struct gatt_db_service *service; > uint16_t handle; > @@ -56,6 +68,12 @@ struct gatt_db_attribute { > gatt_db_read_t read_func; > gatt_db_write_t write_func; > void *user_data; > + > + unsigned int read_id; > + struct queue *pending_reads; > + > + unsigned int write_id; > + struct queue *pending_writes; > }; > > struct gatt_db_service { > @@ -64,11 +82,17 @@ struct gatt_db_service { > struct gatt_db_attribute **attributes; > }; > > -static bool match_service_by_handle(const void *data, const void *user_data) > +static void attribute_destroy(struct gatt_db_attribute *attribute) > { > - const struct gatt_db_service *service = data; > + /* Attribute was not initialized by user */ > + if (!attribute) > + return; > + > + queue_destroy(attribute->pending_reads, free); > + queue_destroy(attribute->pending_writes, free); > > - return service->attributes[0]->handle == PTR_TO_UINT(user_data); > + free(attribute->value); > + free(attribute); > } > > static struct gatt_db_attribute *new_attribute(struct gatt_db_service *service, > @@ -87,25 +111,25 @@ static struct gatt_db_attribute *new_attribute(struct gatt_db_service *service, > attribute->value_len = len; > if (len) { > attribute->value = malloc0(len); > - if (!attribute->value) { > - free(attribute); > - return NULL; > - } > + if (!attribute->value) > + goto failed; > > memcpy(attribute->value, val, len); > } > > - return attribute; > -} > + attribute->pending_reads = queue_new(); > + if (!attribute->pending_reads) > + goto failed; > > -static void attribute_destroy(struct gatt_db_attribute *attribute) > -{ > - /* Attribute was not initialized by user */ > - if (!attribute) > - return; > + attribute->pending_writes = queue_new(); > + if (!attribute->pending_reads) > + goto failed; > > - free(attribute->value); > - free(attribute); > + return attribute; > + > +failed: > + attribute_destroy(attribute); > + return NULL; > } > > struct gatt_db *gatt_db_new(void) > @@ -162,8 +186,10 @@ static int uuid_to_le(const bt_uuid_t *uuid, uint8_t *dst) > return bt_uuid_len(&uuid128); > } > > -uint16_t gatt_db_add_service(struct gatt_db *db, const bt_uuid_t *uuid, > - bool primary, uint16_t num_handles) > +struct gatt_db_attribute *gatt_db_add_service(struct gatt_db *db, > + const bt_uuid_t *uuid, > + bool primary, > + uint16_t num_handles) > { > struct gatt_db_service *service; > const bt_uuid_t *type; > @@ -209,18 +235,21 @@ uint16_t gatt_db_add_service(struct gatt_db *db, const bt_uuid_t *uuid, > db->next_handle += num_handles; > service->num_handles = num_handles; > > - return service->attributes[0]->handle; > + return service->attributes[0]; > } > > -bool gatt_db_remove_service(struct gatt_db *db, uint16_t handle) > +bool gatt_db_remove_service(struct gatt_db *db, > + struct gatt_db_attribute *attrib) > { > struct gatt_db_service *service; > > - service = queue_remove_if(db->services, match_service_by_handle, > - UINT_TO_PTR(handle)); > - if (!service) > + if (!db || !attrib) > return false; > > + service = attrib->service; > + > + queue_remove(db->services, service); > + > gatt_db_service_destroy(service); > > return true; > @@ -245,8 +274,8 @@ static uint16_t get_handle_at_index(struct gatt_db_service *service, > return service->attributes[index]->handle; > } > > -static uint16_t update_attribute_handle(struct gatt_db_service *service, > - int index) > +static struct gatt_db_attribute * > +attribute_update(struct gatt_db_service *service, int index) > { > uint16_t previous_handle; > > @@ -256,7 +285,7 @@ static uint16_t update_attribute_handle(struct gatt_db_service *service, > previous_handle = service->attributes[index - 1]->handle; > service->attributes[index]->handle = previous_handle + 1; > > - return service->attributes[index]->handle; > + return service->attributes[index]; > } > > static void set_attribute_data(struct gatt_db_attribute *attribute, > @@ -271,27 +300,28 @@ static void set_attribute_data(struct gatt_db_attribute *attribute, > attribute->user_data = user_data; > } > > -uint16_t gatt_db_add_characteristic(struct gatt_db *db, uint16_t handle, > - const bt_uuid_t *uuid, > - uint32_t permissions, > - uint8_t properties, > - gatt_db_read_t read_func, > - gatt_db_write_t write_func, > - void *user_data) > +struct gatt_db_attribute * > +gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib, > + const bt_uuid_t *uuid, > + uint32_t permissions, > + uint8_t properties, > + gatt_db_read_t read_func, > + gatt_db_write_t write_func, > + void *user_data) > { > - uint8_t value[MAX_CHAR_DECL_VALUE_LEN]; > struct gatt_db_service *service; > + uint8_t value[MAX_CHAR_DECL_VALUE_LEN]; > uint16_t len = 0; > int i; > > - service = queue_find(db->services, match_service_by_handle, > - UINT_TO_PTR(handle)); > - if (!service) > - return 0; > + if (!attrib) > + return NULL; > + > + service = attrib->service; > > i = get_attribute_index(service, 1); > if (!i) > - return 0; > + return NULL; > > value[0] = properties; > len += sizeof(properties); > @@ -303,96 +333,96 @@ uint16_t gatt_db_add_characteristic(struct gatt_db *db, uint16_t handle, > service->attributes[i] = new_attribute(service, &characteristic_uuid, > value, len); > if (!service->attributes[i]) > - return 0; > + return NULL; > > - update_attribute_handle(service, i++); > + attribute_update(service, i++); > > service->attributes[i] = new_attribute(service, uuid, NULL, 0); > if (!service->attributes[i]) { > free(service->attributes[i - 1]); > - return 0; > + return NULL; > } > > set_attribute_data(service->attributes[i], read_func, write_func, > permissions, user_data); > > - return update_attribute_handle(service, i); > + return attribute_update(service, i); > } > > -uint16_t gatt_db_add_char_descriptor(struct gatt_db *db, uint16_t handle, > - const bt_uuid_t *uuid, > - uint32_t permissions, > - gatt_db_read_t read_func, > - gatt_db_write_t write_func, > - void *user_data) > +struct gatt_db_attribute * > +gatt_db_service_add_descriptor(struct gatt_db_attribute *attrib, > + const bt_uuid_t *uuid, > + uint32_t permissions, > + gatt_db_read_t read_func, > + gatt_db_write_t write_func, > + void *user_data) > { > struct gatt_db_service *service; > int i; > > - service = queue_find(db->services, match_service_by_handle, > - UINT_TO_PTR(handle)); > - if (!service) > - return 0; > + if (!attrib) > + return false; > + > + service = attrib->service; > > i = get_attribute_index(service, 0); > if (!i) > - return 0; > + return NULL; > > service->attributes[i] = new_attribute(service, uuid, NULL, 0); > if (!service->attributes[i]) > - return 0; > + return NULL; > > set_attribute_data(service->attributes[i], read_func, write_func, > permissions, user_data); > > - return update_attribute_handle(service, i); > + return attribute_update(service, i); > } > > -uint16_t gatt_db_add_included_service(struct gatt_db *db, uint16_t handle, > - uint16_t included_handle) > +struct gatt_db_attribute * > +gatt_db_service_add_included(struct gatt_db_attribute *attrib, > + struct gatt_db_attribute *include) > { > - struct gatt_db_service *included_service; > + struct gatt_db_service *service, *included; > uint8_t value[MAX_INCLUDED_VALUE_LEN]; > - uint16_t len = 0; > - struct gatt_db_service *service; > + uint16_t included_handle, len = 0; > int index; > > - service = queue_find(db->services, match_service_by_handle, > - UINT_TO_PTR(handle)); > - if (!service) > - return 0; > + if (!attrib || !include) > + return NULL; > > - included_service = queue_find(db->services, match_service_by_handle, > - UINT_TO_PTR(included_handle)); > + service = attrib->service; > + included = include->service; > > - if (!included_service) > - return 0; > + /* Adjust include to point to the first attribute */ > + if (include != included->attributes[0]) > + include = included->attributes[0]; > + > + included_handle = include->handle; > > put_le16(included_handle, &value[len]); > len += sizeof(uint16_t); > > - put_le16(included_handle + included_service->num_handles - 1, > - &value[len]); > + put_le16(included_handle + included->num_handles - 1, &value[len]); > len += sizeof(uint16_t); > > /* The Service UUID shall only be present when the UUID is a 16-bit > * Bluetooth UUID. Vol 2. Part G. 3.2 > */ > - if (included_service->attributes[0]->value_len == sizeof(uint16_t)) { > - memcpy(&value[len], included_service->attributes[0]->value, > - included_service->attributes[0]->value_len); > - len += included_service->attributes[0]->value_len; > + if (include->value_len == sizeof(uint16_t)) { > + memcpy(&value[len], include->value, include->value_len); > + len += include->value_len; > } > > index = get_attribute_index(service, 0); > if (!index) > - return 0; > + return NULL; > > service->attributes[index] = new_attribute(service, > &included_service_uuid, > value, len); > if (!service->attributes[index]) > - return 0; > + return NULL; > > /* The Attribute Permissions shall be read only and not require > * authentication or authorization. Vol 2. Part G. 3.2 > @@ -401,20 +431,15 @@ uint16_t gatt_db_add_included_service(struct gatt_db *db, uint16_t handle, > */ > set_attribute_data(service->attributes[index], NULL, NULL, 0, NULL); > > - return update_attribute_handle(service, index); > + return attribute_update(service, index); > } > > -bool gatt_db_service_set_active(struct gatt_db *db, uint16_t handle, > - bool active) > +bool gatt_db_service_set_active(struct gatt_db_attribute *attrib, bool active) > { > - struct gatt_db_service *service; > - > - service = queue_find(db->services, match_service_by_handle, > - UINT_TO_PTR(handle)); > - if (!service) > + if (!attrib) > return false; > > - service->active = active; > + attrib->service->active = active; > > return true; > } > @@ -465,8 +490,7 @@ static void read_by_group_type(void *data, void *user_data) > return; > } > > - queue_push_tail(search_data->queue, > - UINT_TO_PTR(service->attributes[0]->handle)); > + queue_push_tail(search_data->queue, service->attributes[0]); > } > > void gatt_db_read_by_group_type(struct gatt_db *db, uint16_t start_handle, > @@ -516,8 +540,7 @@ static void find_by_type(void *data, void *user_data) > if (bt_uuid_cmp(&search_data->uuid, &attribute->uuid)) > continue; > > - queue_push_tail(search_data->queue, > - UINT_TO_PTR(attribute->handle)); > + queue_push_tail(search_data->queue, attribute); > } > } > > @@ -567,8 +590,7 @@ static void read_by_type(void *data, void *user_data) > if (bt_uuid_cmp(&search_data->uuid, &attribute->uuid)) > continue; > > - queue_push_tail(search_data->queue, > - UINT_TO_PTR(attribute->handle)); > + queue_push_tail(search_data->queue, attribute); > } > } > > @@ -619,8 +641,7 @@ static void find_information(void *data, void *user_data) > if (attribute->handle > search_data->end_handle) > return; > > - queue_push_tail(search_data->queue, > - UINT_TO_PTR(attribute->handle)); > + queue_push_tail(search_data->queue, attribute); > } > } > > @@ -649,164 +670,6 @@ static bool find_service_for_handle(const void *data, const void *user_data) > return (start <= handle) && (handle < end); > } > > -bool gatt_db_read(struct gatt_db *db, uint16_t handle, uint16_t offset, > - uint8_t att_opcode, bdaddr_t *bdaddr, > - uint8_t **value, int *length) > -{ > - struct gatt_db_service *service; > - uint16_t service_handle; > - struct gatt_db_attribute *a; > - > - if (!value || !length) > - return false; > - > - service = queue_find(db->services, find_service_for_handle, > - UINT_TO_PTR(handle)); > - if (!service) > - return false; > - > - service_handle = service->attributes[0]->handle; > - > - a = service->attributes[handle - service_handle]; > - if (!a) > - return false; > - > - /* > - * We call callback, and set length to -1, to notify user that callback > - * has been called. Otherwise we set length to value length in database. > - */ > - if (a->read_func) { > - *value = NULL; > - *length = -1; > - a->read_func(handle, offset, att_opcode, bdaddr, a->user_data); > - } else { > - if (offset > a->value_len) > - return false; > - > - *value = &a->value[offset]; > - *length = a->value_len - offset; > - } > - > - return true; > -} > - > -bool gatt_db_write(struct gatt_db *db, uint16_t handle, uint16_t offset, > - const uint8_t *value, size_t len, > - uint8_t att_opcode, bdaddr_t *bdaddr) > -{ > - struct gatt_db_service *service; > - uint16_t service_handle; > - struct gatt_db_attribute *a; > - > - service = queue_find(db->services, find_service_for_handle, > - UINT_TO_PTR(handle)); > - if (!service) > - return false; > - > - service_handle = service->attributes[0]->handle; > - > - a = service->attributes[handle - service_handle]; > - if (!a || !a->write_func) > - return false; > - > - a->write_func(handle, offset, value, len, att_opcode, bdaddr, > - a->user_data); > - > - return true; > -} > - > -const bt_uuid_t *gatt_db_get_attribute_type(struct gatt_db *db, > - uint16_t handle) > -{ > - struct gatt_db_service *service; > - struct gatt_db_attribute *attribute; > - uint16_t service_handle; > - > - service = queue_find(db->services, find_service_for_handle, > - UINT_TO_PTR(handle)); > - if (!service) > - return NULL; > - > - service_handle = service->attributes[0]->handle; > - > - attribute = service->attributes[handle - service_handle]; > - if (!attribute) > - return NULL; > - > - return &attribute->uuid; > -} > - > -uint16_t gatt_db_get_end_handle(struct gatt_db *db, uint16_t handle) > -{ > - struct gatt_db_service *service; > - > - service = queue_find(db->services, find_service_for_handle, > - UINT_TO_PTR(handle)); > - if (!service) > - return 0; > - > - return service->attributes[0]->handle + service->num_handles - 1; > -} > - > -bool gatt_db_get_service_uuid(struct gatt_db *db, uint16_t handle, > - bt_uuid_t *uuid) > -{ > - struct gatt_db_service *service; > - > - service = queue_find(db->services, find_service_for_handle, > - UINT_TO_PTR(handle)); > - if (!service) > - return false; > - > - if (service->attributes[0]->value_len == 2) { > - uint16_t value; > - > - value = get_le16(service->attributes[0]->value); > - bt_uuid16_create(uuid, value); > - > - return true; > - } > - > - if (service->attributes[0]->value_len == 16) { > - uint128_t value; > - > - bswap_128(service->attributes[0]->value, &value); > - bt_uuid128_create(uuid, value); > - > - return true; > - } > - > - return false; > -} > - > -bool gatt_db_get_attribute_permissions(struct gatt_db *db, uint16_t handle, > - uint32_t *permissions) > -{ > - struct gatt_db_attribute *attribute; > - struct gatt_db_service *service; > - uint16_t service_handle; > - > - service = queue_find(db->services, find_service_for_handle, > - UINT_TO_PTR(handle)); > - if (!service) > - return false; > - > - service_handle = service->attributes[0]->handle; > - > - /* > - * We can safely get attribute from attributes array with offset, > - * because find_service_for_handle() check if given handle is > - * in service range. > - */ > - attribute = service->attributes[handle - service_handle]; > - if (!attribute) > - return false; > - > - *permissions = attribute->permissions; > - return true; > - > -} > - > struct gatt_db_attribute *gatt_db_get_attribute(struct gatt_db *db, > uint16_t handle) > { > @@ -920,8 +783,19 @@ bool gatt_db_attribute_read(struct gatt_db_attribute *attrib, uint16_t offset, > return false; > > if (attrib->read_func) { > - /* TODO: Pass callback function to read_func */ > - attrib->read_func(attrib->handle, offset, opcode, bdaddr, > + struct pending_read *p; > + > + p = new0(struct pending_read, 1); > + if (!p) > + return false; > + > + p->id = ++attrib->read_id; > + p->func = func; > + p->user_data = user_data; > + > + queue_push_tail(attrib->pending_reads, p); > + > + attrib->read_func(attrib, p->id, offset, opcode, bdaddr, > attrib->user_data); > return true; > } > @@ -938,6 +812,35 @@ bool gatt_db_attribute_read(struct gatt_db_attribute *attrib, uint16_t offset, > return true; > } > > +static bool find_pending(const void *a, const void *b) > +{ > + const struct pending_read *p = a; > + unsigned int id = PTR_TO_UINT(b); > + > + return p->id == id; > +} > + > +bool gatt_db_attribute_read_result(struct gatt_db_attribute *attrib, > + unsigned int id, int err, > + const uint8_t *value, size_t length) > +{ > + struct pending_read *p; > + > + if (!attrib || !id) > + return false; > + > + p = queue_remove_if(attrib->pending_reads, find_pending, > + UINT_TO_PTR(id)); > + if (!p) > + return false; > + > + p->func(attrib, err, value, length, p->user_data); > + > + free(p); > + > + return true; > +} > + > bool gatt_db_attribute_write(struct gatt_db_attribute *attrib, uint16_t offset, > const uint8_t *value, size_t len, > uint8_t opcode, bdaddr_t *bdaddr, > @@ -948,7 +851,19 @@ bool gatt_db_attribute_write(struct gatt_db_attribute *attrib, uint16_t offset, > return false; > > if (attrib->write_func) { > - attrib->write_func(attrib->handle, offset, value, len, opcode, > + struct pending_write *p; > + > + p = new0(struct pending_write, 1); > + if (!p) > + return false; > + > + p->id = ++attrib->write_id; > + p->func = func; > + p->user_data = user_data; > + > + queue_push_tail(attrib->pending_writes, p); > + > + attrib->write_func(attrib, p->id, offset, value, len, opcode, > bdaddr, attrib->user_data); > return true; > } > @@ -971,3 +886,23 @@ bool gatt_db_attribute_write(struct gatt_db_attribute *attrib, uint16_t offset, > > return true; > } > + > +bool gatt_db_attribute_write_result(struct gatt_db_attribute *attrib, > + unsigned int id, int err) > +{ > + struct pending_write *p; > + > + if (!attrib || !id) > + return false; > + > + p = queue_remove_if(attrib->pending_writes, find_pending, > + UINT_TO_PTR(id)); > + if (!p) > + return false; > + > + p->func(attrib, err, p->user_data); > + > + free(p); > + > + return true; > +} > diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h > index 15be67f..9c71814 100644 > --- a/src/shared/gatt-db.h > +++ b/src/shared/gatt-db.h > @@ -22,43 +22,52 @@ > */ > > struct gatt_db; > +struct gatt_db_attribute; > > struct gatt_db *gatt_db_new(void); > void gatt_db_destroy(struct gatt_db *db); > > -uint16_t gatt_db_add_service(struct gatt_db *db, const bt_uuid_t *uuid, > - bool primary, uint16_t num_handles); > -bool gatt_db_remove_service(struct gatt_db *db, uint16_t handle); > +struct gatt_db_attribute *gatt_db_add_service(struct gatt_db *db, > + const bt_uuid_t *uuid, > + bool primary, > + uint16_t num_handles); > + > +bool gatt_db_remove_service(struct gatt_db *db, > + struct gatt_db_attribute *attrib); > > -typedef void (*gatt_db_read_t) (uint16_t handle, uint16_t offset, > - uint8_t att_opcode, bdaddr_t *bdaddr, > +typedef void (*gatt_db_read_t) (struct gatt_db_attribute *attrib, > + unsigned int id, uint16_t offset, > + uint8_t opcode, bdaddr_t *bdaddr, > void *user_data); > > -typedef void (*gatt_db_write_t) (uint16_t handle, uint16_t offset, > +typedef void (*gatt_db_write_t) (struct gatt_db_attribute *attrib, > + unsigned int id, uint16_t offset, > const uint8_t *value, size_t len, > - uint8_t att_opcode, bdaddr_t *bdaddr, > + uint8_t opcode, bdaddr_t *bdaddr, > void *user_data); > > -uint16_t gatt_db_add_characteristic(struct gatt_db *db, uint16_t handle, > - const bt_uuid_t *uuid, > - uint32_t permissions, > - uint8_t properties, > - gatt_db_read_t read_func, > - gatt_db_write_t write_func, > - void *user_data); > +struct gatt_db_attribute * > +gatt_db_service_add_characteristic(struct gatt_db_attribute *attrib, > + const bt_uuid_t *uuid, > + uint32_t permissions, > + uint8_t properties, > + gatt_db_read_t read_func, > + gatt_db_write_t write_func, > + void *user_data); > > -uint16_t gatt_db_add_char_descriptor(struct gatt_db *db, uint16_t handle, > - const bt_uuid_t *uuid, > - uint32_t permissions, > - gatt_db_read_t read_func, > - gatt_db_write_t write_func, > - void *user_data); > +struct gatt_db_attribute * > +gatt_db_service_add_descriptor(struct gatt_db_attribute *attrib, > + const bt_uuid_t *uuid, > + uint32_t permissions, > + gatt_db_read_t read_func, > + gatt_db_write_t write_func, > + void *user_data); > > -uint16_t gatt_db_add_included_service(struct gatt_db *db, uint16_t handle, > - uint16_t included_handle); > +struct gatt_db_attribute * > +gatt_db_service_add_included(struct gatt_db_attribute *attrib, > + struct gatt_db_attribute *include); > > -bool gatt_db_service_set_active(struct gatt_db *db, uint16_t handle, > - bool active); > +bool gatt_db_service_set_active(struct gatt_db_attribute *attrib, bool active); > > void gatt_db_read_by_group_type(struct gatt_db *db, uint16_t start_handle, > uint16_t end_handle, > @@ -79,25 +88,6 @@ void gatt_db_find_information(struct gatt_db *db, uint16_t start_handle, > uint16_t end_handle, > struct queue *queue); > > -bool gatt_db_read(struct gatt_db *db, uint16_t handle, uint16_t offset, > - uint8_t att_opcode, bdaddr_t *bdaddr, > - uint8_t **value, int *length); > - > -bool gatt_db_write(struct gatt_db *db, uint16_t handle, uint16_t offset, > - const uint8_t *value, size_t len, > - uint8_t att_opcode, bdaddr_t *bdaddr); > - > -const bt_uuid_t *gatt_db_get_attribute_type(struct gatt_db *db, > - uint16_t handle); > - > -uint16_t gatt_db_get_end_handle(struct gatt_db *db, uint16_t handle); > -bool gatt_db_get_service_uuid(struct gatt_db *db, uint16_t handle, > - bt_uuid_t *uuid); > - > -bool gatt_db_get_attribute_permissions(struct gatt_db *db, uint16_t handle, > - uint32_t *permissions); > - > -struct gatt_db_attribute; > > struct gatt_db_attribute *gatt_db_get_attribute(struct gatt_db *db, > uint16_t handle); > @@ -117,13 +107,17 @@ bool gatt_db_attribute_get_permissions(struct gatt_db_attribute *attrib, > uint32_t *permissions); > > typedef void (*gatt_db_attribute_read_t) (struct gatt_db_attribute *attrib, > - int err, uint8_t *value, size_t length, > - void *user_data); > + int err, const uint8_t *value, > + size_t length, void *user_data); > > bool gatt_db_attribute_read(struct gatt_db_attribute *attrib, uint16_t offset, > uint8_t opcode, bdaddr_t *bdaddr, > gatt_db_attribute_read_t func, void *user_data); > > +bool gatt_db_attribute_read_result(struct gatt_db_attribute *attrib, > + unsigned int id, int err, > + const uint8_t *value, size_t length); > + > typedef void (*gatt_db_attribute_write_t) (struct gatt_db_attribute *attrib, > int err, void *user_data); > > @@ -132,3 +126,6 @@ bool gatt_db_attribute_write(struct gatt_db_attribute *attrib, uint16_t offset, > uint8_t opcode, bdaddr_t *bdaddr, > gatt_db_attribute_write_t func, > void *user_data); > + > +bool gatt_db_attribute_write_result(struct gatt_db_attribute *attrib, > + unsigned int id, int err); > diff --git a/src/shared/gatt-server.c b/src/shared/gatt-server.c > index 657b564..18f82c4 100644 > --- a/src/shared/gatt-server.c > +++ b/src/shared/gatt-server.c > @@ -21,6 +21,8 @@ > * > */ > > +#include > + > #include "src/shared/att.h" > #include "lib/uuid.h" > #include "src/shared/queue.h" > @@ -91,31 +93,41 @@ static bool get_uuid_le(const uint8_t *uuid, size_t len, bt_uuid_t *out_uuid) > return false; > } > > +static void attribute_read_cb(struct gatt_db_attribute *attrib, int err, > + const uint8_t *value, size_t length, > + void *user_data) > +{ > + struct iovec *iov = user_data; > + > + iov->iov_base = (void *) value; > + iov->iov_len = length; > +} > + > static bool encode_read_by_grp_type_rsp(struct gatt_db *db, struct queue *q, > uint16_t mtu, > uint8_t *pdu, uint16_t *len) > { > int iter = 0; > uint16_t start_handle, end_handle; > - uint8_t *value; > - int value_len; > + struct iovec value; > uint8_t data_val_len; > > *len = 0; > > while (queue_peek_head(q)) { > - start_handle = PTR_TO_UINT(queue_pop_head(q)); > - value = NULL; > - value_len = 0; > + struct gatt_db_attribute *attrib = queue_pop_head(q); > + > + value.iov_base = NULL; > + value.iov_len = 0; > > /* > * This should never be deferred to the read callback for > * primary/secondary service declarations. > */ > - if (!gatt_db_read(db, start_handle, 0, > + if (!gatt_db_attribute_read(attrib, 0, > BT_ATT_OP_READ_BY_GRP_TYPE_REQ, > - NULL, &value, > - &value_len) || value_len < 0) > + NULL, attribute_read_cb, > + &value) || !value.iov_len) > return false; > > /* > @@ -124,21 +136,22 @@ static bool encode_read_by_grp_type_rsp(struct gatt_db *db, struct queue *q, > * value is seen. > */ > if (iter == 0) { > - data_val_len = value_len; > + data_val_len = value.iov_len; > pdu[0] = data_val_len + 4; > iter++; > - } else if (value_len != data_val_len) > + } else if (value.iov_len != data_val_len) > break; > > /* Stop if this unit would surpass the MTU */ > if (iter + data_val_len + 4 > mtu) > break; > > - end_handle = gatt_db_get_end_handle(db, start_handle); > + gatt_db_attribute_get_service_handles(attrib, &start_handle, > + &end_handle); > > put_le16(start_handle, pdu + iter); > put_le16(end_handle, pdu + iter + 2); > - memcpy(pdu + iter + 4, value, value_len); > + memcpy(pdu + iter + 4, value.iov_base, value.iov_len); > > iter += data_val_len + 4; > } > -- > 1.9.3 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html This one looks good to me. I'll start rebasing on top of this. Cheers, Arman