Bluetooth: OTS - Add Calculate Checksum support
OTS add Calculate checksum feature support. OTS client add object calculate checksum function. Signed-off-by: Pirun Lee <pirun.lee@nordicsemi.no>
This commit is contained in:
parent
4858f8d667
commit
1e6f36cca7
5 changed files with 285 additions and 17 deletions
|
@ -41,6 +41,9 @@ config BT_OTS_OACP_CREATE_SUPPORT
|
|||
depends on BT_OTS_OACP_WRITE_SUPPORT
|
||||
depends on BT_OTS_OBJ_NAME_WRITE_SUPPORT
|
||||
|
||||
config BT_OTS_OACP_CHECKSUM_SUPPORT
|
||||
bool "Support OACP Calculate Checksum operation"
|
||||
|
||||
config BT_OTS_OACP_DELETE_SUPPORT
|
||||
bool "Support OACP Delete Operation"
|
||||
|
||||
|
|
|
@ -42,6 +42,12 @@ LOG_MODULE_REGISTER(bt_ots, CONFIG_BT_OTS_LOG_LEVEL);
|
|||
#define OACP_FEAT_BIT_DELETE 0
|
||||
#endif
|
||||
|
||||
#if defined(BT_OTS_OACP_CHECKSUM_SUPPORT)
|
||||
#define OACP_FEAT_BIT_CRC BIT(BT_OTS_OACP_FEAT_CHECKSUM)
|
||||
#else
|
||||
#define OACP_FEAT_BIT_CRC 0
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_OTS_OACP_READ_SUPPORT)
|
||||
#define OACP_FEAT_BIT_READ BIT(BT_OTS_OACP_FEAT_READ)
|
||||
#else
|
||||
|
@ -64,6 +70,7 @@ LOG_MODULE_REGISTER(bt_ots, CONFIG_BT_OTS_LOG_LEVEL);
|
|||
#define OACP_FEAT ( \
|
||||
OACP_FEAT_BIT_CREATE | \
|
||||
OACP_FEAT_BIT_DELETE | \
|
||||
OACP_FEAT_BIT_CRC | \
|
||||
OACP_FEAT_BIT_READ | \
|
||||
OACP_FEAT_BIT_WRITE | \
|
||||
OACP_FEAT_BIT_PATCH)
|
||||
|
@ -443,6 +450,10 @@ int bt_ots_init(struct bt_ots *ots,
|
|||
__ASSERT(ots_init->cb->obj_deleted ||
|
||||
!BT_OTS_OACP_GET_FEAT_CREATE(ots_init->features.oacp),
|
||||
"Callback for object deletion is not set and object creation is enabled");
|
||||
#if defined(CONFIG_BT_OTS_OACP_CHECKSUM_SUPPORT)
|
||||
__ASSERT(ots_init->cb->obj_cal_checksum,
|
||||
"Callback for object calculate checksum is not set");
|
||||
#endif
|
||||
__ASSERT(ots_init->cb->obj_read ||
|
||||
!BT_OTS_OACP_GET_FEAT_READ(ots_init->features.oacp),
|
||||
"Callback for object reading is not set");
|
||||
|
|
|
@ -125,6 +125,8 @@ static int oacp_read(struct bt_conn *conn,
|
|||
static int oacp_write(struct bt_conn *conn, struct bt_otc_internal_instance_t *inst,
|
||||
const void *buf, uint32_t len, uint32_t offset,
|
||||
enum bt_ots_oacp_write_op_mode mode);
|
||||
static int oacp_checksum(struct bt_conn *conn, struct bt_otc_internal_instance_t *inst,
|
||||
uint32_t offset, uint32_t len);
|
||||
static void read_next_metadata(struct bt_conn *conn,
|
||||
struct bt_otc_internal_instance_t *inst);
|
||||
static int read_attr(struct bt_conn *conn,
|
||||
|
@ -356,6 +358,9 @@ static void oacp_ind_handler(struct bt_conn *conn,
|
|||
const void *data, uint16_t length)
|
||||
{
|
||||
enum bt_gatt_ots_oacp_proc_type op_code;
|
||||
enum bt_gatt_ots_oacp_proc_type req_opcode;
|
||||
enum bt_gatt_ots_oacp_res_code result_code;
|
||||
uint32_t checksum;
|
||||
struct net_buf_simple net_buf;
|
||||
|
||||
net_buf_simple_init_with_data(&net_buf, (void *)data, length);
|
||||
|
@ -365,10 +370,29 @@ static void oacp_ind_handler(struct bt_conn *conn,
|
|||
LOG_DBG("OACP indication");
|
||||
|
||||
if (op_code == BT_GATT_OTS_OACP_PROC_RESP) {
|
||||
enum bt_gatt_ots_oacp_proc_type req_opcode =
|
||||
net_buf_simple_pull_u8(&net_buf);
|
||||
enum bt_gatt_ots_oacp_res_code result_code =
|
||||
net_buf_simple_pull_u8(&net_buf);
|
||||
if (net_buf.len >= (sizeof(req_opcode) + sizeof(result_code))) {
|
||||
req_opcode = net_buf_simple_pull_u8(&net_buf);
|
||||
result_code = net_buf_simple_pull_u8(&net_buf);
|
||||
} else {
|
||||
LOG_ERR("Invalid indication data len %u", net_buf.len);
|
||||
return;
|
||||
}
|
||||
|
||||
if (req_opcode == BT_GATT_OTS_OACP_PROC_CHECKSUM_CALC) {
|
||||
if (net_buf.len == sizeof(checksum)) {
|
||||
checksum = net_buf_simple_pull_le32(&net_buf);
|
||||
LOG_DBG("Object checksum 0x%08x\n", checksum);
|
||||
if (otc_inst->cb->obj_checksum_calculated) {
|
||||
otc_inst->cb->obj_checksum_calculated(
|
||||
otc_inst, conn, result_code, checksum);
|
||||
}
|
||||
} else {
|
||||
LOG_ERR("Invalid indication data len %u after opcode and result "
|
||||
"pulled", net_buf.len);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
print_oacp_response(req_opcode, result_code);
|
||||
} else {
|
||||
LOG_DBG("Invalid indication opcode %u", op_code);
|
||||
|
@ -1263,6 +1287,49 @@ static int oacp_write(struct bt_conn *conn, struct bt_otc_internal_instance_t *i
|
|||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int oacp_checksum(struct bt_conn *conn, struct bt_otc_internal_instance_t *inst,
|
||||
uint32_t offset, uint32_t len)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!inst->otc_inst->oacp_handle) {
|
||||
LOG_DBG("Handle not set");
|
||||
return -EINVAL;
|
||||
} else if (inst->busy) {
|
||||
LOG_DBG("Client is busy");
|
||||
return -EBUSY;
|
||||
} else if (cur_inst) {
|
||||
LOG_DBG("Previous operation is not finished");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
net_buf_simple_reset(&otc_tx_buf);
|
||||
|
||||
/* OP Code */
|
||||
net_buf_simple_add_u8(&otc_tx_buf, BT_GATT_OTS_OACP_PROC_CHECKSUM_CALC);
|
||||
|
||||
/* Offset */
|
||||
net_buf_simple_add_le32(&otc_tx_buf, offset);
|
||||
|
||||
/* Len */
|
||||
net_buf_simple_add_le32(&otc_tx_buf, len);
|
||||
|
||||
inst->otc_inst->write_params.offset = 0;
|
||||
inst->otc_inst->write_params.data = otc_tx_buf.data;
|
||||
inst->otc_inst->write_params.length = otc_tx_buf.len;
|
||||
inst->otc_inst->write_params.handle = inst->otc_inst->oacp_handle;
|
||||
inst->otc_inst->write_params.func = write_oacp_cp_cb;
|
||||
|
||||
err = bt_gatt_write(conn, &inst->otc_inst->write_params);
|
||||
if (err != 0) {
|
||||
inst->busy = true;
|
||||
cur_inst = inst;
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int bt_ots_client_read_object_data(struct bt_ots_client *otc_inst,
|
||||
struct bt_conn *conn)
|
||||
{
|
||||
|
@ -1317,7 +1384,7 @@ int bt_ots_client_write_object_data(struct bt_ots_client *otc_inst,
|
|||
* Offset and Length field are UINT32 Length
|
||||
*/
|
||||
CHECKIF(len > UINT32_MAX) {
|
||||
LOG_ERR("length exceeds UINT32");
|
||||
LOG_ERR("length %zu exceeds UINT32", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -1327,7 +1394,7 @@ int bt_ots_client_write_object_data(struct bt_ots_client *otc_inst,
|
|||
}
|
||||
|
||||
CHECKIF((offset > UINT32_MAX) || (offset < 0)) {
|
||||
LOG_ERR("offset exceeds UINT32");
|
||||
LOG_ERR("offset %ld exceeds UINT32 and must be >= 0", offset);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -1359,6 +1426,54 @@ int bt_ots_client_write_object_data(struct bt_ots_client *otc_inst,
|
|||
return oacp_write(conn, inst, buf, (uint32_t)len, (uint32_t)offset, mode);
|
||||
}
|
||||
|
||||
int bt_ots_client_get_object_checksum(struct bt_ots_client *otc_inst, struct bt_conn *conn,
|
||||
off_t offset, size_t len)
|
||||
{
|
||||
struct bt_otc_internal_instance_t *inst;
|
||||
|
||||
CHECKIF(!conn) {
|
||||
LOG_DBG("Invalid Connection");
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
CHECKIF(!otc_inst) {
|
||||
LOG_DBG("Invalid OTC instance");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* OTS_v10.pdf Table 3.9: Object Action Control Point Procedure Requirements
|
||||
* Offset and Length field are UINT32 Length
|
||||
*/
|
||||
CHECKIF(len > UINT32_MAX) {
|
||||
LOG_DBG("length %zu exceeds UINT32", len);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
CHECKIF(len == 0) {
|
||||
LOG_DBG("length equals zero");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
CHECKIF((offset > UINT32_MAX) || (offset < 0)) {
|
||||
LOG_DBG("offset exceeds %ld UINT32 and must be >= 0", offset);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
CHECKIF((len + offset) > otc_inst->cur_object.size.cur) {
|
||||
LOG_DBG("The sum of offset (%ld) and length (%zu) exceed the Current Size %lu "
|
||||
"alloc %zu.", offset, len, (len + offset), otc_inst->cur_object.size.cur);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
inst = lookup_inst_by_handle(otc_inst->start_handle);
|
||||
if (!inst) {
|
||||
LOG_DBG("Invalid OTC instance");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return oacp_checksum(conn, inst, (uint32_t)offset, (uint32_t)len);
|
||||
}
|
||||
|
||||
static void read_next_metadata(struct bt_conn *conn,
|
||||
struct bt_otc_internal_instance_t *inst)
|
||||
{
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
#include <errno.h>
|
||||
#include <zephyr/sys/printk.h>
|
||||
#include <zephyr/sys/byteorder.h>
|
||||
#include <zephyr/sys/check.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/sys/crc.h>
|
||||
|
||||
#include <zephyr/bluetooth/gatt.h>
|
||||
#include <zephyr/bluetooth/services/ots.h>
|
||||
|
@ -23,7 +25,16 @@
|
|||
LOG_MODULE_DECLARE(bt_ots, CONFIG_BT_OTS_LOG_LEVEL);
|
||||
|
||||
#define OACP_PROC_TYPE_SIZE 1
|
||||
#define OACP_RES_MAX_SIZE 3
|
||||
/**
|
||||
* OTS_v10.pdf Table 3.10: Format of OACP Response V
|
||||
* OACP Response Value contains
|
||||
* 1 octet Procedure code
|
||||
* 1 octet Request op code
|
||||
* 1 octet Result Code
|
||||
* 4 octet CRC checksum (if present)
|
||||
* Execute operation is not supported
|
||||
**/
|
||||
#define OACP_RES_MAX_SIZE (3 + sizeof(uint32_t))
|
||||
|
||||
#if defined(CONFIG_BT_OTS_OACP_WRITE_SUPPORT)
|
||||
static ssize_t oacp_write_proc_cb(struct bt_gatt_ots_l2cap *l2cap_ctx,
|
||||
|
@ -161,12 +172,62 @@ exit:
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_BT_OTS_OACP_CHECKSUM_SUPPORT)
|
||||
static enum bt_gatt_ots_oacp_res_code oacp_checksum_proc_validate(
|
||||
struct bt_conn *conn,
|
||||
struct bt_ots *ots,
|
||||
struct bt_gatt_ots_oacp_proc *proc,
|
||||
struct net_buf_simple *resp_param)
|
||||
{
|
||||
struct bt_gatt_ots_oacp_cs_calc_params *params = &proc->cs_calc_params;
|
||||
void *obj_data;
|
||||
int err;
|
||||
uint32_t checksum;
|
||||
|
||||
LOG_DBG("Validating Checksum procedure with offset: 0x%08X and "
|
||||
"length: 0x%08X", params->offset, params->len);
|
||||
|
||||
if (!ots->cur_obj) {
|
||||
return BT_GATT_OTS_OACP_RES_INV_OBJ;
|
||||
}
|
||||
|
||||
if (params->offset > ots->cur_obj->metadata.size.cur) {
|
||||
return BT_GATT_OTS_OACP_RES_INV_PARAM;
|
||||
}
|
||||
|
||||
if ((params->offset + (uint64_t) params->len) > ots->cur_obj->metadata.size.alloc) {
|
||||
return BT_GATT_OTS_OACP_RES_INV_PARAM;
|
||||
}
|
||||
|
||||
if (ots->cur_obj->state.type != BT_GATT_OTS_OBJECT_IDLE_STATE) {
|
||||
return BT_GATT_OTS_OACP_RES_OBJ_LOCKED;
|
||||
}
|
||||
|
||||
if (ots->cb->obj_cal_checksum) {
|
||||
err = ots->cb->obj_cal_checksum(ots, conn, ots->cur_obj->id, params->offset,
|
||||
params->len, &obj_data);
|
||||
if (err != 0) {
|
||||
return BT_GATT_OTS_OACP_RES_OPER_FAILED;
|
||||
}
|
||||
|
||||
checksum = bt_ots_client_calc_checksum((const uint8_t *)obj_data, params->len);
|
||||
net_buf_simple_reserve(resp_param, sizeof(uint32_t));
|
||||
net_buf_simple_add_le32(resp_param, checksum);
|
||||
LOG_DBG("Calculate from offset %u len %u checksum 0x%08x\n", params->offset,
|
||||
params->len, checksum);
|
||||
return BT_GATT_OTS_OACP_RES_SUCCESS;
|
||||
} else {
|
||||
return BT_GATT_OTS_OACP_RES_OPER_FAILED;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static enum bt_gatt_ots_oacp_res_code oacp_read_proc_validate(
|
||||
struct bt_conn *conn,
|
||||
struct bt_ots *ots,
|
||||
struct bt_gatt_ots_oacp_proc *proc)
|
||||
const struct bt_gatt_ots_oacp_proc *proc)
|
||||
{
|
||||
struct bt_gatt_ots_oacp_read_params *params = &proc->read_params;
|
||||
const struct bt_gatt_ots_oacp_read_params *params = &proc->read_params;
|
||||
|
||||
LOG_DBG("Validating Read procedure with offset: 0x%08X and "
|
||||
"length: 0x%08X", params->offset, params->len);
|
||||
|
@ -273,7 +334,8 @@ static enum bt_gatt_ots_oacp_res_code oacp_write_proc_validate(
|
|||
static enum bt_gatt_ots_oacp_res_code oacp_proc_validate(
|
||||
struct bt_conn *conn,
|
||||
struct bt_ots *ots,
|
||||
struct bt_gatt_ots_oacp_proc *proc)
|
||||
struct bt_gatt_ots_oacp_proc *proc,
|
||||
struct net_buf_simple *resp_param)
|
||||
{
|
||||
switch (proc->type) {
|
||||
case BT_GATT_OTS_OACP_PROC_READ:
|
||||
|
@ -290,7 +352,10 @@ static enum bt_gatt_ots_oacp_res_code oacp_proc_validate(
|
|||
case BT_GATT_OTS_OACP_PROC_DELETE:
|
||||
return oacp_delete_proc_validate(conn, ots, proc);
|
||||
#endif
|
||||
#if defined(CONFIG_BT_OTS_OACP_CHECKSUM_SUPPORT)
|
||||
case BT_GATT_OTS_OACP_PROC_CHECKSUM_CALC:
|
||||
return oacp_checksum_proc_validate(conn, ots, proc, resp_param);
|
||||
#endif
|
||||
case BT_GATT_OTS_OACP_PROC_EXECUTE:
|
||||
case BT_GATT_OTS_OACP_PROC_ABORT:
|
||||
default:
|
||||
|
@ -581,8 +646,9 @@ static void oacp_ind_cb(struct bt_conn *conn,
|
|||
}
|
||||
|
||||
static int oacp_ind_send(const struct bt_gatt_attr *oacp_attr,
|
||||
enum bt_gatt_ots_oacp_proc_type req_op_code,
|
||||
enum bt_gatt_ots_oacp_res_code oacp_status)
|
||||
struct bt_gatt_ots_oacp_proc oacp_proc,
|
||||
enum bt_gatt_ots_oacp_res_code oacp_status,
|
||||
struct net_buf_simple *resp_param)
|
||||
{
|
||||
uint8_t oacp_res[OACP_RES_MAX_SIZE];
|
||||
uint16_t oacp_res_len = 0;
|
||||
|
@ -590,9 +656,14 @@ static int oacp_ind_send(const struct bt_gatt_attr *oacp_attr,
|
|||
|
||||
/* Encode OACP Response */
|
||||
oacp_res[oacp_res_len++] = BT_GATT_OTS_OACP_PROC_RESP;
|
||||
oacp_res[oacp_res_len++] = req_op_code;
|
||||
oacp_res[oacp_res_len++] = oacp_proc.type;
|
||||
oacp_res[oacp_res_len++] = oacp_status;
|
||||
|
||||
if (oacp_proc.type == BT_GATT_OTS_OACP_PROC_CHECKSUM_CALC) {
|
||||
sys_put_le32(net_buf_simple_pull_le32(resp_param), (oacp_res + oacp_res_len));
|
||||
oacp_res_len += sizeof(uint32_t);
|
||||
}
|
||||
|
||||
/* Prepare indication parameters */
|
||||
memset(&ots->oacp_ind.params, 0, sizeof(ots->oacp_ind.params));
|
||||
memcpy(&ots->oacp_ind.attr, oacp_attr, sizeof(ots->oacp_ind.attr));
|
||||
|
@ -613,8 +684,9 @@ ssize_t bt_gatt_ots_oacp_write(struct bt_conn *conn,
|
|||
{
|
||||
enum bt_gatt_ots_oacp_res_code oacp_status;
|
||||
int decode_status;
|
||||
struct bt_gatt_ots_oacp_proc oacp_proc;
|
||||
struct bt_gatt_ots_oacp_proc oacp_proc = {0};
|
||||
struct bt_ots *ots = (struct bt_ots *) attr->user_data;
|
||||
struct net_buf_simple resp_param;
|
||||
|
||||
LOG_DBG("Object Action Control Point GATT Write Operation");
|
||||
|
||||
|
@ -631,7 +703,7 @@ ssize_t bt_gatt_ots_oacp_write(struct bt_conn *conn,
|
|||
decode_status = oacp_command_decode(buf, len, &oacp_proc);
|
||||
switch (decode_status) {
|
||||
case 0:
|
||||
oacp_status = oacp_proc_validate(conn, ots, &oacp_proc);
|
||||
oacp_status = oacp_proc_validate(conn, ots, &oacp_proc, &resp_param);
|
||||
if (oacp_status != BT_GATT_OTS_OACP_RES_SUCCESS) {
|
||||
LOG_WRN("OACP Write error status: 0x%02X", oacp_status);
|
||||
}
|
||||
|
@ -652,7 +724,7 @@ ssize_t bt_gatt_ots_oacp_write(struct bt_conn *conn,
|
|||
return BT_GATT_ERR(BT_ATT_ERR_UNLIKELY);
|
||||
}
|
||||
|
||||
oacp_ind_send(attr, oacp_proc.type, oacp_status);
|
||||
oacp_ind_send(attr, oacp_proc, oacp_status, &resp_param);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue