51 #define ATT_MIN_PDU_LEN 1
52 #define ATT_OP_CMD_MASK 0x40
53 #define ATT_OP_SIGNED_MASK 0x80
54 #define ATT_TIMEOUT_INTERVAL 30000
57 #define BT_ATT_SIGNATURE_LEN 12
139 static const struct {
186 static const struct {
282 return notify->
id ==
id;
308 return disconn->
id ==
id;
312 const void *pdu, uint16_t length)
314 uint16_t pdu_len = 1;
324 if (pdu_len > att->
mtu)
328 op->
pdu = malloc(op->
len);
334 memcpy(op->
pdu + 1, pdu, length);
343 sign_cnt, &((uint8_t *) op->
pdu)[1 + length])))
347 "ATT unable to generate signature");
456 "Operation timed out: 0x%02x", op->
opcode);
476 struct bt_att *att = user_data;
483 struct bt_att *att = user_data;
493 iov.iov_base = op->pdu;
494 iov.iov_len = op->len;
499 "write failed: %s", strerror(-ret));
509 "ATT op 0x%02x", op->opcode);
542 timeout->
id = op->id;
585 struct bt_att *att = user_data;
591 if (getsockopt(att->
fd, SOL_SOCKET, SO_ERROR, &err, &len) < 0) {
593 "Failed to obtain disconnect error: %s",
599 "Physical link disconnected: %s",
638 ssize_t pdu_len, uint8_t *
opcode)
643 if (pdu_len !=
sizeof(*rsp)) {
657 "Retrying operation %p", op);
671 uint8_t *rsp_pdu = NULL;
672 uint16_t rsp_pdu_len = 0;
680 "Received unexpected ATT response");
698 if (req_opcode != op->
opcode)
705 rsp_pdu_len = pdu_len;
712 "Failed to handle response PDU; opcode: 0x%02x", opcode);
734 if (!op || pdu_len) {
736 "Received unexpected/invalid ATT confirmation");
765 return opcode == test_opcode;
812 "ATT failed to verify signature: 0x%02x", opcode);
845 notify->
callback(opcode, pdu, pdu_len,
865 struct bt_att *att = user_data;
870 bytes_read = read(att->
fd, att->
buf, att->
mtu);
889 "ATT response received: 0x%02x", opcode);
890 handle_rsp(att, opcode, pdu + 1, bytes_read - 1);
894 "ATT confirmation received: 0x%02x", opcode);
905 "Received request while another is "
906 "pending: 0x%02x", opcode);
925 "ATT PDU received: 0x%02x", opcode);
943 len =
sizeof(domain);
944 err = getsockopt(fd, SOL_SOCKET, SO_DOMAIN, &domain, &len);
953 err = getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &proto, &len);
1005 att->
buf = malloc(att->
mtu);
1060 __sync_fetch_and_add(&att->
ref_count, 1);
1070 if (__sync_sub_and_fetch(&att->
ref_count, 1))
1081 if (!att || !att->
io)
1165 if (!att || !att->
io)
1221 const void *pdu, uint16_t length,
1228 if (!att || !att->
io)
1275 return op->
id ==
id;
1347 if (err > 0 && err < UINT8_MAX)
1369 uint16_t handle,
int error)
1374 if (!att || !opcode)
1379 memset(&pdu, 0,
sizeof(pdu));
1396 if (!att || !callback || !att->
io)
1459 memset(&sec, 0,
sizeof(sec));
1480 memset(&sec, 0,
sizeof(sec));
1499 (*sign)->counter =
func;
1500 (*sign)->user_data = user_data;
1501 memcpy((*sign)->key, key, 16);
1529 return att->
crypto ?
true :
false;
#define BT_ERROR_OUT_OF_RANGE
void(* bt_att_destroy_func_t)(void *user_data)
void(* bt_att_disconnect_func_t)(int err, void *user_data)
#define BT_ATT_OP_HANDLE_VAL_CONF
#define BT_ATT_OP_READ_BY_TYPE_REQ
bool bt_att_set_remote_key(struct bt_att *att, uint8_t sign_key[16], bt_att_counter_func_t func, void *user_data)
void queue_foreach(struct queue *queue, queue_foreach_func_t function, void *user_data)
const struct queue_entry * queue_get_entries(struct queue *queue)
bool io_set_write_handler(struct io *io, io_callback_func_t callback, void *user_data, io_destroy_func_t destroy)
unsigned int next_reg_id
IDs for registered callbacks.
struct queue * disconn_list
List of disconnect handlers.
#define BT_ATT_OP_READ_RSP
#define BT_ATT_SECURITY_MEDIUM
#define BT_ATT_OP_READ_BY_TYPE_RSP
bool bt_att_cancel_all(struct bt_att *att)
#define BT_ATT_SECURITY_AUTO
struct io * io_new(int fd)
static bool is_io_l2cap_based(int fd)
#define BT_ATT_OP_SIGNED_WRITE_CMD
data structure to manage io
struct att_send_op * pending_ind
Pending indication state.
ssize_t io_send(struct io *io, const struct iovec *iov, int iovcnt)
struct sign_info * remote_sign
remote key structure pointer
void(* bt_att_debug_func_t)(const char *str, void *user_data)
bool bt_att_unregister_all(struct bt_att *att)
bt_att_destroy_func_t destroy
bool bt_att_unregister_disconnect(struct bt_att *att, unsigned int id)
bool io_set_close_on_destroy(struct io *io, bool do_close)
bool bt_att_set_local_key(struct bt_att *att, uint8_t sign_key[16], bt_att_counter_func_t func, void *user_data)
static uint8_t get_req_opcode(uint8_t rsp_opcode)
#define BT_ATT_OP_HANDLE_VAL_IND
#define BT_ERROR_ALREADY_IN_PROGRESS
bt_att_destroy_func_t destroy
void * queue_pop_head(struct queue *queue)
struct sign_info * local_sign
local key structure pointer
static bool match_notify_id(const void *a, const void *b)
#define ATT_OP_SIGNED_MASK
void util_hexdump(const char dir, const unsigned char *buf, size_t len, util_debug_func_t function, void *user_data)
#define BT_ATT_OP_READ_BLOB_REQ
static bool encode_pdu(struct bt_att *att, struct att_send_op *op, const void *pdu, uint16_t length)
#define BT_ATT_OP_PREP_WRITE_REQ
#define BT_ATT_OP_PREP_WRITE_RSP
static uint8_t att_ecode_from_error(int err)
static void wakeup_writer(struct bt_att *att)
static void handle_conf(struct bt_att *att, uint8_t *pdu, ssize_t pdu_len)
#define BT_ATT_OP_MTU_REQ
bool bt_att_unregister(struct bt_att *att, unsigned int id)
uint16_t mtu
actual number of bytes for pdu ATT exchange
#define BT_ATT_OP_WRITE_REQ
unsigned int next_send_id
IDs for "send" ops.
int ref_count
reference counter incremented by bt_att_ref, decremented by bt_att_unref
static bool match_op_id(const void *a, const void *b)
static enum att_op_type get_op_type(uint8_t opcode)
static void put_le16(uint16_t val, void *dst)
#define BT_ATT_OP_FIND_INFO_RSP
static bool disconnect_cb(struct io *io, void *user_data)
bool queue_isempty(struct queue *queue)
bool io_set_disconnect_handler(struct io *io, io_callback_func_t callback, void *user_data, io_destroy_func_t destroy)
bool writer_active
true if already engaged in write operation
static struct att_send_op * create_att_send_op(struct bt_att *att, uint8_t opcode, const void *pdu, uint16_t length, bt_att_response_func_t callback, void *user_data, bt_att_destroy_func_t destroy)
#define BT_ATT_OP_READ_BLOB_RSP
void io_destroy(struct io *io)
int io_sec_level
i/o seurity level: Only used for non-L2CAP
bool bt_att_has_crypto(struct bt_att *att)
struct bt_crypto * bt_crypto_new(void)
bool bt_att_set_mtu(struct bt_att *att, uint16_t mtu)
bool in_req
There's a pending incoming request.
#define BT_ATT_SECURITY_HIGH
#define BT_ATT_OP_WRITE_RSP
struct io * io
io structure for low level i/o (read and write)
#define BT_ATT_OP_READ_MULT_RSP
#define BT_ATT_ERROR_UNLIKELY
bool bt_att_set_debug(struct bt_att *att, bt_att_debug_func_t callback, void *user_data, bt_att_destroy_func_t destroy)
static struct att_send_op * pick_next_send_op(struct bt_att *att)
void queue_destroy(struct queue *queue, queue_destroy_func_t destroy)
static void cancel_att_send_op(struct att_send_op *op)
bool bt_att_set_security(struct bt_att *att, int level)
static const struct @0 att_opcode_type_table[]
static uint32_t get_le32(const void *ptr)
bool ext_signed
true, requires key signature
static bool timeout_cb(void *user_data)
bool bt_att_cancel(struct bt_att *att, unsigned int id)
static void handle_rsp(struct bt_att *att, uint8_t opcode, uint8_t *pdu, ssize_t pdu_len)
static void handle_notify(struct bt_att *att, uint8_t opcode, uint8_t *pdu, ssize_t pdu_len)
uint16_t bt_att_get_mtu(struct bt_att *att)
bool queue_push_tail(struct queue *queue, void *data)
struct queue * queue_new(void)
#define BT_ATT_OP_EXEC_WRITE_REQ
struct bt_att * bt_att_new(int fd, bool ext_signed)
#define BT_ATT_SIGNATURE_LEN
bool io_on_l2cap
true if an l2cap socket
bool bt_att_set_timeout_cb(struct bt_att *att, bt_att_timeout_func_t callback, void *user_data, bt_att_destroy_func_t destroy)
#define BT_ATT_OP_MTU_RSP
bt_att_destroy_func_t debug_destroy
data management function for debug
#define BT_ATT_OP_READ_BY_GRP_TYPE_REQ
bool bt_att_set_close_on_unref(struct bt_att *att, bool do_close)
unsigned int bt_att_send_error_rsp(struct bt_att *att, uint8_t opcode, uint16_t handle, int error)
bt_att_debug_func_t debug_callback
debug callback
#define BT_ATT_OP_ERROR_RSP
unsigned int queue_remove_all(struct queue *queue, queue_match_func_t function, void *user_data, queue_destroy_func_t destroy)
#define BT_ATT_OP_WRITE_CMD
bool io_set_read_handler(struct io *io, io_callback_func_t callback, void *user_data, io_destroy_func_t destroy)
bt_att_response_func_t callback
struct queue * notify_list
List of registered callbacks.
#define BT_ATT_OP_HANDLE_VAL_NOT
void util_debug(util_debug_func_t function, void *user_data, const char *format,...)
#define BT_ATT_OP_FIND_BY_TYPE_VAL_REQ
static void bt_att_free(struct bt_att *att)
bt_att_destroy_func_t timeout_destroy
timeout function to manage data context (house keeping)
bool bt_crypto_sign_att(struct bt_crypto *crypto, const uint8_t key[16], const uint8_t *m, uint16_t m_len, uint32_t sign_cnt, uint8_t signature[12])
#define ATT_TIMEOUT_INTERVAL
void(* bt_att_notify_func_t)(uint8_t opcode, const void *pdu, uint16_t length, void *user_data)
bool(* bt_att_counter_func_t)(uint32_t *sign_cnt, void *user_data)
static const struct @1 att_req_rsp_mapping_table[]
static bool change_security(struct bt_att *att, uint8_t ecode)
#define BT_ATT_OP_READ_MULT_REQ
static bool opcode_match(uint8_t opcode, uint8_t test_opcode)
static bool sign_set_key(struct sign_info **sign, uint8_t key[16], bt_att_counter_func_t func, void *user_data)
#define BT_ATT_ERROR_AUTHENTICATION
static bool can_read_data(struct io *io, void *user_data)
void * queue_remove_if(struct queue *queue, queue_match_func_t function, void *user_data)
struct att_send_op * pending_req
Pending request state.
#define BT_ATT_OP_READ_BY_GRP_TYPE_RSP
bt_att_timeout_func_t timeout_callback
timeout function for callback
#define BT_ATT_ALL_REQUESTS
#define BT_ATT_ERROR_INVALID_HANDLE
static void disconn_handler(void *data, void *user_data)
bt_att_destroy_func_t destroy
#define BT_ATT_DEFAULT_LE_MTU
int bt_att_get_security(struct bt_att *att)
void(* bt_att_response_func_t)(uint8_t opcode, const void *pdu, uint16_t length, void *user_data)
#define BT_ATT_ERROR_INSUFFICIENT_RESOURCES
void bt_crypto_unref(struct bt_crypto *crypto)
static void destroy_att_notify(void *data)
bt_att_counter_func_t counter
static void respond_not_supported(struct bt_att *att, uint8_t opcode)
#define BT_ATT_OP_FIND_BY_TYPE_VAL_RSP
bool io_shutdown(struct io *io)
#define BT_ATT_OP_EXEC_WRITE_RSP
struct bt_crypto * crypto
crypto structure
unsigned int timeout_add(unsigned int timeout, timeout_func_t func, void *user_data, timeout_destroy_func_t destroy)
struct queue_entry * next
static bool match_disconn_id(const void *a, const void *b)
bt_att_notify_func_t callback
static void destroy_att_disconn(void *data)
static bool can_write_data(struct io *io, void *user_data)
uint8_t * buf
buffer pointer
struct queue * write_queue
Queue of PDUs ready to send.
bt_att_disconnect_func_t callback
void(* bt_att_timeout_func_t)(unsigned int id, uint8_t opcode, void *user_data)
struct queue * ind_queue
Queued ATT protocol indications.
void timeout_remove(unsigned int id)
#define BT_ATT_ERROR_REQUEST_NOT_SUPPORTED
#define BT_ATT_OP_READ_REQ
#define BT_ATT_OP_FIND_INFO_REQ
static void destroy_att_send_op(void *data)
destroy att send operation calls the destroy callback with user_data as an argument free pdu data ...
static bool handle_error_rsp(struct bt_att *att, uint8_t *pdu, ssize_t pdu_len, uint8_t *opcode)
void * debug_data
user pointer for debug
unsigned int bt_att_register(struct bt_att *att, uint8_t opcode, bt_att_notify_func_t callback, void *user_data, bt_att_destroy_func_t destroy)
static void write_watch_destroy(void *user_data)
struct queue * req_queue
Queued ATT protocol requests.
unsigned int bt_att_register_disconnect(struct bt_att *att, bt_att_disconnect_func_t callback, void *user_data, bt_att_destroy_func_t destroy)
unsigned int bt_att_send(struct bt_att *att, uint8_t opcode, const void *pdu, uint16_t length, bt_att_response_func_t callback, void *user_data, bt_att_destroy_func_t destroy)
void bt_att_unref(struct bt_att *att)
int bt_att_get_fd(struct bt_att *att)
static bool handle_signed(struct bt_att *att, uint8_t opcode, uint8_t *pdu, ssize_t pdu_len)
struct bt_att * bt_att_ref(struct bt_att *att)
#define BT_ATT_ERROR_INSUFFICIENT_ENCRYPTION
bool queue_push_head(struct queue *queue, void *data)