This patch set makes the following additions/changes:
- The opcode + param structure semantics are no longer used. bt_att_send now
takes in the PDU as it will be sent over the physical link and it won't
perform any explicit encoding or decoding of PDUs between host order and BT
order. Any packed structs that get passed to bt_att_send need to be
formatted according to the correct endianness.
- bt_att_register and bt_att_unregister* functions are implemented. Callbacks
are registered for a particular opcode and they get invoked when an incoming
PDU of type "request", "indication", or "notification" is received.
This provides the basic functionality needed to implement a GATT client layer,
except for PDU signing and verifications of incoming signed PDUs. This isn't
immediately needed to implement a functioning client and could be left to the
upper layer.
Arman Uguray (2):
shared/att: Remove parameters structures.
shared/att: Implement bt_att_register.
src/shared/att-types.h | 153 +-------------------
src/shared/att.c | 383 ++++++++++++++++++++++++++++++++-----------------
src/shared/att.h | 19 +--
3 files changed, 267 insertions(+), 288 deletions(-)
--
2.0.0.526.g5318336
Hi Arman,
> This patch set makes the following additions/changes:
>
> - The opcode + param structure semantics are no longer used. bt_att_send now
> takes in the PDU as it will be sent over the physical link and it won't
> perform any explicit encoding or decoding of PDUs between host order and BT
> order. Any packed structs that get passed to bt_att_send need to be
> formatted according to the correct endianness.
>
> - bt_att_register and bt_att_unregister* functions are implemented. Callbacks
> are registered for a particular opcode and they get invoked when an incoming
> PDU of type "request", "indication", or "notification" is received.
>
> This provides the basic functionality needed to implement a GATT client layer,
> except for PDU signing and verifications of incoming signed PDUs. This isn't
> immediately needed to implement a functioning client and could be left to the
> upper layer.
>
> Arman Uguray (2):
> shared/att: Remove parameters structures.
> shared/att: Implement bt_att_register.
>
> src/shared/att-types.h | 153 +-------------------
> src/shared/att.c | 383 ++++++++++++++++++++++++++++++++-----------------
> src/shared/att.h | 19 +--
> 3 files changed, 267 insertions(+), 288 deletions(-)
I have applied both patches. However please keep in mind that the CSRK signing and resolving still needs to happen in this low-level ATT. The signatures are calculated over the whole PDU including opcode. Our BlueZ for Android code is capable of using signed write, so you can test against that one.
Regards
Marcel
This patch implements bt_att_register and the internal mechanism for invoking
registered callbacks when a non-response/non-indication PDU is received from the
remote end.
---
src/shared/att.c | 207 +++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 186 insertions(+), 21 deletions(-)
diff --git a/src/shared/att.c b/src/shared/att.c
index e5e38ac..0d27dfa 100644
--- a/src/shared/att.c
+++ b/src/shared/att.c
@@ -58,6 +58,10 @@ struct bt_att {
struct queue *write_queue; /* Queue of PDUs ready to send */
bool writer_active;
+ struct queue *notify_list; /* List of registered callbacks */
+ bool in_notify;
+ bool need_notify_cleanup;
+
uint8_t *buf;
uint16_t mtu;
@@ -172,6 +176,61 @@ struct att_send_op {
void *user_data;
};
+static void destroy_att_send_op(void *data)
+{
+ struct att_send_op *op = data;
+
+ if (op->timeout_id)
+ timeout_remove(op->timeout_id);
+
+ if (op->destroy)
+ op->destroy(op->user_data);
+
+ free(op->pdu);
+ free(op);
+}
+
+struct att_notify {
+ unsigned int id;
+ uint16_t opcode;
+ bool removed;
+ bt_att_notify_func_t callback;
+ bt_att_destroy_func_t destroy;
+ void *user_data;
+};
+
+static void destroy_att_notify(void *data)
+{
+ struct att_notify *notify = data;
+
+ if (notify->destroy)
+ notify->destroy(notify->user_data);
+
+ free(notify);
+}
+
+static bool match_notify_id(const void *a, const void *b)
+{
+ const struct att_notify *notify = a;
+ unsigned int id = PTR_TO_UINT(b);
+
+ return notify->id == id;
+}
+
+static bool match_notify_removed(const void *a, const void *b)
+{
+ const struct att_notify *notify = a;
+
+ return notify->removed;
+}
+
+static void mark_notify_removed(void *data, void *user_data)
+{
+ struct att_notify *notify = data;
+
+ notify->removed = true;
+}
+
static bool encode_pdu(struct att_send_op *op, const void *pdu,
uint16_t length, uint16_t mtu)
{
@@ -272,20 +331,6 @@ static struct att_send_op *pick_next_send_op(struct bt_att *att)
return NULL;
}
-static void destroy_att_send_op(void *data)
-{
- struct att_send_op *op = data;
-
- if (op->timeout_id)
- timeout_remove(op->timeout_id);
-
- if (op->destroy)
- op->destroy(op->user_data);
-
- free(op->pdu);
- free(op);
-}
-
struct timeout_data {
struct bt_att *att;
unsigned int id;
@@ -462,6 +507,57 @@ done:
wakeup_writer(att);
}
+struct notify_data {
+ uint8_t opcode;
+ uint8_t *pdu;
+ ssize_t pdu_len;
+};
+
+static void notify_handler(void *data, void *user_data)
+{
+ struct att_notify *notify = data;
+ struct notify_data *not_data = user_data;
+
+ if (notify->removed)
+ return;
+
+ if (notify->opcode != not_data->opcode)
+ return;
+
+ if (notify->callback)
+ notify->callback(not_data->opcode, not_data->pdu,
+ not_data->pdu_len, notify->user_data);
+}
+
+static void handle_notify(struct bt_att *att, uint8_t opcode, uint8_t *pdu,
+ ssize_t pdu_len)
+{
+ struct notify_data data;
+
+ bt_att_ref(att);
+ att->in_notify = true;
+
+ memset(&data, 0, sizeof(data));
+ data.opcode = opcode;
+
+ if (pdu_len > 0) {
+ data.pdu = pdu;
+ data.pdu_len = pdu_len;
+ }
+
+ queue_foreach(att->notify_list, notify_handler, &data);
+
+ att->in_notify = false;
+
+ if (att->need_notify_cleanup) {
+ queue_remove_all(att->notify_list, match_notify_removed, NULL,
+ destroy_att_notify);
+ att->need_notify_cleanup = false;
+ }
+
+ bt_att_unref(att);
+}
+
static bool can_read_data(struct io *io, void *user_data)
{
struct bt_att *att = user_data;
@@ -485,12 +581,22 @@ static bool can_read_data(struct io *io, void *user_data)
/* Act on the received PDU based on the opcode type */
switch (get_op_type(opcode)) {
case ATT_OP_TYPE_RSP:
+ util_debug(att->debug_callback, att->debug_data,
+ "ATT response received: 0x%02x", opcode);
handle_rsp(att, opcode, pdu + 1, bytes_read - 1);
break;
- default:
+ case ATT_OP_TYPE_CONF:
util_debug(att->debug_callback, att->debug_data,
"ATT opcode cannot be handled: 0x%02x", opcode);
break;
+ default:
+ /* For all other opcodes notify the upper layer of the PDU and
+ * let them act on it.
+ */
+ util_debug(att->debug_callback, att->debug_data,
+ "ATT PDU received: 0x%02x", opcode);
+ handle_notify(att, opcode, pdu + 1, bytes_read - 1);
+ break;
}
return true;
@@ -530,6 +636,10 @@ struct bt_att *bt_att_new(int fd)
if (!att->write_queue)
goto fail;
+ att->notify_list = queue_new();
+ if (!att->notify_list)
+ goto fail;
+
if (!io_set_read_handler(att->io, can_read_data, att, NULL))
goto fail;
@@ -564,6 +674,7 @@ void bt_att_unref(struct bt_att *att)
if (__sync_sub_and_fetch(&att->ref_count, 1))
return;
+ bt_att_unregister_all(att);
bt_att_cancel_all(att);
io_set_write_handler(att->io, NULL, NULL, NULL);
@@ -572,9 +683,11 @@ void bt_att_unref(struct bt_att *att)
queue_destroy(att->req_queue, NULL);
queue_destroy(att->ind_queue, NULL);
queue_destroy(att->write_queue, NULL);
+ queue_destroy(att->notify_list, NULL);
att->req_queue = NULL;
att->ind_queue = NULL;
att->write_queue = NULL;
+ att->notify_list = NULL;
io_destroy(att->io);
att->io = NULL;
@@ -786,18 +899,70 @@ unsigned int bt_att_register(struct bt_att *att, uint8_t opcode,
void *user_data,
bt_att_destroy_func_t destroy)
{
- /* TODO */
- return 0;
+ struct att_notify *notify;
+
+ if (!att || !opcode || !callback)
+ return 0;
+
+ notify = new0(struct att_notify, 1);
+ if (!notify)
+ return 0;
+
+ notify->opcode = opcode;
+ notify->callback = callback;
+ notify->destroy = destroy;
+ notify->user_data = user_data;
+
+ if (att->next_reg_id < 1)
+ att->next_reg_id = 1;
+
+ notify->id = att->next_reg_id++;
+
+ if (!queue_push_tail(att->notify_list, notify)) {
+ free(notify);
+ return 0;
+ }
+
+ return notify->id;
}
bool bt_att_unregister(struct bt_att *att, unsigned int id)
{
- /* TODO */
- return false;
+ struct att_notify *notify;
+
+ if (!att || !id)
+ return false;
+
+ notify = queue_find(att->notify_list, match_notify_id,
+ UINT_TO_PTR(id));
+ if (!notify)
+ return false;
+
+ if (!att->in_notify) {
+ queue_remove(att->notify_list, notify);
+ destroy_att_notify(notify);
+ return true;
+ }
+
+ notify->removed = true;
+ att->need_notify_cleanup = true;
+
+ return true;
}
bool bt_att_unregister_all(struct bt_att *att)
{
- /* TODO */
- return false;
+ if (!att)
+ return false;
+
+ if (!att->in_notify) {
+ queue_remove_all(att->notify_list, NULL, NULL,
+ destroy_att_notify);
+ return true;
+ }
+
+ queue_foreach(att->notify_list, mark_notify_removed, NULL);
+ att->need_notify_cleanup = true;
+
+ return true;
}
--
2.0.0.526.g5318336
This patch removes the PDU encoding functionality from src/shared/att. This is
now left up to the upper layer and the responsibilities of bt_att are restricted
to handle the low-level transport and the sequential/non-sequential ATT protocol
logic.
---
src/shared/att-types.h | 153 +----------------------------------
src/shared/att.c | 210 ++++++++++++++++++++-----------------------------
src/shared/att.h | 19 ++---
3 files changed, 98 insertions(+), 284 deletions(-)
diff --git a/src/shared/att-types.h b/src/shared/att-types.h
index 636a5e3..1637f6f 100644
--- a/src/shared/att-types.h
+++ b/src/shared/att-types.h
@@ -23,183 +23,34 @@
#include <stdint.h>
-/* Error response */
+/* ATT protocol opcodes */
#define BT_ATT_OP_ERROR_RSP 0x01
-struct bt_att_error_rsp_param {
- uint8_t request_opcode;
- uint16_t handle;
- uint8_t error_code;
-};
-
-/* Exchange MTU */
#define BT_ATT_OP_MTU_REQ 0x02
-struct bt_att_mtu_req_param {
- uint16_t client_rx_mtu;
-};
-
#define BT_ATT_OP_MTU_RSP 0x03
-struct bt_att_mtu_rsp_param {
- uint16_t server_rx_mtu;
-};
-
-/* Find Information */
#define BT_ATT_OP_FIND_INFO_REQ 0x04
-struct bt_att_find_info_req_param {
- uint16_t start_handle;
- uint16_t end_handle;
-};
-
#define BT_ATT_OP_FIND_INFO_RSP 0x05
-struct bt_att_find_info_rsp_param {
- uint8_t format;
- const uint8_t *info_data;
- uint16_t length;
-};
-
-/* Find By Type Value */
#define BT_ATT_OP_FIND_BY_TYPE_VAL_REQ 0x06
-struct bt_att_find_by_type_value_req_param {
- uint16_t start_handle;
- uint16_t end_handle;
- uint16_t type; /* 2 octet UUID */
- const uint8_t *value;
- uint16_t length; /* MAX length: (ATT_MTU - 7) */
-};
-
#define BT_ATT_OP_FIND_BY_TYPE_VAL_RSP 0x07
-struct bt_att_find_by_type_value_rsp_param {
- const uint8_t *handles_info_list;
- uint16_t length;
-};
-
-/* Read By Type */
#define BT_ATT_OP_READ_BY_TYPE_REQ 0x08
-struct bt_att_read_by_type_req_param {
- uint16_t start_handle;
- uint16_t end_handle;
- bt_uuid_t type; /* 2 or 16 octet UUID */
-};
-
#define BT_ATT_OP_READ_BY_TYPE_RSP 0x09
-struct bt_att_read_by_type_rsp_param {
- uint8_t length;
- const uint8_t *attr_data_list;
- uint16_t list_length; /* Length of "attr_data_list" */
-};
-
-/* Read */
#define BT_ATT_OP_READ_REQ 0x0a
-struct bt_att_read_req_param {
- uint16_t handle;
-};
-
#define BT_ATT_OP_READ_RSP 0x0b
-struct bt_att_read_rsp_param {
- const uint8_t *value;
- uint16_t length;
-};
-
-/* Read Blob */
#define BT_ATT_OP_READ_BLOB_REQ 0x0c
-struct bt_att_read_blob_req_param {
- uint16_t handle;
- uint16_t offset;
-};
-
#define BT_ATT_OP_READ_BLOB_RSP 0x0d
-struct bt_att_read_blob_rsp_param {
- const uint8_t *part_value;
- uint16_t length;
-};
-
-/* Read Multiple */
#define BT_ATT_OP_READ_MULT_REQ 0x0e
-struct bt_att_read_multiple_req_param {
- const uint16_t *handles;
- uint16_t num_handles;
-};
-
#define BT_ATT_OP_READ_MULT_RSP 0x0f
-struct bt_att_read_multiple_rsp_param {
- const uint8_t *values;
- uint16_t length;
-};
-
-/* Read By Group Type */
#define BT_ATT_OP_READ_BY_GRP_TYPE_REQ 0x10
-struct bt_att_read_by_group_type_req_param {
- uint16_t start_handle;
- uint16_t end_handle;
- bt_uuid_t type;
-};
-
#define BT_ATT_OP_READ_BY_GRP_TYPE_RSP 0x11
-struct bt_att_read_by_group_type_rsp_param {
- uint8_t length;
- const uint8_t *attr_data_list;
- uint16_t list_length; /* Length of "attr_data_list" */
-};
-
-/* Write Request */
#define BT_ATT_OP_WRITE_REQ 0x12
-/*
- * bt_att_write_param is used for write request and signed and unsigned write
- * command.
- */
-struct bt_att_write_param {
- uint16_t handle;
- const uint8_t *value;
- uint16_t length;
-};
-
-#define BT_ATT_OP_WRITE_RSP 0x13 /* No parameters */
-
-/* Write Command */
+#define BT_ATT_OP_WRITE_RSP 0x13
#define BT_ATT_OP_WRITE_CMD 0x52
-
-/* Signed Write Command */
#define BT_ATT_OP_SIGNED_WRITE_CMD 0xD2
-
-/* Prepare Write */
#define BT_ATT_OP_PREP_WRITE_REQ 0x16
-struct bt_att_prepare_write_req_param {
- uint16_t handle;
- uint16_t offset;
- const uint8_t *part_value;
- uint16_t length;
-};
-
#define BT_ATT_OP_PREP_WRITE_RSP 0x17
-struct bt_att_prepare_write_rsp_param {
- uint16_t handle;
- uint16_t offset;
- const uint8_t *part_value;
- uint16_t length;
-};
-
-/* Execute Write */
#define BT_ATT_OP_EXEC_WRITE_REQ 0x18
-typedef enum {
- BT_ATT_EXEC_WRITE_FLAG_CANCEL = 0x00,
- BT_ATT_EXEC_WRITE_FLAG_WRITE = 0x01,
-} bt_att_exec_write_flag_t;
-
-struct bt_att_exec_write_req_param {
- bt_att_exec_write_flag_t flags;
-};
-
#define BT_ATT_OP_EXEC_WRITE_RSP 0x19
-
-/* Handle Value Notification/Indication */
#define BT_ATT_OP_HANDLE_VAL_NOT 0x1B
#define BT_ATT_OP_HANDLE_VAL_IND 0x1D
-struct bt_att_notify_param {
- uint16_t handle;
- const uint8_t *value;
- uint16_t length;
-};
-
-/* Handle Value Confirmation */
#define BT_ATT_OP_HANDLE_VAL_CONF 0x1E
/* Error codes for Error response PDU */
diff --git a/src/shared/att.c b/src/shared/att.c
index 57f887e..e5e38ac 100644
--- a/src/shared/att.c
+++ b/src/shared/att.c
@@ -130,6 +130,36 @@ static enum att_op_type get_op_type(uint8_t opcode)
return ATT_OP_TYPE_UNKNOWN;
}
+static const struct {
+ uint8_t req_opcode;
+ uint8_t rsp_opcode;
+} att_req_rsp_mapping_table[] = {
+ { BT_ATT_OP_MTU_REQ, BT_ATT_OP_MTU_RSP },
+ { BT_ATT_OP_FIND_INFO_REQ, BT_ATT_OP_FIND_INFO_RSP},
+ { BT_ATT_OP_FIND_BY_TYPE_VAL_REQ, BT_ATT_OP_FIND_BY_TYPE_VAL_RSP },
+ { BT_ATT_OP_READ_BY_TYPE_REQ, BT_ATT_OP_READ_BY_TYPE_RSP },
+ { BT_ATT_OP_READ_REQ, BT_ATT_OP_READ_RSP },
+ { BT_ATT_OP_READ_BLOB_REQ, BT_ATT_OP_READ_BLOB_RSP },
+ { BT_ATT_OP_READ_MULT_REQ, BT_ATT_OP_READ_MULT_RSP },
+ { BT_ATT_OP_READ_BY_GRP_TYPE_REQ, BT_ATT_OP_READ_BY_GRP_TYPE_RSP },
+ { BT_ATT_OP_WRITE_REQ, BT_ATT_OP_WRITE_RSP },
+ { BT_ATT_OP_PREP_WRITE_REQ, BT_ATT_OP_PREP_WRITE_RSP },
+ { BT_ATT_OP_EXEC_WRITE_REQ, BT_ATT_OP_EXEC_WRITE_RSP },
+ { }
+};
+
+static uint8_t get_req_opcode(uint8_t rsp_opcode)
+{
+ int i;
+
+ for (i = 0; att_req_rsp_mapping_table[i].rsp_opcode; i++) {
+ if (att_req_rsp_mapping_table[i].rsp_opcode == rsp_opcode)
+ return att_req_rsp_mapping_table[i].req_opcode;
+ }
+
+ return 0;
+}
+
struct att_send_op {
unsigned int id;
unsigned int timeout_id;
@@ -137,77 +167,44 @@ struct att_send_op {
uint16_t opcode;
void *pdu;
uint16_t len;
- bt_att_request_func_t callback;
+ bt_att_response_func_t callback;
bt_att_destroy_func_t destroy;
void *user_data;
};
-static bool encode_mtu_req(struct att_send_op *op, const void *param,
+static bool encode_pdu(struct att_send_op *op, const void *pdu,
uint16_t length, uint16_t mtu)
{
- const struct bt_att_mtu_req_param *p = param;
- const uint16_t len = 3;
+ uint16_t pdu_len = 1;
- if (length != sizeof(*p))
- return false;
+ if (length && pdu)
+ pdu_len += length;
- if (len > mtu)
+ if (pdu_len > mtu)
return false;
- op->pdu = malloc(len);
+ op->len = pdu_len;
+ op->pdu = malloc(op->len);
if (!op->pdu)
return false;
((uint8_t *) op->pdu)[0] = op->opcode;
- put_le16(p->client_rx_mtu, ((uint8_t *) op->pdu) + 1);
- op->len = len;
+ if (pdu_len > 1)
+ memcpy(op->pdu + 1, pdu, length);
return true;
}
-static bool encode_pdu(struct att_send_op *op, const void *param,
- uint16_t length, uint16_t mtu)
-{
- /* If no parameters are given, simply set the PDU to consist of the
- * opcode (e.g. BT_ATT_OP_WRITE_RSP),
- */
- if (!length || !param) {
- op->len = 1;
- op->pdu = malloc(1);
- if (!op->pdu)
- return false;
-
- ((uint8_t *) op->pdu)[0] = op->opcode;
- return true;
- }
-
- /* TODO: If the opcode has the "signed" bit set, make sure that the
- * resulting PDU contains the authentication signature. Return an error,
- * if the provided parameters structure is such that it leaves no room
- * for an authentication signature in the PDU, or if no signing data
- * has been set to generate the authentication signature.
- */
-
- switch (op->opcode) {
- case BT_ATT_OP_MTU_REQ:
- return encode_mtu_req(op, param, length, mtu);
- default:
- break;
- }
-
- return false;
-}
-
-static struct att_send_op *create_att_send_op(uint8_t opcode, const void *param,
+static struct att_send_op *create_att_send_op(uint8_t opcode, const void *pdu,
uint16_t length, uint16_t mtu,
- bt_att_request_func_t callback,
+ bt_att_response_func_t callback,
void *user_data,
bt_att_destroy_func_t destroy)
{
struct att_send_op *op;
enum att_op_type op_type;
- if (!length && !param)
+ if (length && !pdu)
return NULL;
op_type = get_op_type(opcode);
@@ -237,7 +234,7 @@ static struct att_send_op *create_att_send_op(uint8_t opcode, const void *param,
op->destroy = destroy;
op->user_data = user_data;
- if (!encode_pdu(op, param, length, mtu)) {
+ if (!encode_pdu(op, pdu, length, mtu)) {
free(op);
return NULL;
}
@@ -411,94 +408,58 @@ static void wakeup_writer(struct bt_att *att)
att->writer_active = true;
}
-static bool request_complete(struct bt_att *att, uint8_t req_opcode,
- uint8_t rsp_opcode, const void *param,
- uint16_t len)
+static void handle_rsp(struct bt_att *att, uint8_t opcode, uint8_t *pdu,
+ ssize_t pdu_len)
{
struct att_send_op *op = att->pending_req;
+ uint8_t req_opcode;
+ uint8_t rsp_opcode;
+ uint8_t *rsp_pdu = NULL;
+ uint16_t rsp_pdu_len = 0;
+ /* If no request is pending, then the response is unexpected. */
if (!op) {
- /* There is no pending request so the response is unexpected. */
wakeup_writer(att);
- return false;
- }
-
- if (op->opcode != req_opcode) {
- /* The request opcode corresponding to the received response
- * opcode does not match the currently pending request.
- */
- return false;
+ return;
}
- if (op->callback)
- op->callback(rsp_opcode, param, len, op->user_data);
-
- destroy_att_send_op(op);
- att->pending_req = NULL;
-
- wakeup_writer(att);
- return true;
-}
-
-static bool handle_error_rsp(struct bt_att *att, uint8_t opcode, uint8_t *pdu,
- ssize_t pdu_len)
-{
- struct bt_att_error_rsp_param param;
-
- if (pdu_len != 5)
- return false;
-
- memset(¶m, 0, sizeof(param));
- param.request_opcode = pdu[1];
- param.handle = get_le16(pdu + 2);
- param.error_code = pdu[4];
+ /* If the received response doesn't match the pending request, or if
+ * the request is malformed, end the current request with failure.
+ */
+ if (opcode == BT_ATT_OP_ERROR_RSP) {
+ if (pdu_len != 4)
+ goto fail;
- return request_complete(att, pdu[1], opcode, ¶m, sizeof(param));
-}
+ req_opcode = pdu[0];
+ } else if (!(req_opcode = get_req_opcode(opcode)))
+ goto fail;
-static bool handle_mtu_rsp(struct bt_att *att, uint8_t opcode, uint8_t *pdu,
- ssize_t pdu_len)
-{
- struct bt_att_mtu_rsp_param param;
+ if (req_opcode != op->opcode)
+ goto fail;
- if (pdu_len != 3)
- return false;
+ rsp_opcode = opcode;
- memset(¶m, 0, sizeof(param));
- param.server_rx_mtu = get_le16(pdu + 1);
+ if (pdu_len > 0) {
+ rsp_pdu = pdu;
+ rsp_pdu_len = pdu_len;
+ }
- return request_complete(att, BT_ATT_OP_MTU_REQ, opcode,
- ¶m, sizeof(param));
-}
+ goto done;
-static void handle_rsp(struct bt_att *att, uint8_t opcode, uint8_t *pdu,
- ssize_t pdu_len)
-{
- bool success;
+fail:
+ util_debug(att->debug_callback, att->debug_data,
+ "Failed to handle response PDU; opcode: 0x%02x", opcode);
- switch (opcode) {
- case BT_ATT_OP_ERROR_RSP:
- success = handle_error_rsp(att, opcode, pdu, pdu_len);
- break;
- case BT_ATT_OP_MTU_RSP:
- success = handle_mtu_rsp(att, opcode, pdu, pdu_len);
- break;
- default:
- success = false;
- util_debug(att->debug_callback, att->debug_data,
- "Unknown response opcode: 0x%02x", opcode);
- break;
- }
+ rsp_opcode = BT_ATT_OP_ERROR_RSP;
- if (success)
- return;
+done:
+ if (op->callback)
+ op->callback(rsp_opcode, rsp_pdu, rsp_pdu_len, op->user_data);
- util_debug(att->debug_callback, att->debug_data,
- "Failed to handle respone PDU; opcode: 0x%02x", opcode);
+ destroy_att_send_op(op);
+ att->pending_req = NULL;
- if (att->pending_req)
- request_complete(att, att->pending_req->opcode,
- BT_ATT_OP_ERROR_RSP, NULL, 0);
+ wakeup_writer(att);
}
static bool can_read_data(struct io *io, void *user_data)
@@ -524,7 +485,7 @@ static bool can_read_data(struct io *io, void *user_data)
/* Act on the received PDU based on the opcode type */
switch (get_op_type(opcode)) {
case ATT_OP_TYPE_RSP:
- handle_rsp(att, opcode, pdu, bytes_read);
+ handle_rsp(att, opcode, pdu + 1, bytes_read - 1);
break;
default:
util_debug(att->debug_callback, att->debug_data,
@@ -707,8 +668,8 @@ bool bt_att_set_timeout_cb(struct bt_att *att, bt_att_timeout_func_t callback,
}
unsigned int bt_att_send(struct bt_att *att, uint8_t opcode,
- const void *param, uint16_t length,
- bt_att_request_func_t callback, void *user_data,
+ const void *pdu, uint16_t length,
+ bt_att_response_func_t callback, void *user_data,
bt_att_destroy_func_t destroy)
{
struct att_send_op *op;
@@ -720,7 +681,7 @@ unsigned int bt_att_send(struct bt_att *att, uint8_t opcode,
if (att->invalid)
return 0;
- op = create_att_send_op(opcode, param, length, att->mtu, callback,
+ op = create_att_send_op(opcode, pdu, length, att->mtu, callback,
user_data, destroy);
if (!op)
return 0;
@@ -821,8 +782,9 @@ bool bt_att_cancel_all(struct bt_att *att)
}
unsigned int bt_att_register(struct bt_att *att, uint8_t opcode,
- bt_att_request_func_t callback,
- void *user_data, bt_att_destroy_func_t destroy)
+ bt_att_notify_func_t callback,
+ void *user_data,
+ bt_att_destroy_func_t destroy)
{
/* TODO */
return 0;
diff --git a/src/shared/att.h b/src/shared/att.h
index 65c2152..9fcd780 100644
--- a/src/shared/att.h
+++ b/src/shared/att.h
@@ -35,13 +35,12 @@ void bt_att_unref(struct bt_att *att);
bool bt_att_set_close_on_unref(struct bt_att *att, bool do_close);
-typedef void (*bt_att_request_func_t)(uint8_t opcode, const void *param,
+typedef void (*bt_att_response_func_t)(uint8_t opcode, const void *pdu,
+ uint16_t length, void *user_data);
+typedef void (*bt_att_notify_func_t)(uint8_t opcode, const void *pdu,
uint16_t length, void *user_data);
typedef void (*bt_att_destroy_func_t)(void *user_data);
typedef void (*bt_att_debug_func_t)(const char *str, void *user_data);
-typedef void (*bt_att_notify_func_t)(uint8_t opcode,
- const struct bt_att_notify_param *param,
- void *user_data);
typedef void (*bt_att_timeout_func_t)(unsigned int id, uint8_t opcode,
void *user_data);
@@ -56,14 +55,16 @@ bool bt_att_set_timeout_cb(struct bt_att *att, bt_att_timeout_func_t callback,
bt_att_destroy_func_t destroy);
unsigned int bt_att_send(struct bt_att *att, uint8_t opcode,
- const void *param, uint16_t length,
- bt_att_request_func_t callback, void *user_data,
- bt_att_destroy_func_t destroy);
+ const void *pdu, uint16_t length,
+ bt_att_response_func_t callback,
+ void *user_data,
+ bt_att_destroy_func_t destroy);
bool bt_att_cancel(struct bt_att *att, unsigned int id);
bool bt_att_cancel_all(struct bt_att *att);
unsigned int bt_att_register(struct bt_att *att, uint8_t opcode,
- bt_att_request_func_t callback,
- void *user_data, bt_att_destroy_func_t destroy);
+ bt_att_notify_func_t callback,
+ void *user_data,
+ bt_att_destroy_func_t destroy);
bool bt_att_unregister(struct bt_att *att, unsigned int id);
bool bt_att_unregister_all(struct bt_att *att);
--
2.0.0.526.g5318336