static void read_complete_cb(struct gatt_db_attribute *attr, int err, const uint8_t *value, size_t len, void *user_data) { struct async_read_op *op = user_data; struct bt_gatt_server *server = op->server; uint8_t rsp_opcode; uint16_t mtu; uint16_t handle; if (!server) { async_read_op_destroy(op); return; } mtu = bt_att_get_mtu(server->att); handle = gatt_db_attribute_get_handle(attr); if (err) { bt_att_send_error_rsp(server->att, op->opcode, handle, err); async_read_op_destroy(op); return; } rsp_opcode = get_read_rsp_opcode(op->opcode); bt_att_send(server->att, rsp_opcode, len ? value : NULL, MIN((unsigned) mtu - 1, len), NULL, NULL, NULL); async_read_op_destroy(op); }
static void process_read_by_type(struct async_read_op *op) { struct bt_gatt_server *server = op->server; uint8_t ecode; struct gatt_db_attribute *attr; attr = queue_pop_head(op->db_data); if (op->done || !attr) { bt_att_send(server->att, BT_ATT_OP_READ_BY_TYPE_RSP, op->pdu, op->pdu_len, NULL, NULL, NULL); async_read_op_destroy(op); return; } ecode = check_permissions(server, attr, BT_ATT_PERM_READ | BT_ATT_PERM_READ_AUTHEN | BT_ATT_PERM_READ_ENCRYPT); if (ecode) goto error; if (gatt_db_attribute_read(attr, 0, op->opcode, server->att, read_by_type_read_complete_cb, op)) return; ecode = BT_ATT_ERROR_UNLIKELY; error: bt_att_send_error_rsp(server->att, BT_ATT_OP_READ_BY_TYPE_REQ, gatt_db_attribute_get_handle(attr), ecode); async_read_op_destroy(op); }
static void read_by_type_read_complete_cb(struct gatt_db_attribute *attr, int err, const uint8_t *value, size_t len, void *user_data) { struct async_read_op *op = user_data; struct bt_gatt_server *server = op->server; uint16_t mtu; uint16_t handle; if (!server) { async_read_op_destroy(op); return; } mtu = bt_att_get_mtu(server->att); handle = gatt_db_attribute_get_handle(attr); /* Terminate the operation if there was an error */ if (err) { bt_att_send_error_rsp(server->att, BT_ATT_OP_READ_BY_TYPE_REQ, handle, err); async_read_op_destroy(op); return; } if (op->pdu_len == 0) { op->value_len = MIN(MIN((unsigned) mtu - 4, 253), len); op->pdu[0] = op->value_len + 2; op->pdu_len++; } else if (len != op->value_len) { op->done = true; goto done; } /* Stop if this would surpass the MTU */ if (op->pdu_len + op->value_len + 2 > (unsigned) mtu - 1) { op->done = true; goto done; } /* Encode the current value */ put_le16(handle, op->pdu + op->pdu_len); memcpy(op->pdu + op->pdu_len + 2, value, op->value_len); op->pdu_len += op->value_len + 2; if (op->pdu_len == (unsigned) mtu - 1) op->done = true; done: process_read_by_type(op); }
static void process_read_by_type(struct async_read_op *op) { struct bt_gatt_server *server = op->server; uint8_t ecode; struct gatt_db_attribute *attr; uint32_t perm; attr = queue_pop_head(op->db_data); if (op->done || !attr) { bt_att_send(server->att, BT_ATT_OP_READ_BY_TYPE_RSP, op->pdu, op->pdu_len, NULL, NULL, NULL); async_read_op_destroy(op); return; } perm = gatt_db_attribute_get_permissions(attr); /* * Check for the READ access permission. Encryption, * authentication, and authorization permissions need to be * checked by the read handler, since bt_att is agnostic to * connection type and doesn't have security information on it. */ if (perm && !(perm & BT_ATT_PERM_READ)) { ecode = BT_ATT_ERROR_READ_NOT_PERMITTED; goto error; } if (gatt_db_attribute_read(attr, 0, op->opcode, server->att, read_by_type_read_complete_cb, op)) return; ecode = BT_ATT_ERROR_UNLIKELY; error: bt_att_send_error_rsp(server->att, BT_ATT_OP_READ_BY_TYPE_REQ, gatt_db_attribute_get_handle(attr), ecode); async_read_op_destroy(op); }
static void handle_read_req(struct bt_gatt_server *server, uint8_t opcode, uint16_t handle, uint16_t offset) { struct gatt_db_attribute *attr; uint8_t ecode; uint32_t perm; struct async_read_op *op = NULL; attr = gatt_db_get_attribute(server->db, handle); if (!attr) { ecode = BT_ATT_ERROR_INVALID_HANDLE; goto error; } util_debug(server->debug_callback, server->debug_data, "Read %sReq - handle: 0x%04x", opcode == BT_ATT_OP_READ_BLOB_REQ ? "Blob " : "", handle); perm = gatt_db_attribute_get_permissions(attr); if (perm && !(perm & BT_ATT_PERM_READ)) { ecode = BT_ATT_ERROR_READ_NOT_PERMITTED; goto error; } if (server->pending_read_op) { ecode = BT_ATT_ERROR_UNLIKELY; goto error; } op = new0(struct async_read_op, 1); if (!op) { ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES; goto error; } op->opcode = opcode; op->server = server; server->pending_read_op = op; if (gatt_db_attribute_read(attr, offset, opcode, server->att, read_complete_cb, op)) return; ecode = BT_ATT_ERROR_UNLIKELY; error: if (op) async_read_op_destroy(op); bt_att_send_error_rsp(server->att, opcode, handle, ecode); }
static void handle_read_req(struct bt_gatt_server *server, uint8_t opcode, uint16_t handle, uint16_t offset) { struct gatt_db_attribute *attr; uint8_t ecode; struct async_read_op *op = NULL; ecode = authorize_req(server, opcode, handle); if (ecode) goto error; attr = gatt_db_get_attribute(server->db, handle); if (!attr) { ecode = BT_ATT_ERROR_INVALID_HANDLE; goto error; } util_debug(server->debug_callback, server->debug_data, "Read %sReq - handle: 0x%04x", opcode == BT_ATT_OP_READ_BLOB_REQ ? "Blob " : "", handle); ecode = check_permissions(server, attr, BT_ATT_PERM_READ | BT_ATT_PERM_READ_AUTHEN | BT_ATT_PERM_READ_ENCRYPT); if (ecode) goto error; if (server->pending_read_op) { ecode = BT_ATT_ERROR_UNLIKELY; goto error; } op = new0(struct async_read_op, 1); op->opcode = opcode; op->server = server; server->pending_read_op = op; if (gatt_db_attribute_read(attr, offset, opcode, server->att, read_complete_cb, op)) return; ecode = BT_ATT_ERROR_UNLIKELY; error: if (op) async_read_op_destroy(op); bt_att_send_error_rsp(server->att, opcode, handle, ecode); }