diff --git a/android/gatt.c b/android/gatt.c
index 4a28b29..b367eef 100644
--- a/android/gatt.c
+++ b/android/gatt.c
int length;
uint8_t *value;
uint16_t offset;
+
+ uint8_t *filter_value;
+ uint16_t filter_vlen;
};
static void destroy_pending_request(void *data)
struct pending_request *entry = data;
free(entry->value);
+ free(entry->filter_value);
free(entry);
}
HAL_OP_GATT_SERVER_ADD_INC_SERVICE, status);
}
+static bool is_service(const bt_uuid_t *type)
+{
+ bt_uuid_t uuid;
+
+ bt_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+ if (!bt_uuid_cmp(&uuid, type))
+ return true;
+
+ bt_uuid16_create(&uuid, GATT_SND_SVC_UUID);
+ if (!bt_uuid_cmp(&uuid, type))
+ return true;
+
+ return false;
+}
+
static void send_dev_pending_response(struct gatt_device *device,
uint8_t opcode)
{
break;
}
+ case ATT_OP_FIND_BY_TYPE_REQ: {
+ GSList *list = NULL;
+
+ val = queue_pop_head(device->pending_requests);
+ while (val) {
+ struct att_range *range;
+ const bt_uuid_t *type;
+
+ /* Its find by type and value - filter by value here */
+ if ((val->length != val->filter_vlen) ||
+ memcmp(val->value, val->filter_value,
+ val->length)) {
+
+ destroy_pending_request(val);
+ val = queue_pop_head(device->pending_requests);
+ continue;
+ }
+
+ range = new0(struct att_range, 1);
+ if (!range) {
+ destroy_pending_request(val);
+ error = ATT_ECODE_INSUFF_RESOURCES;
+ break;
+ }
+
+ range->start = val->handle;
+ range->end = range->start;
+
+ /* Get proper end handle if its group type */
+ type = gatt_db_get_attribute_type(gatt_db, val->handle);
+ if (is_service(type))
+ range->end = gatt_db_get_end_handle(gatt_db,
+ val->handle);
+
+ list = g_slist_append(list, range);
+
+ destroy_pending_request(val);
+ val = queue_pop_head(device->pending_requests);
+ }
+
+ if (list && !error)
+ len = enc_find_by_type_resp(list, rsp, sizeof(rsp));
+ else
+ error = ATT_ECODE_ATTR_NOT_FOUND;
+
+ g_slist_free_full(list, free);
+
+ break;
+ }
default:
break;
}
sizeof(struct hal_cmd_gatt_server_send_response) },
};
-
static uint8_t read_by_group_type(const uint8_t *cmd, uint16_t cmd_len,
uint8_t *rsp, size_t rsp_size,
uint16_t *length,
return 0;
}
+static uint8_t find_by_type_request(const uint8_t *cmd, uint16_t cmd_len,
+ struct gatt_device *device)
+{
+ uint8_t search_value[ATT_DEFAULT_LE_MTU];
+ size_t search_vlen;
+ uint16_t start, end;
+ uint16_t handle;
+ struct queue *q;
+ bt_uuid_t uuid;
+ uint16_t len;
+
+ DBG("");
+
+ len = dec_find_by_type_req(cmd, cmd_len, &start, &end, &uuid,
+ search_value, &search_vlen);
+ if (!len)
+ return ATT_ECODE_INVALID_PDU;
+
+ q = queue_new();
+ if (!q)
+ return ATT_ECODE_UNLIKELY;
+
+ gatt_db_find_by_type(gatt_db, start, end, &uuid, q);
+
+ handle = PTR_TO_UINT(queue_pop_head(q));
+ while (handle) {
+ struct pending_request *data;
+
+ data = new0(struct pending_request, 1);
+ if (!data) {
+ queue_destroy(q, NULL);
+ return ATT_ECODE_INSUFF_RESOURCES;
+ }
+
+ data->filter_value = malloc0(search_vlen);
+ if (!data) {
+ destroy_pending_request(data);
+ queue_destroy(q, NULL);
+ return ATT_ECODE_INSUFF_RESOURCES;
+ }
+
+ data->handle = handle;
+ 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);
+
+ process_dev_pending_requests(device, ATT_OP_FIND_BY_TYPE_REQ);
+
+ /* Send if no response_data elements left to be filled by callbacks */
+ if (!queue_find(device->pending_requests, match_pending_dev_request,
+ NULL))
+ send_dev_pending_response(device, cmd[0]);
+
+ return 0;
+}
+
static uint8_t write_cmd_request(const uint8_t *cmd, uint16_t cmd_len,
struct gatt_device *dev)
{
if (!status)
return;
break;
+ case ATT_OP_FIND_BY_TYPE_REQ:
+ status = find_by_type_request(ipdu, len, dev);
+ break;
case ATT_OP_EXEC_WRITE_REQ:
/* TODO */
- case ATT_OP_FIND_BY_TYPE_REQ:
case ATT_OP_HANDLE_CNF:
case ATT_OP_HANDLE_IND:
case ATT_OP_HANDLE_NOTIFY: