static void handle_characteristic(struct gatt_db_attribute *attr, void *user_data) { struct gas *gas = user_data; uint16_t value_handle; bt_uuid_t uuid; if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle, NULL, NULL, &uuid)) { error("Failed to obtain characteristic data"); return; } if (uuid_cmp(GATT_CHARAC_DEVICE_NAME, &uuid)) handle_device_name(gas, value_handle); else if (uuid_cmp(GATT_CHARAC_APPEARANCE, &uuid)) handle_appearance(gas, value_handle); else { char uuid_str[MAX_LEN_UUID_STR]; /* TODO: Support peripheral privacy feature */ bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str)); DBG("Unsupported characteristic: %s", uuid_str); } }
static void resolve_included_uuid_cb(uint8_t status, const uint8_t *pdu, uint16_t len, gpointer user_data) { struct included_uuid_query *query = user_data; struct included_discovery *isd = query->isd; struct gatt_included *incl = query->included; unsigned int err = status; bt_uuid_t uuid; size_t buflen; uint8_t *buf; if (err) goto done; buf = g_attrib_get_buffer(isd->attrib, &buflen); if (dec_read_resp(pdu, len, buf, buflen) != 16) { err = ATT_ECODE_IO; goto done; } uuid = att_get_uuid128(buf); bt_uuid_to_string(&uuid, incl->uuid, sizeof(incl->uuid)); isd->includes = g_slist_append(isd->includes, incl); done: if (err) g_free(incl); if (isd->err == 0) isd->err = err; isd_unref(isd); g_free(query); }
static void print_uuid(const bt_uuid_t *uuid) { char uuid_str[MAX_LEN_UUID_STR]; bt_uuid_t uuid128; bt_uuid_to_uuid128(uuid, &uuid128); bt_uuid_to_string(&uuid128, uuid_str, sizeof(uuid_str)); printf("%s\n", uuid_str); }
static void print_uuid(const uint8_t uuid[16]) { char uuid_str[MAX_LEN_UUID_STR]; bt_uuid_t tmp; tmp.type = BT_UUID128; memcpy(tmp.value.u128.data, uuid, 16 * sizeof(uint8_t)); bt_uuid_to_string(&tmp, uuid_str, sizeof(uuid_str)); printf("%s\n", uuid_str); }
static gboolean characteristic_get_uuid(const GDBusPropertyTable *property, DBusMessageIter *iter, void *data) { char uuid[MAX_LEN_UUID_STR + 1]; const char *ptr = uuid; struct characteristic *chrc = data; bt_uuid_to_string(&chrc->uuid, uuid, sizeof(uuid)); dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &ptr); return TRUE; }
static void check_updated_characteristics(struct gatt_service *gatt) { DBusMessage *reply; DBusMessageIter iter, array_iter; GSList *l, *d; uint16_t count = 0; if (!att_device_connected(gatt)) return; INFO("%s",gatt->path); for (l = gatt->chars; l; l = l->next) { struct characteristic *chr = l->data; for (d = chr->descriptors; d; d = d->next, count++); if (count < chr->descriptor_count) { INFO("Not all chars are updated (%s)",chr->path); return; } } /* DEBUG ONLY */ for (l = gatt->chars; l; l = l->next) { struct characteristic *chr = l->data; for (d = chr->descriptors; d; d = d->next) { struct characteristic_descriptor *desc = d->data; char str[100]; bt_uuid_to_string(&desc->uuid,str,100); INFO("%s desc:%s handle:%02X",chr->path,str,desc->handle); } } /* END OF DEBUG ONLY */ reply = dbus_message_new_method_return(gatt->query->msg); dbus_message_iter_init_append(reply, &iter); dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter); for (l = gatt->chars; l; l = l->next) { struct characteristic *chr = l->data; dbus_message_iter_append_basic(&array_iter, DBUS_TYPE_OBJECT_PATH, &chr->path); } dbus_message_iter_close_container(&iter, &array_iter); g_dbus_send_message(gatt->conn, reply); INFO("dbus sent"); }
static void log_service_event(struct gatt_db_attribute *attr, const char *str) { char uuid_str[MAX_LEN_UUID_STR]; bt_uuid_t uuid; uint16_t start, end; gatt_db_attribute_get_service_uuid(attr, &uuid); bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str)); gatt_db_attribute_get_service_handles(attr, &start, &end); PRLOG("%s - UUID: %s start: 0x%04x end: 0x%04x\n", str, uuid_str, start, end); }
static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { struct att_data_list *list; guint8 format; int i; if (status != 0) { g_printerr("Discover all characteristic descriptors failed: " "%s\n", att_ecode2str(status)); goto done; } list = dec_find_info_resp(pdu, plen, &format); if (list == NULL) goto done; for (i = 0; i < list->num; i++) { char uuidstr[MAX_LEN_UUID_STR]; uint16_t handle; uint8_t *value; bt_uuid_t uuid; value = list->data[i]; handle = get_le16(value); if (format == ATT_FIND_INFO_RESP_FMT_16BIT) bt_uuid16_create(&uuid, get_le16(&value[2])); else { uint128_t u128; /* Converts from LE to BE byte order */ bswap_128(&value[2], &u128); bt_uuid128_create(&uuid, u128); } bt_uuid_to_string(&uuid, uuidstr, MAX_LEN_UUID_STR); g_print("handle = 0x%04x, uuid = %s\n", handle, uuidstr); } att_data_list_free(list); done: if (!opt_listen) g_main_loop_quit(event_loop); }
static struct gatt_included *included_from_buf(const uint8_t *buf, gsize len) { struct gatt_included *incl = g_new0(struct gatt_included, 1); incl->handle = get_le16(&buf[0]); incl->range.start = get_le16(&buf[2]); incl->range.end = get_le16(&buf[4]); if (len == 8) { bt_uuid_t uuid128; get_uuid128(BT_UUID16, &buf[6], &uuid128); bt_uuid_to_string(&uuid128, incl->uuid, sizeof(incl->uuid)); } return incl; }
static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { struct att_data_list *list; guint8 format; uint16_t handle = 0xffff; int i; if (status != 0) { resp_error(err_COMM_ERR); // Todo: status return; } list = dec_find_info_resp(pdu, plen, &format); if (list == NULL) { resp_error(err_NOT_FOUND); // Todo: what does this mean? return; } resp_begin(rsp_DESCRIPTORS); for (i = 0; i < list->num; i++) { char uuidstr[MAX_LEN_UUID_STR]; uint8_t *value; bt_uuid_t uuid; value = list->data[i]; handle = att_get_u16(value); if (format == 0x01) uuid = att_get_uuid16(&value[2]); else uuid = att_get_uuid128(&value[2]); bt_uuid_to_string(&uuid, uuidstr, MAX_LEN_UUID_STR); send_uint(tag_HANDLE, handle); send_str (tag_UUID, uuidstr); } resp_end(); att_data_list_free(list); if (handle != 0xffff && handle < end) gatt_discover_char_desc(attrib, handle + 1, end, char_desc_cb, NULL); }
static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { struct att_data_list *list; guint8 format; int i; if (status != 0) { printf("Discover all characteristic descriptors failed: " "%s\n", att_ecode2str(status)); goto done; } list = dec_find_info_resp(pdu, plen, &format); if (list == NULL) goto done; printf("\n"); for (i = 0; i < list->num; i++) { char uuidstr[MAX_LEN_UUID_STR]; uint16_t handle; uint8_t *value; bt_uuid_t uuid; value = list->data[i]; handle = att_get_u16(value); if (format == 0x01) uuid = att_get_uuid16(&value[2]); else uuid = att_get_uuid128(&value[2]); bt_uuid_to_string(&uuid, uuidstr, MAX_LEN_UUID_STR); printf("handle: 0x%04x, uuid: %s\n", handle, uuidstr); } att_data_list_free(list); done: printf("\n%s", get_prompt()); fflush(stdout); }
static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { struct att_data_list *list; guint8 format; uint16_t handle = 0xffff; int i; if (status != 0) { rl_printf("Discover descriptors finished: %s\n", att_ecode2str(status)); return; } list = dec_find_info_resp(pdu, plen, &format); if (list == NULL) return; for (i = 0; i < list->num; i++) { char uuidstr[MAX_LEN_UUID_STR]; uint8_t *value; bt_uuid_t uuid; value = list->data[i]; handle = att_get_u16(value); if (format == 0x01) uuid = att_get_uuid16(&value[2]); else uuid = att_get_uuid128(&value[2]); bt_uuid_to_string(&uuid, uuidstr, MAX_LEN_UUID_STR); rl_printf("handle: 0x%04x, uuid: %s\n", handle, uuidstr); } att_data_list_free(list); if (handle != 0xffff && handle < end) gatt_discover_char_desc(attrib, handle + 1, end, char_desc_cb, NULL); }
static void handle_characteristic(struct gatt_db_attribute *attr, void *user_data) { struct btd_device *device = user_data; uint16_t value_handle; bt_uuid_t uuid, pnpid_uuid; bt_string_to_uuid(&pnpid_uuid, PNPID_UUID); if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle, NULL, NULL, &uuid)) { error("Failed to obtain characteristic data"); return; } if (bt_uuid_cmp(&pnpid_uuid, &uuid) == 0) handle_pnpid(device, value_handle); else { char uuid_str[MAX_LEN_UUID_STR]; bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str)); DBG("Unsupported characteristic: %s", uuid_str); } }
static void store_attribute(struct gatt_service *gatt, uint16_t handle, uint16_t type, uint8_t *value, gsize len) { bdaddr_t sba, dba; bt_uuid_t uuid; char *str, *tmp; guint i; str = g_malloc0(MAX_LEN_UUID_STR + len * 2 + 1); bt_uuid16_create(&uuid, type); bt_uuid_to_string(&uuid, str, MAX_LEN_UUID_STR); str[MAX_LEN_UUID_STR - 1] = '#'; for (i = 0, tmp = str + MAX_LEN_UUID_STR; i < len; i++, tmp += 2) sprintf(tmp, "%02X", value[i]); gatt_get_address(gatt, &sba, &dba); write_device_attribute(&sba, &dba, handle, str); g_free(str); }
int gattlib_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n) { return bt_uuid_to_string(uuid, str, n); }
static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen, gpointer user_data) { struct discover_char *dc = user_data; struct att_data_list *list; unsigned int i, err = ATT_ECODE_ATTR_NOT_FOUND; uint16_t last = 0; if (status) { err = status; goto done; } list = dec_read_by_type_resp(ipdu, iplen); if (list == NULL) { err = ATT_ECODE_IO; goto done; } for (i = 0; i < list->num; i++) { uint8_t *value = list->data[i]; struct gatt_char *chars; bt_uuid_t uuid; last = att_get_u16(value); if (list->len == 7) { bt_uuid_t uuid16 = att_get_uuid16(&value[5]); bt_uuid_to_uuid128(&uuid16, &uuid); } else uuid = att_get_uuid128(&value[5]); if (dc->uuid && bt_uuid_cmp(dc->uuid, &uuid)) continue; chars = g_try_new0(struct gatt_char, 1); if (!chars) { err = ATT_ECODE_INSUFF_RESOURCES; goto done; } chars->handle = last; chars->properties = value[2]; chars->value_handle = att_get_u16(&value[3]); bt_uuid_to_string(&uuid, chars->uuid, sizeof(chars->uuid)); dc->characteristics = g_slist_append(dc->characteristics, chars); } att_data_list_free(list); if (last != 0 && (last + 1 < dc->end)) { bt_uuid_t uuid; guint16 oplen; size_t buflen; uint8_t *buf; buf = g_attrib_get_buffer(dc->attrib, &buflen); bt_uuid16_create(&uuid, GATT_CHARAC_UUID); oplen = enc_read_by_type_req(last + 1, dc->end, &uuid, buf, buflen); if (oplen == 0) return; g_attrib_send(dc->attrib, 0, buf, oplen, char_discovered_cb, dc, NULL); return; } done: err = (dc->characteristics ? 0 : err); dc->cb(dc->characteristics, err, dc->user_data); discover_char_free(dc); }
static void primary_all_cb(guint8 status, const guint8 *ipdu, guint16 iplen, gpointer user_data) { struct discover_primary *dp = user_data; struct att_data_list *list; unsigned int i, err; uint16_t start, end; if (status) { err = status == ATT_ECODE_ATTR_NOT_FOUND ? 0 : status; goto done; } list = dec_read_by_grp_resp(ipdu, iplen); if (list == NULL) { err = ATT_ECODE_IO; goto done; } for (i = 0, end = 0; i < list->num; i++) { const uint8_t *data = list->data[i]; struct gatt_primary *primary; bt_uuid_t uuid; start = att_get_u16(&data[0]); end = att_get_u16(&data[2]); if (list->len == 6) { bt_uuid_t uuid16 = att_get_uuid16(&data[4]); bt_uuid_to_uuid128(&uuid16, &uuid); } else if (list->len == 20) { uuid = att_get_uuid128(&data[4]); } else { /* Skipping invalid data */ continue; } primary = g_try_new0(struct gatt_primary, 1); if (!primary) { att_data_list_free(list); err = ATT_ECODE_INSUFF_RESOURCES; goto done; } primary->range.start = start; primary->range.end = end; bt_uuid_to_string(&uuid, primary->uuid, sizeof(primary->uuid)); dp->primaries = g_slist_append(dp->primaries, primary); } att_data_list_free(list); err = 0; if (end != 0xffff) { size_t buflen; uint8_t *buf = g_attrib_get_buffer(dp->attrib, &buflen); guint16 oplen = encode_discover_primary(end + 1, 0xffff, NULL, buf, buflen); g_attrib_send(dp->attrib, 0, buf, oplen, primary_all_cb, dp, NULL); return; } done: dp->cb(dp->primaries, err, dp->user_data); discover_primary_free(dp); }
void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen, gpointer user_data) { struct att_data_list *list = NULL; guint8 format; uint16_t handle = 0xffff; int i; char uuid_str[MAX_LEN_UUID_STR]; uint8_t *value; printf_dbg("[CB] IN char_desc_cb\n"); if (status) { cb_ret_val = BL_REQUEST_FAIL_ERROR; sprintf(cb_ret_msg, "Characteristic descriptor " "callback: Failure: %s\n", att_ecode2str(status)); goto exit; } list = dec_find_info_resp(pdu, plen, &format); if (list == NULL) { cb_ret_val = BL_NO_ERROR; strcpy(cb_ret_msg, "Characteristic descriptor callback: Nothing found\n"); goto exit; } for (i = 0; i < list->num; i++) { bt_uuid_t uuid; value = list->data[i]; handle = att_get_u16(value); if (format == 0x01) uuid = att_get_uuid16(&value[2]); else uuid = att_get_uuid128(&value[2]); bt_uuid_to_string(&uuid, uuid_str, MAX_LEN_UUID_STR); if (strcmp(uuid_str, GATT_PRIM_SVC_UUID_STR) && strcmp(uuid_str, GATT_SND_SVC_UUID_STR) && strcmp(uuid_str, GATT_INCLUDE_UUID_STR) && strcmp(uuid_str, GATT_CHARAC_UUID_STR)) { bl_desc_t *bl_desc = bl_desc_new(uuid_str, handle); if (bl_desc == NULL) { cb_ret_val = BL_MALLOC_ERROR; strcpy(cb_ret_msg, "Characteristic descriptor callback: Malloc " "error\n"); goto exit; } if (bl_desc_list == NULL) { bl_desc_list = g_slist_alloc(); if (bl_desc_list == NULL) { cb_ret_val = BL_MALLOC_ERROR; strcpy(cb_ret_msg, "Characteristic descriptor callback: Malloc " "error\n"); goto exit; } bl_desc_list->data = bl_desc; } else { bl_desc_list = g_slist_append(bl_desc_list, bl_desc); } } else { printf_dbg("Reach end of descriptor list\n"); goto exit; } } if ((handle != 0xffff) && (handle < end_handle_cb)) { printf_dbg("[CB] OUT with asking for a new request\n"); if (gatt_discover_char_desc(attrib, handle + 1, end_handle_cb, char_desc_cb, NULL)) { goto next; } cb_ret_val = BL_SEND_REQUEST_ERROR; strcpy(cb_ret_msg, "Unable to send request\n"); } exit: if (bl_desc_list) { // Return what we got if we add something cb_ret_val = BL_NO_ERROR; cb_ret_pointer = bl_desc_list; } bl_desc_list = NULL; g_mutex_unlock(pending_callback); next: if (list) att_data_list_free(list); printf_dbg("[CB] OUT char_desc_cb\n"); }
static void desc_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen, gpointer user_data) { struct discover_desc *dd = user_data; struct att_data_list *list; unsigned int i, err = 0; guint8 format; uint16_t last = 0xffff; uint8_t type; gboolean uuid_found = FALSE; if (status == ATT_ECODE_ATTR_NOT_FOUND) { err = dd->descriptors ? 0 : status; goto done; } if (status) { err = status; goto done; } list = dec_find_info_resp(ipdu, iplen, &format); if (!list) { err = ATT_ECODE_IO; goto done; } if (format == ATT_FIND_INFO_RESP_FMT_16BIT) type = BT_UUID16; else type = BT_UUID128; for (i = 0; i < list->num; i++) { uint8_t *value = list->data[i]; struct gatt_desc *desc; bt_uuid_t uuid128; last = get_le16(value); get_uuid128(type, &value[2], &uuid128); if (dd->uuid) { if (bt_uuid_cmp(dd->uuid, &uuid128)) continue; else uuid_found = TRUE; } desc = g_try_new0(struct gatt_desc, 1); if (!desc) { att_data_list_free(list); err = ATT_ECODE_INSUFF_RESOURCES; goto done; } bt_uuid_to_string(&uuid128, desc->uuid, sizeof(desc->uuid)); desc->handle = last; if (type == BT_UUID16) desc->uuid16 = get_le16(&value[2]); dd->descriptors = g_slist_append(dd->descriptors, desc); if (uuid_found) break; } att_data_list_free(list); /* * If last handle is lower from previous start handle then it is smth * wrong. Let's stop search, otherwise we might enter infinite loop. */ if (last < dd->start) { err = ATT_ECODE_UNLIKELY; goto done; } dd->start = last + 1; if (last < dd->end && !uuid_found) { guint16 oplen; size_t buflen; uint8_t *buf; buf = g_attrib_get_buffer(dd->attrib, &buflen); oplen = enc_find_info_req(dd->start, dd->end, buf, buflen); if (oplen == 0) return; g_attrib_send(dd->attrib, dd->id, buf, oplen, desc_discovered_cb, discover_desc_ref(dd), discover_desc_unref); return; } done: dd->cb(err, dd->descriptors, dd->user_data); }
static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen, gpointer user_data) { struct discover_char *dc = user_data; struct att_data_list *list; unsigned int i, err = 0; uint16_t last = 0; uint8_t type; /* We have all the characteristic now, lets send it up */ if (status == ATT_ECODE_ATTR_NOT_FOUND) { err = dc->characteristics ? 0 : status; goto done; } if (status) { err = status; goto done; } list = dec_read_by_type_resp(ipdu, iplen); if (list == NULL) { err = ATT_ECODE_IO; goto done; } if (list->len == 7) type = BT_UUID16; else type = BT_UUID128; for (i = 0; i < list->num; i++) { uint8_t *value = list->data[i]; struct gatt_char *chars; bt_uuid_t uuid128; last = get_le16(value); get_uuid128(type, &value[5], &uuid128); if (dc->uuid && bt_uuid_cmp(dc->uuid, &uuid128)) continue; chars = g_try_new0(struct gatt_char, 1); if (!chars) { att_data_list_free(list); err = ATT_ECODE_INSUFF_RESOURCES; goto done; } chars->handle = last; chars->properties = value[2]; chars->value_handle = get_le16(&value[3]); bt_uuid_to_string(&uuid128, chars->uuid, sizeof(chars->uuid)); dc->characteristics = g_slist_append(dc->characteristics, chars); } att_data_list_free(list); /* * If last handle is lower from previous start handle then it is smth * wrong. Let's stop search, otherwise we might enter infinite loop. */ if (last < dc->start) { err = ATT_ECODE_UNLIKELY; goto done; } dc->start = last + 1; if (last != 0 && (dc->start < dc->end)) { bt_uuid_t uuid; guint16 oplen; size_t buflen; uint8_t *buf; buf = g_attrib_get_buffer(dc->attrib, &buflen); bt_uuid16_create(&uuid, GATT_CHARAC_UUID); oplen = enc_read_by_type_req(dc->start, dc->end, &uuid, buf, buflen); if (oplen == 0) return; g_attrib_send(dc->attrib, dc->id, buf, oplen, char_discovered_cb, discover_char_ref(dc), discover_char_unref); return; } done: dc->cb(err, dc->characteristics, dc->user_data); }
static void primary_all_cb(guint8 status, const guint8 *ipdu, guint16 iplen, gpointer user_data) { struct discover_primary *dp = user_data; struct att_data_list *list; unsigned int i, err; uint16_t start, end; uint8_t type; if (status) { err = status == ATT_ECODE_ATTR_NOT_FOUND ? 0 : status; goto done; } list = dec_read_by_grp_resp(ipdu, iplen); if (list == NULL) { err = ATT_ECODE_IO; goto done; } if (list->len == 6) type = BT_UUID16; else if (list->len == 20) type = BT_UUID128; else { att_data_list_free(list); err = ATT_ECODE_INVALID_PDU; goto done; } for (i = 0, end = 0; i < list->num; i++) { const uint8_t *data = list->data[i]; struct gatt_primary *primary; bt_uuid_t uuid128; start = get_le16(&data[0]); end = get_le16(&data[2]); get_uuid128(type, &data[4], &uuid128); primary = g_try_new0(struct gatt_primary, 1); if (!primary) { att_data_list_free(list); err = ATT_ECODE_INSUFF_RESOURCES; goto done; } primary->range.start = start; primary->range.end = end; bt_uuid_to_string(&uuid128, primary->uuid, sizeof(primary->uuid)); dp->primaries = g_slist_append(dp->primaries, primary); } att_data_list_free(list); err = 0; /* * If last handle is lower from previous start handle then it is smth * wrong. Let's stop search, otherwise we might enter infinite loop. */ if (end < dp->start) { err = ATT_ECODE_UNLIKELY; goto done; } dp->start = end + 1; if (end != 0xffff) { size_t buflen; uint8_t *buf = g_attrib_get_buffer(dp->attrib, &buflen); guint16 oplen = encode_discover_primary(dp->start, 0xffff, NULL, buf, buflen); g_attrib_send(dp->attrib, dp->id, buf, oplen, primary_all_cb, discover_primary_ref(dp), discover_primary_unref); return; } done: dp->cb(err, dp->primaries, dp->user_data); }