static int uuid_to_le(const bt_uuid_t *uuid, uint8_t *dst) { bt_uuid_t uuid128; if (uuid->type == BT_UUID16) { put_le16(uuid->value.u16, dst); return bt_uuid_len(uuid); } bt_uuid_to_uuid128(uuid, &uuid128); bswap_128(&uuid128.value.u128, dst); return bt_uuid_len(&uuid128); }
static guint16 encode_discover_primary(uint16_t start, uint16_t end, bt_uuid_t *uuid, uint8_t *pdu, size_t len) { bt_uuid_t prim; guint16 plen; bt_uuid16_create(&prim, GATT_PRIM_SVC_UUID); if (uuid == NULL) { /* Discover all primary services */ plen = enc_read_by_grp_req(start, end, &prim, pdu, len); } else { uint8_t value[16]; size_t vlen; /* Discover primary service by service UUID */ put_uuid_le(uuid, value); vlen = bt_uuid_len(uuid); plen = enc_find_by_type_req(start, end, &prim, value, vlen, pdu, len); } return plen; }
struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid) { struct btd_attribute *attr; uint16_t len = bt_uuid_len(uuid); uint8_t value[len]; /* * Service DECLARATION * * TYPE ATTRIBUTE VALUE * +-------+---------------------------------+ * |0x2800 | 0xYYYY... | * | (1) | (2) | * +------+----------------------------------+ * (1) - 2 octets: Primary/Secondary Service UUID * (2) - 2 or 16 octets: Service UUID */ /* Set attribute value */ put_uuid_le(uuid, value); attr = new_const_attribute(&primary_uuid, value, len); if (!attr) return NULL; if (local_database_add(next_handle, attr) < 0) { free(attr); return NULL; } /* TODO: missing overflow checking */ next_handle = next_handle + 1; return attr; }
static bool encode_find_info_rsp(struct gatt_db *db, struct queue *q, uint16_t mtu, uint8_t *pdu, uint16_t *len) { uint16_t handle; struct gatt_db_attribute *attr; const bt_uuid_t *type; int uuid_len, cur_uuid_len; int iter = 0; *len = 0; while (queue_peek_head(q)) { attr = queue_pop_head(q); handle = gatt_db_attribute_get_handle(attr); type = gatt_db_attribute_get_type(attr); if (!handle || !type) return false; cur_uuid_len = bt_uuid_len(type); if (iter == 0) { switch (cur_uuid_len) { case 2: uuid_len = 2; pdu[0] = 0x01; break; case 4: case 16: uuid_len = 16; pdu[0] = 0x02; break; default: return false; } iter++; } else if (cur_uuid_len != uuid_len) break; if (iter + uuid_len + 2 > mtu - 1) break; put_le16(handle, pdu + iter); bt_uuid_to_le(type, pdu + iter + 2); iter += uuid_len + 2; } *len = iter; return true; }
struct btd_attribute *btd_gatt_add_char(const bt_uuid_t *uuid, uint8_t properties, btd_attr_read_t read_cb, btd_attr_write_t write_cb) { struct btd_attribute *char_decl, *char_value = NULL; /* Attribute value length */ uint16_t len = 1 + 2 + bt_uuid_len(uuid); uint8_t value[len]; /* * Characteristic DECLARATION * * TYPE ATTRIBUTE VALUE * +-------+---------------------------------+ * |0x2803 | 0xXX 0xYYYY 0xZZZZ... | * | (1) | (2) (3) (4) | * +------+----------------------------------+ * (1) - 2 octets: Characteristic declaration UUID * (2) - 1 octet : Properties * (3) - 2 octets: Handle of the characteristic Value * (4) - 2 or 16 octets: Characteristic UUID */ value[0] = properties; /* * Since we don't know yet the characteristic value attribute * handle, we skip and set it later. */ put_uuid_le(uuid, &value[3]); char_decl = new_const_attribute(&chr_uuid, value, len); if (!char_decl) goto fail; char_value = new_attribute(uuid, read_cb, write_cb); if (!char_value) goto fail; if (local_database_add(next_handle, char_decl) < 0) goto fail; next_handle = next_handle + 1; /* * Characteristic VALUE * * TYPE ATTRIBUTE VALUE * +----------+---------------------------------+ * |0xZZZZ... | 0x... | * | (1) | (2) | * +----------+---------------------------------+ * (1) - 2 or 16 octets: Characteristic UUID * (2) - N octets: Value is read dynamically from the service * implementation (external entity). */ if (local_database_add(next_handle, char_value) < 0) /* TODO: remove declaration */ goto fail; next_handle = next_handle + 1; /* * Update characteristic value handle in characteristic declaration * attribute. For local attributes, we can assume that the handle * representing the characteristic value will get the next available * handle. However, for remote attribute this assumption is not valid. */ put_le16(char_value->handle, &char_decl->value[1]); return char_value; fail: free(char_decl); free(char_value); return NULL; }