From: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
To: linux-bluetooth@vger.kernel.org
Subject: [PATCH BlueZ v6 22/23] attrib: Remove GAttrib and gatttool
Date: Mon, 28 Sep 2026 16:00:28 -0400 [thread overview]
Message-ID: <20260928200031.1209311-23-luiz.dentz@gmail.com> (raw)
In-Reply-To: <20260928200031.1209311-1-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
GAttrib has no users left besides the deprecated gatttool, which is
replaced by the gatt submenu of bluetoothctl and btgatt-client, so
remove both along with unit/test-gattrib and what is left unused of
attrib/gatt.c, only keeping struct gatt_primary and gatt_parse_record
which are still used by bluetoothd.
Assisted-by: OpenCode:claude-opus-5.5
---
.gitignore | 2 -
Makefile.am | 11 +-
Makefile.tools | 12 -
attrib/gatt.c | 1150 +-----------------------------------------
attrib/gatt.h | 89 ----
attrib/gattrib.c | 473 -----------------
attrib/gattrib.h | 65 ---
attrib/gatttool.c | 612 ----------------------
attrib/gatttool.h | 17 -
attrib/interactive.c | 1020 -------------------------------------
attrib/utils.c | 110 ----
unit/test-gattrib.c | 552 --------------------
12 files changed, 3 insertions(+), 4110 deletions(-)
delete mode 100644 attrib/gattrib.c
delete mode 100644 attrib/gattrib.h
delete mode 100644 attrib/gatttool.c
delete mode 100644 attrib/gatttool.h
delete mode 100644 attrib/interactive.c
delete mode 100644 attrib/utils.c
delete mode 100644 unit/test-gattrib.c
diff --git a/.gitignore b/.gitignore
index a52e6eb1b9d8..06b24735df45 100644
--- a/.gitignore
+++ b/.gitignore
@@ -45,7 +45,6 @@ tools/97-hid2hci.rules
profiles/cups/bluetooth
profiles/iap/iapd
-attrib/gatttool
tools/avinfo
tools/bccmd
tools/hwdb
@@ -175,7 +174,6 @@ unit/test-avctp
unit/test-avrcp
unit/test-gatt
unit/test-midi
-unit/test-gattrib
unit/test-mesh-crypto
unit/test-micp
unit/test-vcp
diff --git a/Makefile.am b/Makefile.am
index 015c3c318528..4ce15dbf083a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -287,8 +287,7 @@ src_libshared_ell_la_CFLAGS = $(AM_CFLAGS)
endif
attrib_sources = attrib/att.h attrib/att-database.h attrib/att.c \
- attrib/gatt.h attrib/gatt.c \
- attrib/gattrib.h attrib/gattrib.c
+ attrib/gatt.h attrib/gatt.c
btio_sources = btio/btio.h btio/btio.c
@@ -777,14 +776,6 @@ unit_test_hog_SOURCES = unit/test-hog.c
unit_test_hog_LDADD = src/libshared-glib.la \
lib/libbluetooth-internal.la $(GLIB_LIBS)
-unit_tests += unit/test-gattrib
-
-unit_test_gattrib_SOURCES = unit/test-gattrib.c attrib/gattrib.c \
- $(btio_sources) src/log.h src/log.c
-unit_test_gattrib_LDADD = src/libshared-glib.la \
- lib/libbluetooth-internal.la \
- $(GLIB_LIBS) $(DBUS_LIBS) -ldl -lrt
-
unit_tests += unit/test-bap
unit_test_bap_SOURCES = unit/test-bap.c
diff --git a/Makefile.tools b/Makefile.tools
index 671b40fb0e42..f0ed20969e7e 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -514,18 +514,6 @@ tools_btmgmt_SOURCES = tools/btmgmt.c src/uuid-helper.c client/display.c \
client/mgmt.c
tools_btmgmt_LDADD = lib/libbluetooth-internal.la src/libshared-glib.la \
$(GLIB_LIBS) -lreadline
-if DEPRECATED
-noinst_PROGRAMS += attrib/gatttool
-
-attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \
- attrib/gattrib.c btio/btio.c \
- attrib/gatttool.h attrib/interactive.c \
- attrib/utils.c src/log.c client/display.c \
- client/display.h
-attrib_gatttool_LDADD = lib/libbluetooth-internal.la \
- src/libshared-glib.la $(GLIB_LIBS) -lreadline
-
-endif
endif
if CUPS
diff --git a/attrib/gatt.c b/attrib/gatt.c
index 71367c083fc4..335094f37b09 100644
--- a/attrib/gatt.c
+++ b/attrib/gatt.c
@@ -15,1164 +15,18 @@
#include <stdint.h>
#include <stdlib.h>
+#include <string.h>
#include <glib.h>
+#include "bluetooth/bluetooth.h"
#include "bluetooth/sdp.h"
#include "bluetooth/sdp_lib.h"
#include "bluetooth/uuid.h"
-#include "src/shared/util.h"
#include "att.h"
-#include "gattrib.h"
#include "gatt.h"
-struct discover_primary {
- int ref;
- GAttrib *attrib;
- unsigned int id;
- bt_uuid_t uuid;
- uint16_t start;
- GSList *primaries;
- gatt_cb_t cb;
- void *user_data;
-};
-
-/* Used for the Included Services Discovery (ISD) procedure */
-struct included_discovery {
- GAttrib *attrib;
- unsigned int id;
- int refs;
- int err;
- uint16_t start_handle;
- uint16_t end_handle;
- GSList *includes;
- gatt_cb_t cb;
- void *user_data;
-};
-
-struct included_uuid_query {
- struct included_discovery *isd;
- struct gatt_included *included;
-};
-
-struct discover_char {
- int ref;
- GAttrib *attrib;
- unsigned int id;
- bt_uuid_t *uuid;
- uint16_t end;
- uint16_t start;
- GSList *characteristics;
- gatt_cb_t cb;
- void *user_data;
-};
-
-struct discover_desc {
- int ref;
- GAttrib *attrib;
- unsigned int id;
- bt_uuid_t *uuid;
- uint16_t start;
- uint16_t end;
- GSList *descriptors;
- gatt_cb_t cb;
- void *user_data;
-};
-
-static void discover_primary_unref(void *data)
-{
- struct discover_primary *dp = data;
-
- dp->ref--;
-
- if (dp->ref > 0)
- return;
-
- g_slist_free_full(dp->primaries, g_free);
- g_attrib_unref(dp->attrib);
- g_free(dp);
-}
-
-static struct discover_primary *discover_primary_ref(
- struct discover_primary *dp)
-{
- dp->ref++;
-
- return dp;
-}
-
-static struct included_discovery *isd_ref(struct included_discovery *isd)
-{
- __sync_fetch_and_add(&isd->refs, 1);
-
- return isd;
-}
-
-static void isd_unref(struct included_discovery *isd)
-{
- if (__sync_sub_and_fetch(&isd->refs, 1) > 0)
- return;
-
- if (isd->err)
- isd->cb(isd->err, NULL, isd->user_data);
- else
- isd->cb(isd->err, isd->includes, isd->user_data);
-
- g_slist_free_full(isd->includes, g_free);
- g_attrib_unref(isd->attrib);
- g_free(isd);
-}
-
-static void discover_char_unref(void *data)
-{
- struct discover_char *dc = data;
-
- dc->ref--;
-
- if (dc->ref > 0)
- return;
-
- g_slist_free_full(dc->characteristics, g_free);
- g_attrib_unref(dc->attrib);
- free(dc->uuid);
- g_free(dc);
-}
-
-static struct discover_char *discover_char_ref(struct discover_char *dc)
-{
- dc->ref++;
-
- return dc;
-}
-
-static void discover_desc_unref(void *data)
-{
- struct discover_desc *dd = data;
-
- dd->ref--;
-
- if (dd->ref > 0)
- return;
-
- g_slist_free_full(dd->descriptors, g_free);
- g_attrib_unref(dd->attrib);
- free(dd->uuid);
- g_free(dd);
-}
-
-static struct discover_desc *discover_desc_ref(struct discover_desc *dd)
-{
- dd->ref++;
-
- return dd;
-}
-
-static void put_uuid_le(const bt_uuid_t *uuid, void *dst)
-{
- if (uuid->type == BT_UUID16)
- put_le16(uuid->value.u16, dst);
- else
- /* Convert from 128-bit BE to LE */
- bswap_128(&uuid->value.u128, dst);
-}
-
-static void get_uuid128(uint8_t type, const void *val, bt_uuid_t *uuid)
-{
- if (type == BT_UUID16) {
- bt_uuid_t uuid16;
-
- bt_uuid16_create(&uuid16, get_le16(val));
- bt_uuid_to_uuid128(&uuid16, uuid);
- } else {
- uint128_t u128;
-
- /* Convert from 128-bit LE to BE */
- bswap_128(val, &u128);
- bt_uuid128_create(uuid, u128);
- }
-}
-
-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;
-}
-
-static void primary_by_uuid_cb(guint8 status, const guint8 *ipdu,
- guint16 iplen, gpointer user_data)
-
-{
- struct discover_primary *dp = user_data;
- GSList *ranges, *last;
- struct att_range *range;
- uint8_t *buf;
- guint16 oplen;
- int err = 0;
- size_t buflen;
-
- if (status) {
- err = status == ATT_ECODE_ATTR_NOT_FOUND ? 0 : status;
- goto done;
- }
-
- ranges = dec_find_by_type_resp(ipdu, iplen);
- if (ranges == NULL)
- goto done;
-
- dp->primaries = g_slist_concat(dp->primaries, ranges);
-
- last = g_slist_last(ranges);
- range = last->data;
-
- if (range->end == 0xffff)
- goto done;
-
- /*
- * 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 (range->end < dp->start) {
- err = ATT_ECODE_UNLIKELY;
- goto done;
- }
-
- dp->start = range->end + 1;
-
- buf = g_attrib_get_buffer(dp->attrib, &buflen);
- oplen = encode_discover_primary(dp->start, 0xffff, &dp->uuid,
- buf, buflen);
-
- if (oplen == 0)
- goto done;
-
- g_attrib_send(dp->attrib, dp->id, buf, oplen, primary_by_uuid_cb,
- discover_primary_ref(dp), discover_primary_unref);
- return;
-
-done:
- dp->cb(err, dp->primaries, dp->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);
-}
-
-guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func,
- gpointer user_data)
-{
- struct discover_primary *dp;
- size_t buflen;
- uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
- GAttribResultFunc cb;
- guint16 plen;
-
- plen = encode_discover_primary(0x0001, 0xffff, uuid, buf, buflen);
- if (plen == 0)
- return 0;
-
- dp = g_try_new0(struct discover_primary, 1);
- if (dp == NULL)
- return 0;
-
- dp->attrib = g_attrib_ref(attrib);
- dp->cb = func;
- dp->user_data = user_data;
- dp->start = 0x0001;
-
- if (uuid) {
- dp->uuid = *uuid;
- cb = primary_by_uuid_cb;
- } else
- cb = primary_all_cb;
-
- dp->id = g_attrib_send(attrib, 0, buf, plen, cb,
- discover_primary_ref(dp),
- discover_primary_unref);
-
- return dp->id;
-}
-
-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 uuid128;
- 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;
- }
-
- get_uuid128(BT_UUID128, buf, &uuid128);
-
- bt_uuid_to_string(&uuid128, incl->uuid, sizeof(incl->uuid));
- isd->includes = g_slist_append(isd->includes, incl);
- query->included = NULL;
-
-done:
- if (isd->err == 0)
- isd->err = err;
-}
-
-static void inc_query_free(void *data)
-{
- struct included_uuid_query *query = data;
-
- isd_unref(query->isd);
- g_free(query->included);
- g_free(query);
-}
-
-static guint resolve_included_uuid(struct included_discovery *isd,
- struct gatt_included *incl)
-{
- struct included_uuid_query *query;
- size_t buflen;
- uint8_t *buf = g_attrib_get_buffer(isd->attrib, &buflen);
- guint16 oplen = enc_read_req(incl->range.start, buf, buflen);
-
- query = g_new0(struct included_uuid_query, 1);
- query->isd = isd_ref(isd);
- query->included = incl;
-
- return g_attrib_send(isd->attrib, query->isd->id, buf, oplen,
- resolve_included_uuid_cb, query,
- inc_query_free);
-}
-
-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 find_included_cb(uint8_t status, const uint8_t *pdu, uint16_t len,
- gpointer user_data);
-
-static guint find_included(struct included_discovery *isd, uint16_t start)
-{
- bt_uuid_t uuid;
- size_t buflen;
- uint8_t *buf = g_attrib_get_buffer(isd->attrib, &buflen);
- guint16 oplen;
-
- bt_uuid16_create(&uuid, GATT_INCLUDE_UUID);
- oplen = enc_read_by_type_req(start, isd->end_handle, &uuid,
- buf, buflen);
-
- /* If id != 0 it means we are in the middle of include search */
- if (isd->id)
- return g_attrib_send(isd->attrib, isd->id, buf, oplen,
- find_included_cb, isd_ref(isd),
- (GDestroyNotify) isd_unref);
-
- /* This is first call from the gattrib user */
- isd->id = g_attrib_send(isd->attrib, 0, buf, oplen, find_included_cb,
- isd_ref(isd), (GDestroyNotify) isd_unref);
-
- return isd->id;
-}
-
-static void find_included_cb(uint8_t status, const uint8_t *pdu, uint16_t len,
- gpointer user_data)
-{
- struct included_discovery *isd = user_data;
- uint16_t last_handle = isd->end_handle;
- unsigned int err = status;
- struct att_data_list *list;
- int i;
-
- if (err == ATT_ECODE_ATTR_NOT_FOUND)
- err = 0;
-
- if (status)
- goto done;
-
- list = dec_read_by_type_resp(pdu, len);
- if (list == NULL) {
- err = ATT_ECODE_IO;
- goto done;
- }
-
- if (list->len != 6 && list->len != 8) {
- err = ATT_ECODE_IO;
- att_data_list_free(list);
- goto done;
- }
-
- for (i = 0; i < list->num; i++) {
- struct gatt_included *incl;
-
- incl = included_from_buf(list->data[i], list->len);
- last_handle = incl->handle;
-
- /* 128 bit UUID, needs resolving */
- if (list->len == 6) {
- resolve_included_uuid(isd, incl);
- continue;
- }
-
- isd->includes = g_slist_append(isd->includes, incl);
- }
-
- 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_handle < isd->start_handle) {
- isd->err = ATT_ECODE_UNLIKELY;
- goto done;
- }
-
- isd->start_handle = last_handle + 1;
-
- if (last_handle < isd->end_handle)
- find_included(isd, isd->start_handle);
-
-done:
- if (isd->err == 0)
- isd->err = err;
-}
-
-unsigned int gatt_find_included(GAttrib *attrib, uint16_t start, uint16_t end,
- gatt_cb_t func, gpointer user_data)
-{
- struct included_discovery *isd;
-
- isd = g_new0(struct included_discovery, 1);
- isd->attrib = g_attrib_ref(attrib);
- isd->start_handle = start;
- isd->end_handle = end;
- isd->cb = func;
- isd->user_data = user_data;
-
- return find_included(isd, start);
-}
-
-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);
-}
-
-guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
- bt_uuid_t *uuid, gatt_cb_t func,
- gpointer user_data)
-{
- size_t buflen;
- uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
- struct discover_char *dc;
- bt_uuid_t type_uuid;
- guint16 plen;
-
- bt_uuid16_create(&type_uuid, GATT_CHARAC_UUID);
-
- plen = enc_read_by_type_req(start, end, &type_uuid, buf, buflen);
- if (plen == 0)
- return 0;
-
- dc = g_try_new0(struct discover_char, 1);
- if (dc == NULL)
- return 0;
-
- dc->attrib = g_attrib_ref(attrib);
- dc->cb = func;
- dc->user_data = user_data;
- dc->end = end;
- dc->start = start;
- dc->uuid = util_memdup(uuid, sizeof(bt_uuid_t));
-
- dc->id = g_attrib_send(attrib, 0, buf, plen, char_discovered_cb,
- discover_char_ref(dc), discover_char_unref);
-
- return dc->id;
-}
-
-guint gatt_read_char_by_uuid(GAttrib *attrib, uint16_t start, uint16_t end,
- bt_uuid_t *uuid, GAttribResultFunc func,
- gpointer user_data)
-{
- size_t buflen;
- uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
- guint16 plen;
-
- plen = enc_read_by_type_req(start, end, uuid, buf, buflen);
- if (plen == 0)
- return 0;
-
- return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
-}
-
-struct read_long_data {
- GAttrib *attrib;
- GAttribResultFunc func;
- gpointer user_data;
- guint8 *buffer;
- guint16 size;
- guint16 handle;
- guint id;
- int ref;
-};
-
-static void read_long_destroy(gpointer user_data)
-{
- struct read_long_data *long_read = user_data;
-
- if (__sync_sub_and_fetch(&long_read->ref, 1) > 0)
- return;
-
- g_attrib_unref(long_read->attrib);
-
- if (long_read->buffer != NULL)
- g_free(long_read->buffer);
-
- g_free(long_read);
-}
-
-static void read_blob_helper(guint8 status, const guint8 *rpdu, guint16 rlen,
- gpointer user_data)
-{
- struct read_long_data *long_read = user_data;
- uint8_t *buf;
- size_t buflen;
- guint8 *tmp;
- guint16 plen;
- guint id;
-
- if (status != 0 || rlen == 1) {
- status = 0;
- goto done;
- }
-
- tmp = g_try_realloc(long_read->buffer, long_read->size + rlen - 1);
-
- if (tmp == NULL) {
- status = ATT_ECODE_INSUFF_RESOURCES;
- goto done;
- }
-
- memcpy(&tmp[long_read->size], &rpdu[1], rlen - 1);
- long_read->buffer = tmp;
- long_read->size += rlen - 1;
-
- buf = g_attrib_get_buffer(long_read->attrib, &buflen);
- if (rlen < buflen)
- goto done;
-
- plen = enc_read_blob_req(long_read->handle, long_read->size - 1,
- buf, buflen);
- id = g_attrib_send(long_read->attrib, long_read->id, buf, plen,
- read_blob_helper, long_read, read_long_destroy);
-
- if (id != 0) {
- __sync_fetch_and_add(&long_read->ref, 1);
- return;
- }
-
- status = ATT_ECODE_IO;
-
-done:
- long_read->func(status, long_read->buffer, long_read->size,
- long_read->user_data);
-}
-
-static void read_char_helper(guint8 status, const guint8 *rpdu,
- guint16 rlen, gpointer user_data)
-{
- struct read_long_data *long_read = user_data;
- size_t buflen;
- uint8_t *buf = g_attrib_get_buffer(long_read->attrib, &buflen);
- guint16 plen;
- guint id;
-
- if (status != 0 || rlen < buflen)
- goto done;
-
- long_read->buffer = g_malloc(rlen);
- if (long_read->buffer == NULL) {
- status = ATT_ECODE_INSUFF_RESOURCES;
- goto done;
- }
-
- memcpy(long_read->buffer, rpdu, rlen);
- long_read->size = rlen;
-
- plen = enc_read_blob_req(long_read->handle, rlen - 1, buf, buflen);
-
- id = g_attrib_send(long_read->attrib, long_read->id, buf, plen,
- read_blob_helper, long_read, read_long_destroy);
- if (id != 0) {
- __sync_fetch_and_add(&long_read->ref, 1);
- return;
- }
-
- status = ATT_ECODE_IO;
-
-done:
- long_read->func(status, rpdu, rlen, long_read->user_data);
-}
-
-guint gatt_read_char(GAttrib *attrib, uint16_t handle, GAttribResultFunc func,
- gpointer user_data)
-{
- uint8_t *buf;
- size_t buflen;
- guint16 plen;
- guint id;
- struct read_long_data *long_read;
-
- long_read = g_try_new0(struct read_long_data, 1);
-
- if (long_read == NULL)
- return 0;
-
- long_read->attrib = g_attrib_ref(attrib);
- long_read->func = func;
- long_read->user_data = user_data;
- long_read->handle = handle;
-
- buf = g_attrib_get_buffer(attrib, &buflen);
- plen = enc_read_req(handle, buf, buflen);
- id = g_attrib_send(attrib, 0, buf, plen, read_char_helper,
- long_read, read_long_destroy);
- if (id == 0) {
- g_attrib_unref(long_read->attrib);
- g_free(long_read);
- } else {
- __sync_fetch_and_add(&long_read->ref, 1);
- long_read->id = id;
- }
-
- return id;
-}
-
-struct write_long_data {
- GAttrib *attrib;
- GAttribResultFunc func;
- gpointer user_data;
- guint16 handle;
- uint16_t offset;
- uint8_t *value;
- size_t vlen;
-};
-
-static guint execute_write(GAttrib *attrib, uint8_t flags,
- GAttribResultFunc func, gpointer user_data)
-{
- uint8_t *buf;
- size_t buflen;
- guint16 plen;
-
- buf = g_attrib_get_buffer(attrib, &buflen);
- plen = enc_exec_write_req(flags, buf, buflen);
- if (plen == 0)
- return 0;
-
- return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
-}
-
-static guint prepare_write(struct write_long_data *long_write);
-
-static void prepare_write_cb(guint8 status, const guint8 *rpdu, guint16 rlen,
- gpointer user_data)
-{
- struct write_long_data *long_write = user_data;
-
- if (status != 0) {
- long_write->func(status, rpdu, rlen, long_write->user_data);
- return;
- }
-
- /* Skip Prepare Write Response PDU header (5 bytes) */
- long_write->offset += rlen - 5;
-
- if (long_write->offset == long_write->vlen) {
- execute_write(long_write->attrib, ATT_WRITE_ALL_PREP_WRITES,
- long_write->func, long_write->user_data);
- free(long_write->value);
- g_free(long_write);
-
- return;
- }
-
- prepare_write(long_write);
-}
-
-static guint prepare_write(struct write_long_data *long_write)
-{
- GAttrib *attrib = long_write->attrib;
- uint16_t handle = long_write->handle;
- uint16_t offset = long_write->offset;
- uint8_t *buf, *value = long_write->value + offset;
- size_t buflen, vlen = long_write->vlen - offset;
- guint16 plen;
-
- buf = g_attrib_get_buffer(attrib, &buflen);
-
- plen = enc_prep_write_req(handle, offset, value, vlen, buf, buflen);
- if (plen == 0)
- return 0;
-
- return g_attrib_send(attrib, 0, buf, plen, prepare_write_cb, long_write,
- NULL);
-}
-
-guint gatt_write_char(GAttrib *attrib, uint16_t handle, const uint8_t *value,
- size_t vlen, GAttribResultFunc func, gpointer user_data)
-{
- uint8_t *buf;
- size_t buflen;
- struct write_long_data *long_write;
-
- buf = g_attrib_get_buffer(attrib, &buflen);
-
- /* Use Write Request if payload fits on a single transfer, including 3
- * bytes for the header. */
- if (vlen <= buflen - 3) {
- uint16_t plen;
-
- plen = enc_write_req(handle, value, vlen, buf, buflen);
- if (plen == 0)
- return 0;
-
- return g_attrib_send(attrib, 0, buf, plen, func, user_data,
- NULL);
- }
-
- /* Write Long Characteristic Values */
- long_write = g_try_new0(struct write_long_data, 1);
- if (long_write == NULL)
- return 0;
-
- long_write->attrib = attrib;
- long_write->func = func;
- long_write->user_data = user_data;
- long_write->handle = handle;
- long_write->value = util_memdup(value, vlen);
- long_write->vlen = vlen;
-
- return prepare_write(long_write);
-}
-
-guint gatt_execute_write(GAttrib *attrib, uint8_t flags,
- GAttribResultFunc func, gpointer user_data)
-{
- return execute_write(attrib, flags, func, user_data);
-}
-
-guint gatt_reliable_write_char(GAttrib *attrib, uint16_t handle,
- const uint8_t *value, size_t vlen,
- GAttribResultFunc func,
- gpointer user_data)
-{
- uint8_t *buf;
- guint16 plen;
- size_t buflen;
-
- buf = g_attrib_get_buffer(attrib, &buflen);
-
- plen = enc_prep_write_req(handle, 0, value, vlen, buf, buflen);
- if (!plen)
- return 0;
-
- return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
-}
-
-guint gatt_exchange_mtu(GAttrib *attrib, uint16_t mtu, GAttribResultFunc func,
- gpointer user_data)
-{
- uint8_t *buf;
- size_t buflen;
- guint16 plen;
-
- buf = g_attrib_get_buffer(attrib, &buflen);
- plen = enc_mtu_req(mtu, buf, buflen);
- return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
-}
-
-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 or if iterating
- * to the next handle from the last possible offset would overflow, then
- * something is wrong. Let's stop search, otherwise we might enter
- * infinite loop.
- */
- if (last < dd->start || last == G_MAXUINT16) {
- 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);
-}
-
-guint gatt_discover_desc(GAttrib *attrib, uint16_t start, uint16_t end,
- bt_uuid_t *uuid, gatt_cb_t func,
- gpointer user_data)
-{
- size_t buflen;
- uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
- struct discover_desc *dd;
- guint16 plen;
-
- plen = enc_find_info_req(start, end, buf, buflen);
- if (plen == 0)
- return 0;
-
- dd = g_try_new0(struct discover_desc, 1);
- if (dd == NULL)
- return 0;
-
- dd->attrib = g_attrib_ref(attrib);
- dd->cb = func;
- dd->user_data = user_data;
- dd->start = start;
- dd->end = end;
- dd->uuid = util_memdup(uuid, sizeof(bt_uuid_t));
-
- dd->id = g_attrib_send(attrib, 0, buf, plen, desc_discovered_cb,
- discover_desc_ref(dd), discover_desc_unref);
-
- return dd->id;
-}
-
-guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, const uint8_t *value,
- int vlen, GDestroyNotify notify, gpointer user_data)
-{
- uint8_t *buf;
- size_t buflen;
- guint16 plen;
-
- buf = g_attrib_get_buffer(attrib, &buflen);
- plen = enc_write_cmd(handle, value, vlen, buf, buflen);
- return g_attrib_send(attrib, 0, buf, plen, NULL, user_data, notify);
-}
-
-guint gatt_signed_write_cmd(GAttrib *attrib, uint16_t handle,
- const uint8_t *value, int vlen,
- struct bt_crypto *crypto,
- const uint8_t csrk[16],
- uint32_t sign_cnt,
- GDestroyNotify notify,
- gpointer user_data)
-{
- uint8_t *buf;
- size_t buflen;
- guint16 plen;
-
- buf = g_attrib_get_buffer(attrib, &buflen);
- plen = enc_signed_write_cmd(handle, value, vlen, crypto, csrk, sign_cnt,
- buf, buflen);
- if (plen == 0)
- return 0;
-
- return g_attrib_send(attrib, 0, buf, plen, NULL, user_data, notify);
-}
-
static sdp_data_t *proto_seq_find(sdp_list_t *proto_list)
{
sdp_list_t *list;
diff --git a/attrib/gatt.h b/attrib/gatt.h
index e2c8c90a8add..0fe81db06fe6 100644
--- a/attrib/gatt.h
+++ b/attrib/gatt.h
@@ -9,101 +9,12 @@
*
*/
-/*
- * GATT Characteristic Property bit field
- * Reference: Core SPEC 4.1 page 2183 (Table 3.5: Characteristic Properties
- * bit field) defines how the Characteristic Value can be used, or how the
- * characteristic descriptors (see Section 3.3.3 - page 2184) can be accessed.
- * In the core spec, regular properties are included in the characteristic
- * declaration, and the extended properties are defined as descriptor.
- */
-
-#define GATT_CHR_PROP_BROADCAST 0x01
-#define GATT_CHR_PROP_READ 0x02
-#define GATT_CHR_PROP_WRITE_WITHOUT_RESP 0x04
-#define GATT_CHR_PROP_WRITE 0x08
-#define GATT_CHR_PROP_NOTIFY 0x10
-#define GATT_CHR_PROP_INDICATE 0x20
-#define GATT_CHR_PROP_AUTH 0x40
-#define GATT_CHR_PROP_EXT_PROP 0x80
-
-/* Client Characteristic Configuration bit field */
-#define GATT_CLIENT_CHARAC_CFG_NOTIF_BIT 0x0001
-#define GATT_CLIENT_CHARAC_CFG_IND_BIT 0x0002
-
-typedef void (*gatt_cb_t) (uint8_t status, GSList *l, void *user_data);
-
struct gatt_primary {
char uuid[MAX_LEN_UUID_STR + 1];
gboolean changed;
struct att_range range;
};
-struct gatt_included {
- char uuid[MAX_LEN_UUID_STR + 1];
- uint16_t handle;
- struct att_range range;
-};
-
-struct gatt_char {
- char uuid[MAX_LEN_UUID_STR + 1];
- uint16_t handle;
- uint8_t properties;
- uint16_t value_handle;
-};
-
-struct gatt_desc {
- char uuid[MAX_LEN_UUID_STR + 1];
- uint16_t handle;
- uint16_t uuid16;
-};
-
-guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func,
- gpointer user_data);
-
-unsigned int gatt_find_included(GAttrib *attrib, uint16_t start, uint16_t end,
- gatt_cb_t func, gpointer user_data);
-
-guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
- bt_uuid_t *uuid, gatt_cb_t func,
- gpointer user_data);
-
-guint gatt_read_char(GAttrib *attrib, uint16_t handle, GAttribResultFunc func,
- gpointer user_data);
-
-guint gatt_write_char(GAttrib *attrib, uint16_t handle, const uint8_t *value,
- size_t vlen, GAttribResultFunc func,
- gpointer user_data);
-
-guint gatt_discover_desc(GAttrib *attrib, uint16_t start, uint16_t end,
- bt_uuid_t *uuid, gatt_cb_t func,
- gpointer user_data);
-
-guint gatt_reliable_write_char(GAttrib *attrib, uint16_t handle,
- const uint8_t *value, size_t vlen,
- GAttribResultFunc func,
- gpointer user_data);
-
-guint gatt_execute_write(GAttrib *attrib, uint8_t flags,
- GAttribResultFunc func, gpointer user_data);
-
-guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, const uint8_t *value,
- int vlen, GDestroyNotify notify, gpointer user_data);
-
-guint gatt_signed_write_cmd(GAttrib *attrib, uint16_t handle,
- const uint8_t *value, int vlen,
- struct bt_crypto *crypto,
- const uint8_t csrk[16],
- uint32_t sign_cnt,
- GDestroyNotify notify,
- gpointer user_data);
-guint gatt_read_char_by_uuid(GAttrib *attrib, uint16_t start, uint16_t end,
- bt_uuid_t *uuid, GAttribResultFunc func,
- gpointer user_data);
-
-guint gatt_exchange_mtu(GAttrib *attrib, uint16_t mtu, GAttribResultFunc func,
- gpointer user_data);
-
gboolean gatt_parse_record(const sdp_record_t *rec,
uuid_t *prim_uuid, uint16_t *psm,
uint16_t *start, uint16_t *end);
diff --git a/attrib/gattrib.c b/attrib/gattrib.c
deleted file mode 100644
index 3a988e131e94..000000000000
--- a/attrib/gattrib.c
+++ /dev/null
@@ -1,473 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2010 Nokia Corporation
- * Copyright (C) 2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdbool.h>
-#include <string.h>
-
-#include <glib.h>
-
-#include "bluetooth/bluetooth.h"
-#include "bluetooth/uuid.h"
-
-#include "btio/btio.h"
-#include "src/log.h"
-#include "src/shared/util.h"
-#include "src/shared/att.h"
-#include "src/shared/gatt-helpers.h"
-#include "src/shared/queue.h"
-#include "src/shared/gatt-db.h"
-#include "src/shared/gatt-client.h"
-#include "attrib/att.h"
-#include "attrib/gattrib.h"
-
-struct _GAttrib {
- int ref_count;
- struct bt_att *att;
- struct bt_gatt_client *client;
- GIOChannel *io;
- GDestroyNotify destroy;
- gpointer destroy_user_data;
- struct queue *callbacks;
- uint8_t *buf;
- int buflen;
- struct queue *track_ids;
-};
-
-struct attrib_callbacks {
- unsigned int id;
- GAttribResultFunc result_func;
- GAttribNotifyFunc notify_func;
- GDestroyNotify destroy_func;
- gpointer user_data;
- GAttrib *parent;
- uint16_t notify_handle;
-};
-
-GAttrib *g_attrib_new(GIOChannel *io, guint16 mtu, bool ext_signed)
-{
- gint fd;
- GAttrib *attr;
-
- if (!io)
- return NULL;
-
- fd = g_io_channel_unix_get_fd(io);
- attr = new0(GAttrib, 1);
- if (!attr)
- return NULL;
-
- g_io_channel_ref(io);
- attr->io = io;
-
- attr->att = bt_att_new(fd, ext_signed);
- if (!attr->att)
- goto fail;
-
- bt_att_set_close_on_unref(attr->att, true);
- g_io_channel_set_close_on_unref(io, FALSE);
-
- if (!bt_att_set_mtu(attr->att, mtu))
- goto fail;
-
- attr->buf = malloc0(mtu);
- attr->buflen = mtu;
- if (!attr->buf)
- goto fail;
-
- attr->callbacks = queue_new();
- if (!attr->callbacks)
- goto fail;
-
- attr->track_ids = queue_new();
- if (!attr->track_ids)
- goto fail;
-
- return g_attrib_ref(attr);
-
-fail:
- free(attr->buf);
- bt_att_unref(attr->att);
- g_io_channel_unref(io);
- free(attr);
- return NULL;
-}
-
-GAttrib *g_attrib_ref(GAttrib *attrib)
-{
- if (!attrib)
- return NULL;
-
- __sync_fetch_and_add(&attrib->ref_count, 1);
-
- DBG("%p: g_attrib_ref=%d ", attrib, attrib->ref_count);
-
- return attrib;
-}
-
-static void attrib_callbacks_destroy(void *data)
-{
- struct attrib_callbacks *cb = data;
-
- if (cb->destroy_func)
- cb->destroy_func(cb->user_data);
-
- free(data);
-}
-
-static void attrib_callbacks_remove(void *data)
-{
- struct attrib_callbacks *cb = data;
-
- if (!data || !queue_remove(cb->parent->callbacks, data))
- return;
-
- attrib_callbacks_destroy(data);
-}
-
-void g_attrib_unref(GAttrib *attrib)
-{
- if (!attrib)
- return;
-
- DBG("%p: g_attrib_unref=%d ", attrib, attrib->ref_count - 1);
-
- if (__sync_sub_and_fetch(&attrib->ref_count, 1))
- return;
-
- if (attrib->destroy)
- attrib->destroy(attrib->destroy_user_data);
-
- bt_gatt_client_unref(attrib->client);
- bt_att_unref(attrib->att);
-
- queue_destroy(attrib->callbacks, attrib_callbacks_destroy);
- queue_destroy(attrib->track_ids, NULL);
-
- free(attrib->buf);
-
- g_io_channel_unref(attrib->io);
-
- free(attrib);
-}
-
-GIOChannel *g_attrib_get_channel(GAttrib *attrib)
-{
- if (!attrib)
- return NULL;
-
- return attrib->io;
-}
-
-struct bt_att *g_attrib_get_att(GAttrib *attrib)
-{
- if (!attrib)
- return NULL;
-
- return attrib->att;
-}
-
-gboolean g_attrib_set_destroy_function(GAttrib *attrib, GDestroyNotify destroy,
- gpointer user_data)
-{
- if (!attrib)
- return FALSE;
-
- attrib->destroy = destroy;
- attrib->destroy_user_data = user_data;
-
- return TRUE;
-}
-
-
-static uint8_t *construct_full_pdu(uint8_t opcode, const void *pdu,
- uint16_t length)
-{
- uint8_t *buf = malloc0(length + 1);
-
- if (!buf)
- return NULL;
-
- buf[0] = opcode;
-
- if (pdu && length)
- memcpy(buf + 1, pdu, length);
-
- return buf;
-}
-
-static void attrib_callback_result(uint8_t opcode, const void *pdu,
- uint16_t length, void *user_data)
-{
- uint8_t *buf;
- struct attrib_callbacks *cb = user_data;
- guint8 status = 0;
-
- if (!cb)
- return;
-
- buf = construct_full_pdu(opcode, pdu, length);
- if (!buf)
- return;
-
- if (opcode == BT_ATT_OP_ERROR_RSP) {
- /* Error code is the third byte of the PDU data */
- if (length < 4)
- status = BT_ATT_ERROR_UNLIKELY;
- else
- status = ((guint8 *)pdu)[3];
- }
-
- if (cb->result_func)
- cb->result_func(status, buf, length + 1, cb->user_data);
-
- free(buf);
-}
-
-static void attrib_callback_notify(struct bt_att_chan *chan, uint16_t mtu,
- uint8_t opcode, const void *pdu,
- uint16_t length, void *user_data)
-{
- uint8_t *buf;
- struct attrib_callbacks *cb = user_data;
-
- if (!cb || !cb->notify_func)
- return;
-
- if (cb->notify_handle != GATTRIB_ALL_HANDLES && length < 2)
- return;
-
- if (cb->notify_handle != GATTRIB_ALL_HANDLES &&
- cb->notify_handle != get_le16(pdu))
- return;
-
- buf = construct_full_pdu(opcode, pdu, length);
- if (!buf)
- return;
-
- cb->notify_func(buf, length + 1, cb->user_data);
-
- free(buf);
-}
-
-guint g_attrib_send(GAttrib *attrib, guint id, const guint8 *pdu, guint16 len,
- GAttribResultFunc func, gpointer user_data,
- GDestroyNotify notify)
-{
- struct attrib_callbacks *cb = NULL;
- bt_att_response_func_t response_cb = NULL;
- bt_att_destroy_func_t destroy_cb = NULL;
-
- if (!attrib)
- return 0;
-
- if (!pdu || !len)
- return 0;
-
- if (func || notify) {
- cb = new0(struct attrib_callbacks, 1);
- if (!cb)
- return 0;
- cb->result_func = func;
- cb->user_data = user_data;
- cb->destroy_func = notify;
- cb->parent = attrib;
- queue_push_head(attrib->callbacks, cb);
- response_cb = attrib_callback_result;
- destroy_cb = attrib_callbacks_remove;
-
- }
-
- if (id == 0)
- id = bt_att_send(attrib->att, pdu[0], (void *) pdu + 1,
- len - 1, response_cb, cb, destroy_cb);
- else {
- int err;
-
- err = bt_att_resend(attrib->att, id, pdu[0], (void *) pdu + 1,
- len - 1, response_cb, cb, destroy_cb);
- if (err)
- return 0;
- }
-
- if (!id)
- return id;
-
- /*
- * If user what us to use given id, lets keep track on that so we give
- * user a possibility to cancel ongoing request.
- */
- if (cb) {
- cb->id = id;
- queue_push_tail(attrib->track_ids, UINT_TO_PTR(id));
- }
-
- return id;
-}
-
-gboolean g_attrib_cancel(GAttrib *attrib, guint id)
-{
- if (!attrib)
- return FALSE;
-
- return bt_att_cancel(attrib->att, id);
-}
-
-static void cancel_request(void *data, void *user_data)
-{
- unsigned int id = PTR_TO_UINT(data);
- GAttrib *attrib = user_data;
-
- bt_att_cancel(attrib->att, id);
-}
-
-gboolean g_attrib_cancel_all(GAttrib *attrib)
-{
- if (!attrib)
- return FALSE;
-
- queue_foreach(attrib->track_ids, cancel_request, attrib);
- queue_remove_all(attrib->track_ids, NULL, NULL, NULL);
-
- return TRUE;
-}
-
-static void client_notify_cb(uint16_t value_handle, const uint8_t *value,
- uint16_t length, void *user_data)
-{
- uint8_t *buf = newa(uint8_t, length + 2);
-
- put_le16(value_handle, buf);
-
- if (length)
- memcpy(buf + 2, value, length);
-
- attrib_callback_notify(NULL, 0, ATT_OP_HANDLE_NOTIFY, buf, length + 2,
- user_data);
-}
-
-guint g_attrib_register(GAttrib *attrib, guint8 opcode, guint16 handle,
- GAttribNotifyFunc func, gpointer user_data,
- GDestroyNotify notify)
-{
- struct attrib_callbacks *cb = NULL;
-
- if (!attrib)
- return 0;
-
- if (func || notify) {
- cb = new0(struct attrib_callbacks, 1);
- if (!cb)
- return 0;
- cb->notify_func = func;
- cb->notify_handle = handle;
- cb->user_data = user_data;
- cb->destroy_func = notify;
- cb->parent = attrib;
- queue_push_head(attrib->callbacks, cb);
- }
-
- if (opcode == ATT_OP_HANDLE_NOTIFY && attrib->client) {
- unsigned int id;
-
- id = bt_gatt_client_register_notify(attrib->client, handle,
- NULL, client_notify_cb, cb,
- attrib_callbacks_remove);
- if (id)
- return id;
- }
-
- if (opcode == GATTRIB_ALL_REQS)
- opcode = BT_ATT_ALL_REQUESTS;
-
- return bt_att_register(attrib->att, opcode, attrib_callback_notify,
- cb, attrib_callbacks_remove);
-}
-
-uint8_t *g_attrib_get_buffer(GAttrib *attrib, size_t *len)
-{
- uint16_t mtu;
-
- if (!attrib || !len)
- return NULL;
-
- mtu = bt_att_get_mtu(attrib->att);
-
- /*
- * Clients of this expect a buffer to use.
- *
- * Pdu encoding in shared/att verifies if whole buffer fits the mtu,
- * thus we should set the buflen also when mtu is reduced. But we
- * need to reallocate the buffer only if mtu is larger.
- */
- if (mtu > attrib->buflen)
- attrib->buf = g_realloc(attrib->buf, mtu);
-
- attrib->buflen = mtu;
- *len = attrib->buflen;
- return attrib->buf;
-}
-
-gboolean g_attrib_set_mtu(GAttrib *attrib, int mtu)
-{
- if (!attrib)
- return FALSE;
-
- /*
- * Clients of this expect a buffer to use.
- *
- * Pdu encoding in sharred/att verifies if whole buffer fits the mtu,
- * thus we should set the buflen also when mtu is reduced. But we
- * need to reallocate the buffer only if mtu is larger.
- */
- if (mtu > attrib->buflen)
- attrib->buf = g_realloc(attrib->buf, mtu);
-
- attrib->buflen = mtu;
-
- return bt_att_set_mtu(attrib->att, mtu);
-}
-
-gboolean g_attrib_attach_client(GAttrib *attrib, struct bt_gatt_client *client)
-{
- if (!attrib || !client)
- return FALSE;
-
- if (attrib->client)
- bt_gatt_client_unref(attrib->client);
-
- attrib->client = bt_gatt_client_clone(client);
- if (!attrib->client)
- return FALSE;
-
- return TRUE;
-}
-
-gboolean g_attrib_unregister(GAttrib *attrib, guint id)
-{
- if (!attrib)
- return FALSE;
-
- return bt_att_unregister(attrib->att, id);
-}
-
-gboolean g_attrib_unregister_all(GAttrib *attrib)
-{
- if (!attrib)
- return false;
-
- return bt_att_unregister_all(attrib->att);
-}
diff --git a/attrib/gattrib.h b/attrib/gattrib.h
deleted file mode 100644
index 0111bfc3f2fa..000000000000
--- a/attrib/gattrib.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2010 Nokia Corporation
- * Copyright (C) 2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- */
-#ifndef __GATTRIB_H
-#define __GATTRIB_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define GATTRIB_ALL_REQS 0xFE
-#define GATTRIB_ALL_HANDLES 0x0000
-
-struct bt_att; /* Forward declaration for compatibility */
-struct bt_gatt_client; /* Forward declaration for compatibility */
-struct _GAttrib;
-typedef struct _GAttrib GAttrib;
-
-typedef void (*GAttribResultFunc) (guint8 status, const guint8 *pdu,
- guint16 len, gpointer user_data);
-typedef void (*GAttribDisconnectFunc)(gpointer user_data);
-typedef void (*GAttribDebugFunc)(const char *str, gpointer user_data);
-typedef void (*GAttribNotifyFunc)(const guint8 *pdu, guint16 len,
- gpointer user_data);
-
-GAttrib *g_attrib_new(GIOChannel *io, guint16 mtu, bool ext_signed);
-GAttrib *g_attrib_ref(GAttrib *attrib);
-void g_attrib_unref(GAttrib *attrib);
-
-GIOChannel *g_attrib_get_channel(GAttrib *attrib);
-
-struct bt_att *g_attrib_get_att(GAttrib *attrib);
-
-gboolean g_attrib_set_destroy_function(GAttrib *attrib,
- GDestroyNotify destroy, gpointer user_data);
-
-guint g_attrib_send(GAttrib *attrib, guint id, const guint8 *pdu, guint16 len,
- GAttribResultFunc func, gpointer user_data,
- GDestroyNotify notify);
-
-gboolean g_attrib_cancel(GAttrib *attrib, guint id);
-gboolean g_attrib_cancel_all(GAttrib *attrib);
-
-guint g_attrib_register(GAttrib *attrib, guint8 opcode, guint16 handle,
- GAttribNotifyFunc func, gpointer user_data,
- GDestroyNotify notify);
-
-uint8_t *g_attrib_get_buffer(GAttrib *attrib, size_t *len);
-gboolean g_attrib_set_mtu(GAttrib *attrib, int mtu);
-gboolean g_attrib_attach_client(GAttrib *attrib, struct bt_gatt_client *client);
-
-gboolean g_attrib_unregister(GAttrib *attrib, guint id);
-gboolean g_attrib_unregister_all(GAttrib *attrib);
-
-#ifdef __cplusplus
-}
-#endif
-#endif
diff --git a/attrib/gatttool.c b/attrib/gatttool.c
deleted file mode 100644
index c984bef9dd39..000000000000
--- a/attrib/gatttool.c
+++ /dev/null
@@ -1,612 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2010 Nokia Corporation
- * Copyright (C) 2010 Marcel Holtmann <marcel@holtmann.org>
- *
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <glib.h>
-
-#include "bluetooth/bluetooth.h"
-#include "bluetooth/hci.h"
-#include "bluetooth/hci_lib.h"
-#include "bluetooth/sdp.h"
-#include "bluetooth/uuid.h"
-
-#include "src/shared/att-types.h"
-#include "src/shared/util.h"
-#include "att.h"
-#include "btio/btio.h"
-#include "gattrib.h"
-#include "gatt.h"
-#include "gatttool.h"
-
-static char *opt_src = NULL;
-static char *opt_dst = NULL;
-static char *opt_dst_type = NULL;
-static char *opt_value = NULL;
-static char *opt_sec_level = NULL;
-static bt_uuid_t *opt_uuid = NULL;
-static int opt_start = 0x0001;
-static int opt_end = 0xffff;
-static int opt_handle = -1;
-static int opt_mtu = 0;
-static int opt_psm = 0;
-static gboolean opt_primary = FALSE;
-static gboolean opt_characteristics = FALSE;
-static gboolean opt_char_read = FALSE;
-static gboolean opt_listen = FALSE;
-static gboolean opt_char_desc = FALSE;
-static gboolean opt_char_write = FALSE;
-static gboolean opt_char_write_req = FALSE;
-static gboolean opt_interactive = FALSE;
-static GMainLoop *event_loop;
-static gboolean got_error = FALSE;
-static GSourceFunc operation;
-
-struct characteristic_data {
- GAttrib *attrib;
- uint16_t start;
- uint16_t end;
-};
-
-static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
-{
- GAttrib *attrib = user_data;
- uint8_t *opdu;
- uint16_t handle, i, olen = 0;
- size_t plen;
-
- handle = get_le16(&pdu[1]);
-
- switch (pdu[0]) {
- case ATT_OP_HANDLE_NOTIFY:
- g_print("Notification handle = 0x%04x value: ", handle);
- break;
- case ATT_OP_HANDLE_IND:
- g_print("Indication handle = 0x%04x value: ", handle);
- break;
- default:
- g_print("Invalid opcode\n");
- return;
- }
-
- for (i = 3; i < len; i++)
- g_print("%02x ", pdu[i]);
-
- g_print("\n");
-
- if (pdu[0] == ATT_OP_HANDLE_NOTIFY)
- return;
-
- opdu = g_attrib_get_buffer(attrib, &plen);
- olen = enc_confirmation(opdu, plen);
-
- if (olen > 0)
- g_attrib_send(attrib, 0, opdu, olen, NULL, NULL, NULL);
-}
-
-static gboolean listen_start(gpointer user_data)
-{
- GAttrib *attrib = user_data;
-
- g_attrib_register(attrib, ATT_OP_HANDLE_NOTIFY, GATTRIB_ALL_HANDLES,
- events_handler, attrib, NULL);
- g_attrib_register(attrib, ATT_OP_HANDLE_IND, GATTRIB_ALL_HANDLES,
- events_handler, attrib, NULL);
-
- return FALSE;
-}
-
-static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
-{
- GAttrib *attrib;
- uint16_t mtu;
- uint16_t cid;
- GError *gerr = NULL;
-
- if (err) {
- g_printerr("%s\n", err->message);
- got_error = TRUE;
- g_main_loop_quit(event_loop);
- }
-
- bt_io_get(io, &gerr, BT_IO_OPT_IMTU, &mtu,
- BT_IO_OPT_CID, &cid, BT_IO_OPT_INVALID);
-
- if (gerr) {
- g_printerr("Can't detect MTU, using default: %s",
- gerr->message);
- g_error_free(gerr);
- mtu = ATT_DEFAULT_LE_MTU;
- }
-
- if (cid == BT_ATT_CID)
- mtu = ATT_DEFAULT_LE_MTU;
-
- attrib = g_attrib_new(io, mtu, false);
-
- if (opt_listen)
- g_idle_add(listen_start, attrib);
-
- operation(attrib);
-}
-
-static void primary_all_cb(uint8_t status, GSList *services, void *user_data)
-{
- GSList *l;
-
- if (status) {
- g_printerr("Discover all primary services failed: %s\n",
- att_ecode2str(status));
- goto done;
- }
-
- for (l = services; l; l = l->next) {
- struct gatt_primary *prim = l->data;
- g_print("attr handle = 0x%04x, end grp handle = 0x%04x "
- "uuid: %s\n", prim->range.start, prim->range.end, prim->uuid);
- }
-
-done:
- g_main_loop_quit(event_loop);
-}
-
-static void primary_by_uuid_cb(uint8_t status, GSList *ranges, void *user_data)
-{
- GSList *l;
-
- if (status != 0) {
- g_printerr("Discover primary services by UUID failed: %s\n",
- att_ecode2str(status));
- goto done;
- }
-
- for (l = ranges; l; l = l->next) {
- struct att_range *range = l->data;
- g_print("Starting handle: %04x Ending handle: %04x\n",
- range->start, range->end);
- }
-
-done:
- g_main_loop_quit(event_loop);
-}
-
-static gboolean primary(gpointer user_data)
-{
- GAttrib *attrib = user_data;
-
- if (opt_uuid)
- gatt_discover_primary(attrib, opt_uuid, primary_by_uuid_cb,
- NULL);
- else
- gatt_discover_primary(attrib, NULL, primary_all_cb, NULL);
-
- return FALSE;
-}
-
-static void char_discovered_cb(uint8_t status, GSList *characteristics,
- void *user_data)
-{
- GSList *l;
-
- if (status) {
- g_printerr("Discover all characteristics failed: %s\n",
- att_ecode2str(status));
- goto done;
- }
-
- for (l = characteristics; l; l = l->next) {
- struct gatt_char *chars = l->data;
-
- g_print("handle = 0x%04x, char properties = 0x%02x, char value "
- "handle = 0x%04x, uuid = %s\n", chars->handle,
- chars->properties, chars->value_handle, chars->uuid);
- }
-
-done:
- g_main_loop_quit(event_loop);
-}
-
-static gboolean characteristics(gpointer user_data)
-{
- GAttrib *attrib = user_data;
-
- gatt_discover_char(attrib, opt_start, opt_end, opt_uuid,
- char_discovered_cb, NULL);
-
- return FALSE;
-}
-
-static void char_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
- gpointer user_data)
-{
- uint8_t value[plen];
- ssize_t vlen;
- int i;
-
- if (status != 0) {
- g_printerr("Characteristic value/descriptor read failed: %s\n",
- att_ecode2str(status));
- goto done;
- }
-
- vlen = dec_read_resp(pdu, plen, value, sizeof(value));
- if (vlen < 0) {
- g_printerr("Protocol error\n");
- goto done;
- }
- g_print("Characteristic value/descriptor: ");
- for (i = 0; i < vlen; i++)
- g_print("%02x ", value[i]);
- g_print("\n");
-
-done:
- if (!opt_listen)
- g_main_loop_quit(event_loop);
-}
-
-static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu,
- guint16 plen, gpointer user_data)
-{
- struct att_data_list *list;
- int i;
-
- if (status != 0) {
- g_printerr("Read characteristics by UUID failed: %s\n",
- att_ecode2str(status));
- goto done;
- }
-
- list = dec_read_by_type_resp(pdu, plen);
- if (list == NULL)
- goto done;
-
- for (i = 0; i < list->num; i++) {
- uint8_t *value = list->data[i];
- int j;
-
- g_print("handle: 0x%04x \t value: ", get_le16(value));
- value += 2;
- for (j = 0; j < list->len - 2; j++, value++)
- g_print("%02x ", *value);
- g_print("\n");
- }
-
- att_data_list_free(list);
-
-done:
- g_main_loop_quit(event_loop);
-}
-
-static gboolean characteristics_read(gpointer user_data)
-{
- GAttrib *attrib = user_data;
-
- if (opt_uuid != NULL) {
-
- gatt_read_char_by_uuid(attrib, opt_start, opt_end, opt_uuid,
- char_read_by_uuid_cb, NULL);
-
- return FALSE;
- }
-
- if (opt_handle <= 0) {
- g_printerr("A valid handle is required\n");
- g_main_loop_quit(event_loop);
- return FALSE;
- }
-
- gatt_read_char(attrib, opt_handle, char_read_cb, attrib);
-
- return FALSE;
-}
-
-static void mainloop_quit(gpointer user_data)
-{
- uint8_t *value = user_data;
-
- g_free(value);
- g_main_loop_quit(event_loop);
-}
-
-static gboolean characteristics_write(gpointer user_data)
-{
- GAttrib *attrib = user_data;
- uint8_t *value;
- size_t len;
-
- if (opt_handle <= 0) {
- g_printerr("A valid handle is required\n");
- goto error;
- }
-
- if (opt_value == NULL || opt_value[0] == '\0') {
- g_printerr("A value is required\n");
- goto error;
- }
-
- len = gatt_attr_data_from_string(opt_value, &value);
- if (len == 0) {
- g_printerr("Invalid value\n");
- goto error;
- }
-
- gatt_write_cmd(attrib, opt_handle, value, len, mainloop_quit, value);
-
- g_free(value);
- return FALSE;
-
-error:
- g_main_loop_quit(event_loop);
- return FALSE;
-}
-
-static void char_write_req_cb(guint8 status, const guint8 *pdu, guint16 plen,
- gpointer user_data)
-{
- if (status != 0) {
- g_printerr("Characteristic Write Request failed: "
- "%s\n", att_ecode2str(status));
- goto done;
- }
-
- if (!dec_write_resp(pdu, plen) && !dec_exec_write_resp(pdu, plen)) {
- g_printerr("Protocol error\n");
- goto done;
- }
-
- g_print("Characteristic value was written successfully\n");
-
-done:
- if (!opt_listen)
- g_main_loop_quit(event_loop);
-}
-
-static gboolean characteristics_write_req(gpointer user_data)
-{
- GAttrib *attrib = user_data;
- uint8_t *value;
- size_t len;
-
- if (opt_handle <= 0) {
- g_printerr("A valid handle is required\n");
- goto error;
- }
-
- if (opt_value == NULL || opt_value[0] == '\0') {
- g_printerr("A value is required\n");
- goto error;
- }
-
- len = gatt_attr_data_from_string(opt_value, &value);
- if (len == 0) {
- g_printerr("Invalid value\n");
- goto error;
- }
-
- gatt_write_char(attrib, opt_handle, value, len, char_write_req_cb,
- NULL);
-
- g_free(value);
- return FALSE;
-
-error:
- g_main_loop_quit(event_loop);
- return FALSE;
-}
-
-static void char_desc_cb(uint8_t status, GSList *descriptors, void *user_data)
-{
- GSList *l;
-
- if (status) {
- g_printerr("Discover descriptors failed: %s\n",
- att_ecode2str(status));
- return;
- }
-
- for (l = descriptors; l; l = l->next) {
- struct gatt_desc *desc = l->data;
-
- g_print("handle = 0x%04x, uuid = %s\n", desc->handle,
- desc->uuid);
- }
-
- if (!opt_listen)
- g_main_loop_quit(event_loop);
-}
-
-static gboolean characteristics_desc(gpointer user_data)
-{
- GAttrib *attrib = user_data;
-
- gatt_discover_desc(attrib, opt_start, opt_end, NULL, char_desc_cb,
- NULL);
-
- return FALSE;
-}
-
-static gboolean parse_uuid(const char *key, const char *value,
- gpointer user_data, GError **error)
-{
- if (!value)
- return FALSE;
-
- opt_uuid = g_try_malloc(sizeof(bt_uuid_t));
- if (opt_uuid == NULL)
- return FALSE;
-
- if (bt_string_to_uuid(opt_uuid, value) < 0)
- return FALSE;
-
- return TRUE;
-}
-
-static const GOptionEntry primary_char_options[] = {
- { "start", 's' , 0, G_OPTION_ARG_INT, &opt_start,
- "Starting handle (optional)", "0x0001" },
- { "end", 'e' , 0, G_OPTION_ARG_INT, &opt_end,
- "Ending handle (optional)", "0xffff" },
- { "uuid", 'u', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
- parse_uuid, "UUID16 or UUID128 (optional)", "0x1801"},
- { NULL },
-};
-
-static const GOptionEntry char_rw_options[] = {
- { "handle", 'a' , 0, G_OPTION_ARG_INT, &opt_handle,
- "Read/Write characteristic by handle (required)", "0x0001" },
- { "value", 'n' , 0, G_OPTION_ARG_STRING, &opt_value,
- "Write characteristic value (required for write operation)",
- "0x0001" },
- {NULL},
-};
-
-static const GOptionEntry gatt_options[] = {
- { "primary", 0, 0, G_OPTION_ARG_NONE, &opt_primary,
- "Primary Service Discovery", NULL },
- { "characteristics", 0, 0, G_OPTION_ARG_NONE, &opt_characteristics,
- "Characteristics Discovery", NULL },
- { "char-read", 0, 0, G_OPTION_ARG_NONE, &opt_char_read,
- "Characteristics Value/Descriptor Read", NULL },
- { "char-write", 0, 0, G_OPTION_ARG_NONE, &opt_char_write,
- "Characteristics Value Write Without Response (Write Command)",
- NULL },
- { "char-write-req", 0, 0, G_OPTION_ARG_NONE, &opt_char_write_req,
- "Characteristics Value Write (Write Request)", NULL },
- { "char-desc", 0, 0, G_OPTION_ARG_NONE, &opt_char_desc,
- "Characteristics Descriptor Discovery", NULL },
- { "listen", 0, 0, G_OPTION_ARG_NONE, &opt_listen,
- "Listen for notifications and indications", NULL },
- { "interactive", 'I', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
- &opt_interactive, "Use interactive mode", NULL },
- { NULL },
-};
-
-static const GOptionEntry options[] = {
- { "adapter", 'i', 0, G_OPTION_ARG_STRING, &opt_src,
- "Specify local adapter interface", "hciX" },
- { "device", 'b', 0, G_OPTION_ARG_STRING, &opt_dst,
- "Specify remote Bluetooth address", "MAC" },
- { "addr-type", 't', 0, G_OPTION_ARG_STRING, &opt_dst_type,
- "Set LE address type. Default: public", "[public | random]"},
- { "mtu", 'm', 0, G_OPTION_ARG_INT, &opt_mtu,
- "Specify the MTU size", "MTU" },
- { "psm", 'p', 0, G_OPTION_ARG_INT, &opt_psm,
- "Specify the PSM for GATT/ATT over BR/EDR", "PSM" },
- { "sec-level", 'l', 0, G_OPTION_ARG_STRING, &opt_sec_level,
- "Set security level. Default: low", "[low | medium | high]"},
- { NULL },
-};
-
-int main(int argc, char *argv[])
-{
- GOptionContext *context;
- GOptionGroup *gatt_group, *params_group, *char_rw_group;
- GError *gerr = NULL;
- GIOChannel *chan;
-
- opt_dst_type = g_strdup("public");
- opt_sec_level = g_strdup("low");
-
- context = g_option_context_new(NULL);
- g_option_context_add_main_entries(context, options, NULL);
-
- /* GATT commands */
- gatt_group = g_option_group_new("gatt", "GATT commands",
- "Show all GATT commands", NULL, NULL);
- g_option_context_add_group(context, gatt_group);
- g_option_group_add_entries(gatt_group, gatt_options);
-
- /* Primary Services and Characteristics arguments */
- params_group = g_option_group_new("params",
- "Primary Services/Characteristics arguments",
- "Show all Primary Services/Characteristics arguments",
- NULL, NULL);
- g_option_context_add_group(context, params_group);
- g_option_group_add_entries(params_group, primary_char_options);
-
- /* Characteristics value/descriptor read/write arguments */
- char_rw_group = g_option_group_new("char-read-write",
- "Characteristics Value/Descriptor Read/Write arguments",
- "Show all Characteristics Value/Descriptor Read/Write "
- "arguments",
- NULL, NULL);
- g_option_context_add_group(context, char_rw_group);
- g_option_group_add_entries(char_rw_group, char_rw_options);
-
- if (!g_option_context_parse(context, &argc, &argv, &gerr)) {
- g_printerr("%s\n", gerr->message);
- g_clear_error(&gerr);
- }
-
- if (opt_interactive) {
- interactive(opt_src, opt_dst, opt_dst_type, opt_psm);
- goto done;
- }
-
- if (opt_primary)
- operation = primary;
- else if (opt_characteristics)
- operation = characteristics;
- else if (opt_char_read)
- operation = characteristics_read;
- else if (opt_char_write)
- operation = characteristics_write;
- else if (opt_char_write_req)
- operation = characteristics_write_req;
- else if (opt_char_desc)
- operation = characteristics_desc;
- else {
- char *help = g_option_context_get_help(context, TRUE, NULL);
- g_print("%s\n", help);
- g_free(help);
- got_error = TRUE;
- goto done;
- }
-
- if (opt_dst == NULL) {
- g_print("Remote Bluetooth address required\n");
- got_error = TRUE;
- goto done;
- }
-
- chan = gatt_connect(opt_src, opt_dst, opt_dst_type, opt_sec_level,
- opt_psm, opt_mtu, connect_cb, &gerr);
- if (chan == NULL) {
- g_printerr("%s\n", gerr->message);
- g_clear_error(&gerr);
- got_error = TRUE;
- goto done;
- }
-
- event_loop = g_main_loop_new(NULL, FALSE);
-
- g_main_loop_run(event_loop);
-
- g_main_loop_unref(event_loop);
-
-done:
- g_option_context_free(context);
- g_free(opt_src);
- g_free(opt_dst);
- g_free(opt_uuid);
- g_free(opt_sec_level);
-
- if (got_error)
- exit(EXIT_FAILURE);
- else
- exit(EXIT_SUCCESS);
-}
diff --git a/attrib/gatttool.h b/attrib/gatttool.h
deleted file mode 100644
index 20cb42417e34..000000000000
--- a/attrib/gatttool.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011 Nokia Corporation
- *
- *
- */
-
-int interactive(const char *src, const char *dst, const char *dst_type,
- int psm);
-GIOChannel *gatt_connect(const char *src, const char *dst,
- const char *dst_type, const char *sec_level,
- int psm, int mtu, BtIOConnect connect_cb,
- GError **gerr);
-size_t gatt_attr_data_from_string(const char *str, uint8_t **data);
diff --git a/attrib/interactive.c b/attrib/interactive.c
deleted file mode 100644
index 0291fa876533..000000000000
--- a/attrib/interactive.c
+++ /dev/null
@@ -1,1020 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011 Nokia Corporation
- *
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <string.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/signalfd.h>
-#include <glib.h>
-
-#include <readline/readline.h>
-#include <readline/history.h>
-
-#include "bluetooth/bluetooth.h"
-#include "bluetooth/sdp.h"
-#include "bluetooth/uuid.h"
-
-#include "src/shared/att-types.h"
-#include "src/shared/util.h"
-#include "btio/btio.h"
-#include "att.h"
-#include "gattrib.h"
-#include "gatt.h"
-#include "gatttool.h"
-#include "client/display.h"
-
-static GIOChannel *iochannel = NULL;
-static GAttrib *attrib = NULL;
-static GMainLoop *event_loop;
-static GString *prompt;
-
-static char *opt_src = NULL;
-static char *opt_dst = NULL;
-static char *opt_dst_type = NULL;
-static char *opt_sec_level = NULL;
-static int opt_psm = 0;
-static int opt_mtu = 0;
-static int start;
-static int end;
-
-static void cmd_help(int argcp, char **argvp);
-
-static enum state {
- STATE_DISCONNECTED,
- STATE_CONNECTING,
- STATE_CONNECTED
-} conn_state;
-
-#define error(fmt, arg...) \
- rl_printf(COLOR_RED "Error: " COLOR_OFF fmt, ## arg)
-
-#define failed(fmt, arg...) \
- rl_printf(COLOR_RED "Command Failed: " COLOR_OFF fmt, ## arg)
-
-static char *get_prompt(void)
-{
- if (conn_state == STATE_CONNECTED)
- g_string_assign(prompt, COLOR_BLUE);
- else
- g_string_assign(prompt, "");
-
- if (opt_dst)
- g_string_append_printf(prompt, "[%17s]", opt_dst);
- else
- g_string_append_printf(prompt, "[%17s]", "");
-
- if (conn_state == STATE_CONNECTED)
- g_string_append(prompt, COLOR_OFF);
-
- if (opt_psm)
- g_string_append(prompt, "[BR]");
- else
- g_string_append(prompt, "[LE]");
-
- g_string_append(prompt, "> ");
-
- return prompt->str;
-}
-
-
-static void set_state(enum state st)
-{
- conn_state = st;
- rl_set_prompt(get_prompt());
-}
-
-static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
-{
- uint8_t *opdu;
- uint16_t handle, i, olen;
- size_t plen;
- GString *s;
-
- handle = get_le16(&pdu[1]);
-
- switch (pdu[0]) {
- case ATT_OP_HANDLE_NOTIFY:
- s = g_string_new(NULL);
- g_string_printf(s, "Notification handle = 0x%04x value: ",
- handle);
- break;
- case ATT_OP_HANDLE_IND:
- s = g_string_new(NULL);
- g_string_printf(s, "Indication handle = 0x%04x value: ",
- handle);
- break;
- default:
- error("Invalid opcode\n");
- return;
- }
-
- for (i = 3; i < len; i++)
- g_string_append_printf(s, "%02x ", pdu[i]);
-
- rl_printf("%s\n", s->str);
- g_string_free(s, TRUE);
-
- if (pdu[0] == ATT_OP_HANDLE_NOTIFY)
- return;
-
- opdu = g_attrib_get_buffer(attrib, &plen);
- olen = enc_confirmation(opdu, plen);
-
- if (olen > 0)
- g_attrib_send(attrib, 0, opdu, olen, NULL, NULL, NULL);
-}
-
-static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
-{
- uint16_t mtu;
- uint16_t cid;
-
- if (err) {
- set_state(STATE_DISCONNECTED);
- error("%s\n", err->message);
- return;
- }
-
- bt_io_get(io, &err, BT_IO_OPT_IMTU, &mtu,
- BT_IO_OPT_CID, &cid, BT_IO_OPT_INVALID);
-
- if (err) {
- g_printerr("Can't detect MTU, using default: %s", err->message);
- g_error_free(err);
- mtu = ATT_DEFAULT_LE_MTU;
- }
-
- if (cid == BT_ATT_CID)
- mtu = ATT_DEFAULT_LE_MTU;
-
- attrib = g_attrib_new(iochannel, mtu, false);
- g_attrib_register(attrib, ATT_OP_HANDLE_NOTIFY, GATTRIB_ALL_HANDLES,
- events_handler, attrib, NULL);
- g_attrib_register(attrib, ATT_OP_HANDLE_IND, GATTRIB_ALL_HANDLES,
- events_handler, attrib, NULL);
- set_state(STATE_CONNECTED);
- rl_printf("Connection successful\n");
-}
-
-static void disconnect_io(void)
-{
- if (conn_state == STATE_DISCONNECTED)
- return;
-
- g_attrib_unref(attrib);
- attrib = NULL;
- opt_mtu = 0;
-
- g_io_channel_shutdown(iochannel, FALSE, NULL);
- g_io_channel_unref(iochannel);
- iochannel = NULL;
-
- set_state(STATE_DISCONNECTED);
-}
-
-static void primary_all_cb(uint8_t status, GSList *services, void *user_data)
-{
- GSList *l;
-
- if (status) {
- error("Discover all primary services failed: %s\n",
- att_ecode2str(status));
- return;
- }
-
- if (services == NULL) {
- error("No primary service found\n");
- return;
- }
-
- for (l = services; l; l = l->next) {
- struct gatt_primary *prim = l->data;
- rl_printf("attr handle: 0x%04x, end grp handle: 0x%04x uuid: %s\n",
- prim->range.start, prim->range.end, prim->uuid);
- }
-}
-
-static void primary_by_uuid_cb(uint8_t status, GSList *ranges, void *user_data)
-{
- GSList *l;
-
- if (status) {
- error("Discover primary services by UUID failed: %s\n",
- att_ecode2str(status));
- return;
- }
-
- if (ranges == NULL) {
- error("No service UUID found\n");
- return;
- }
-
- for (l = ranges; l; l = l->next) {
- struct att_range *range = l->data;
- rl_printf("Starting handle: 0x%04x Ending handle: 0x%04x\n",
- range->start, range->end);
- }
-}
-
-static void included_cb(uint8_t status, GSList *includes, void *user_data)
-{
- GSList *l;
-
- if (status) {
- error("Find included services failed: %s\n",
- att_ecode2str(status));
- return;
- }
-
- if (includes == NULL) {
- rl_printf("No included services found for this range\n");
- return;
- }
-
- for (l = includes; l; l = l->next) {
- struct gatt_included *incl = l->data;
- rl_printf("handle: 0x%04x, start handle: 0x%04x, "
- "end handle: 0x%04x uuid: %s\n",
- incl->handle, incl->range.start,
- incl->range.end, incl->uuid);
- }
-}
-
-static void char_cb(uint8_t status, GSList *characteristics, void *user_data)
-{
- GSList *l;
-
- if (status) {
- error("Discover all characteristics failed: %s\n",
- att_ecode2str(status));
- return;
- }
-
- for (l = characteristics; l; l = l->next) {
- struct gatt_char *chars = l->data;
-
- rl_printf("handle: 0x%04x, char properties: 0x%02x, char value "
- "handle: 0x%04x, uuid: %s\n", chars->handle,
- chars->properties, chars->value_handle,
- chars->uuid);
- }
-}
-
-static void char_desc_cb(uint8_t status, GSList *descriptors, void *user_data)
-{
- GSList *l;
-
- if (status) {
- error("Discover descriptors failed: %s\n",
- att_ecode2str(status));
- return;
- }
-
- for (l = descriptors; l; l = l->next) {
- struct gatt_desc *desc = l->data;
-
- rl_printf("handle: 0x%04x, uuid: %s\n", desc->handle,
- desc->uuid);
- }
-}
-
-static void char_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
- gpointer user_data)
-{
- uint8_t value[plen];
- ssize_t vlen;
- int i;
- GString *s;
-
- if (status != 0) {
- error("Characteristic value/descriptor read failed: %s\n",
- att_ecode2str(status));
- return;
- }
-
- vlen = dec_read_resp(pdu, plen, value, sizeof(value));
- if (vlen < 0) {
- error("Protocol error\n");
- return;
- }
-
- s = g_string_new("Characteristic value/descriptor: ");
- for (i = 0; i < vlen; i++)
- g_string_append_printf(s, "%02x ", value[i]);
-
- rl_printf("%s\n", s->str);
- g_string_free(s, TRUE);
-}
-
-static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu,
- guint16 plen, gpointer user_data)
-{
- struct att_data_list *list;
- int i;
- GString *s;
-
- if (status != 0) {
- error("Read characteristics by UUID failed: %s\n",
- att_ecode2str(status));
- return;
- }
-
- list = dec_read_by_type_resp(pdu, plen);
- if (list == NULL)
- return;
-
- s = g_string_new(NULL);
- for (i = 0; i < list->num; i++) {
- uint8_t *value = list->data[i];
- int j;
-
- g_string_printf(s, "handle: 0x%04x \t value: ",
- get_le16(value));
- value += 2;
- for (j = 0; j < list->len - 2; j++, value++)
- g_string_append_printf(s, "%02x ", *value);
-
- rl_printf("%s\n", s->str);
- }
-
- att_data_list_free(list);
- g_string_free(s, TRUE);
-}
-
-static void cmd_exit(int argcp, char **argvp)
-{
- rl_callback_handler_remove();
- g_main_loop_quit(event_loop);
-}
-
-static gboolean channel_watcher(GIOChannel *chan, GIOCondition cond,
- gpointer user_data)
-{
- disconnect_io();
-
- return FALSE;
-}
-
-static void cmd_connect(int argcp, char **argvp)
-{
- GError *gerr = NULL;
-
- if (conn_state != STATE_DISCONNECTED)
- return;
-
- if (argcp > 1) {
- g_free(opt_dst);
- opt_dst = g_strdup(argvp[1]);
-
- g_free(opt_dst_type);
- if (argcp > 2)
- opt_dst_type = g_strdup(argvp[2]);
- else
- opt_dst_type = g_strdup("public");
- }
-
- if (opt_dst == NULL) {
- error("Remote Bluetooth address required\n");
- return;
- }
-
- rl_printf("Attempting to connect to %s\n", opt_dst);
- set_state(STATE_CONNECTING);
- iochannel = gatt_connect(opt_src, opt_dst, opt_dst_type, opt_sec_level,
- opt_psm, opt_mtu, connect_cb, &gerr);
- if (iochannel == NULL) {
- set_state(STATE_DISCONNECTED);
- error("%s\n", gerr->message);
- g_error_free(gerr);
- } else
- g_io_add_watch(iochannel, G_IO_HUP, channel_watcher, NULL);
-}
-
-static void cmd_disconnect(int argcp, char **argvp)
-{
- disconnect_io();
-}
-
-static void cmd_primary(int argcp, char **argvp)
-{
- bt_uuid_t uuid;
-
- if (conn_state != STATE_CONNECTED) {
- failed("Disconnected\n");
- return;
- }
-
- if (argcp == 1) {
- gatt_discover_primary(attrib, NULL, primary_all_cb, NULL);
- return;
- }
-
- if (bt_string_to_uuid(&uuid, argvp[1]) < 0) {
- error("Invalid UUID\n");
- return;
- }
-
- gatt_discover_primary(attrib, &uuid, primary_by_uuid_cb, NULL);
-}
-
-static int strtohandle(const char *src)
-{
- char *e;
- int dst;
-
- errno = 0;
- dst = strtoll(src, &e, 16);
- if (errno != 0 || *e != '\0')
- return -EINVAL;
-
- return dst;
-}
-
-static void cmd_included(int argcp, char **argvp)
-{
- int start = 0x0001;
- int end = 0xffff;
-
- if (conn_state != STATE_CONNECTED) {
- failed("Disconnected\n");
- return;
- }
-
- if (argcp > 1) {
- start = strtohandle(argvp[1]);
- if (start < 0) {
- error("Invalid start handle: %s\n", argvp[1]);
- return;
- }
- end = start;
- }
-
- if (argcp > 2) {
- end = strtohandle(argvp[2]);
- if (end < 0) {
- error("Invalid end handle: %s\n", argvp[2]);
- return;
- }
- }
-
- gatt_find_included(attrib, start, end, included_cb, NULL);
-}
-
-static void cmd_char(int argcp, char **argvp)
-{
- int start = 0x0001;
- int end = 0xffff;
-
- if (conn_state != STATE_CONNECTED) {
- failed("Disconnected\n");
- return;
- }
-
- if (argcp > 1) {
- start = strtohandle(argvp[1]);
- if (start < 0) {
- error("Invalid start handle: %s\n", argvp[1]);
- return;
- }
- }
-
- if (argcp > 2) {
- end = strtohandle(argvp[2]);
- if (end < 0) {
- error("Invalid end handle: %s\n", argvp[2]);
- return;
- }
- }
-
- if (argcp > 3) {
- bt_uuid_t uuid;
-
- if (bt_string_to_uuid(&uuid, argvp[3]) < 0) {
- error("Invalid UUID\n");
- return;
- }
-
- gatt_discover_char(attrib, start, end, &uuid, char_cb, NULL);
- return;
- }
-
- gatt_discover_char(attrib, start, end, NULL, char_cb, NULL);
-}
-
-static void cmd_char_desc(int argcp, char **argvp)
-{
- if (conn_state != STATE_CONNECTED) {
- failed("Disconnected\n");
- return;
- }
-
- if (argcp > 1) {
- start = strtohandle(argvp[1]);
- if (start < 0) {
- error("Invalid start handle: %s\n", argvp[1]);
- return;
- }
- } else
- start = 0x0001;
-
- if (argcp > 2) {
- end = strtohandle(argvp[2]);
- if (end < 0) {
- error("Invalid end handle: %s\n", argvp[2]);
- return;
- }
- } else
- end = 0xffff;
-
- gatt_discover_desc(attrib, start, end, NULL, char_desc_cb, NULL);
-}
-
-static void cmd_read_hnd(int argcp, char **argvp)
-{
- int handle;
-
- if (conn_state != STATE_CONNECTED) {
- failed("Disconnected\n");
- return;
- }
-
- if (argcp < 2) {
- error("Missing argument: handle\n");
- return;
- }
-
- handle = strtohandle(argvp[1]);
- if (handle < 0) {
- error("Invalid handle: %s\n", argvp[1]);
- return;
- }
-
- gatt_read_char(attrib, handle, char_read_cb, attrib);
-}
-
-static void cmd_read_uuid(int argcp, char **argvp)
-{
- int start = 0x0001;
- int end = 0xffff;
- bt_uuid_t uuid;
-
- if (conn_state != STATE_CONNECTED) {
- failed("Disconnected\n");
- return;
- }
-
- if (argcp < 2) {
- error("Missing argument: UUID\n");
- return;
- }
-
- if (bt_string_to_uuid(&uuid, argvp[1]) < 0) {
- error("Invalid UUID\n");
- return;
- }
-
- if (argcp > 2) {
- start = strtohandle(argvp[2]);
- if (start < 0) {
- error("Invalid start handle: %s\n", argvp[1]);
- return;
- }
- }
-
- if (argcp > 3) {
- end = strtohandle(argvp[3]);
- if (end < 0) {
- error("Invalid end handle: %s\n", argvp[2]);
- return;
- }
- }
-
- gatt_read_char_by_uuid(attrib, start, end, &uuid, char_read_by_uuid_cb,
- NULL);
-}
-
-static void char_write_req_cb(guint8 status, const guint8 *pdu, guint16 plen,
- gpointer user_data)
-{
- if (status != 0) {
- error("Characteristic Write Request failed: "
- "%s\n", att_ecode2str(status));
- return;
- }
-
- if (!dec_write_resp(pdu, plen) && !dec_exec_write_resp(pdu, plen)) {
- error("Protocol error\n");
- return;
- }
-
- rl_printf("Characteristic value was written successfully\n");
-}
-
-static void cmd_char_write(int argcp, char **argvp)
-{
- uint8_t *value;
- size_t plen;
- int handle;
-
- if (conn_state != STATE_CONNECTED) {
- failed("Disconnected\n");
- return;
- }
-
- if (argcp < 3) {
- rl_printf("Usage: %s <handle> <new value>\n", argvp[0]);
- return;
- }
-
- handle = strtohandle(argvp[1]);
- if (handle <= 0) {
- error("A valid handle is required\n");
- return;
- }
-
- plen = gatt_attr_data_from_string(argvp[2], &value);
- if (plen == 0) {
- error("Invalid value\n");
- return;
- }
-
- if (g_strcmp0("char-write-req", argvp[0]) == 0)
- gatt_write_char(attrib, handle, value, plen,
- char_write_req_cb, NULL);
- else
- gatt_write_cmd(attrib, handle, value, plen, NULL, NULL);
-
- g_free(value);
-}
-
-static void cmd_sec_level(int argcp, char **argvp)
-{
- GError *gerr = NULL;
- BtIOSecLevel sec_level;
-
- if (argcp < 2) {
- rl_printf("sec-level: %s\n", opt_sec_level);
- return;
- }
-
- if (strcasecmp(argvp[1], "medium") == 0)
- sec_level = BT_IO_SEC_MEDIUM;
- else if (strcasecmp(argvp[1], "high") == 0)
- sec_level = BT_IO_SEC_HIGH;
- else if (strcasecmp(argvp[1], "low") == 0)
- sec_level = BT_IO_SEC_LOW;
- else {
- rl_printf("Allowed values: low | medium | high\n");
- return;
- }
-
- g_free(opt_sec_level);
- opt_sec_level = g_strdup(argvp[1]);
-
- if (conn_state != STATE_CONNECTED)
- return;
-
- if (opt_psm) {
- rl_printf("Change will take effect on reconnection\n");
- return;
- }
-
- bt_io_set(iochannel, &gerr,
- BT_IO_OPT_SEC_LEVEL, sec_level,
- BT_IO_OPT_INVALID);
- if (gerr) {
- error("%s\n", gerr->message);
- g_error_free(gerr);
- }
-}
-
-static void exchange_mtu_cb(guint8 status, const guint8 *pdu, guint16 plen,
- gpointer user_data)
-{
- uint16_t mtu;
-
- if (status != 0) {
- error("Exchange MTU Request failed: %s\n",
- att_ecode2str(status));
- return;
- }
-
- if (!dec_mtu_resp(pdu, plen, &mtu)) {
- error("Protocol error\n");
- return;
- }
-
- mtu = MIN(mtu, opt_mtu);
- /* Set new value for MTU in client */
- if (g_attrib_set_mtu(attrib, mtu))
- rl_printf("MTU was exchanged successfully: %d\n", mtu);
- else
- error("Error exchanging MTU\n");
-}
-
-static void cmd_mtu(int argcp, char **argvp)
-{
- if (conn_state != STATE_CONNECTED) {
- failed("Disconnected\n");
- return;
- }
-
- if (opt_psm) {
- failed("Operation is only available for LE transport.\n");
- return;
- }
-
- if (argcp < 2) {
- rl_printf("Usage: mtu <value>\n");
- return;
- }
-
- if (opt_mtu) {
- failed("MTU exchange can only occur once per connection.\n");
- return;
- }
-
- errno = 0;
- opt_mtu = strtoll(argvp[1], NULL, 0);
- if (errno != 0 || opt_mtu < ATT_DEFAULT_LE_MTU) {
- error("Invalid value. Minimum MTU size is %d\n",
- ATT_DEFAULT_LE_MTU);
- return;
- }
-
- gatt_exchange_mtu(attrib, opt_mtu, exchange_mtu_cb, NULL);
-}
-
-static const struct {
- const char *cmd;
- void (*func)(int argcp, char **argvp);
- const char *params;
- const char *desc;
-} commands[] = {
- { "help", cmd_help, "",
- "Show this help"},
- { "exit", cmd_exit, "",
- "Exit interactive mode" },
- { "quit", cmd_exit, "",
- "Exit interactive mode" },
- { "connect", cmd_connect, "[address [address type]]",
- "Connect to a remote device" },
- { "disconnect", cmd_disconnect, "",
- "Disconnect from a remote device" },
- { "primary", cmd_primary, "[UUID]",
- "Primary Service Discovery" },
- { "included", cmd_included, "[start hnd [end hnd]]",
- "Find Included Services" },
- { "characteristics", cmd_char, "[start hnd [end hnd [UUID]]]",
- "Characteristics Discovery" },
- { "char-desc", cmd_char_desc, "[start hnd] [end hnd]",
- "Characteristics Descriptor Discovery" },
- { "char-read-hnd", cmd_read_hnd, "<handle>",
- "Characteristics Value/Descriptor Read by handle" },
- { "char-read-uuid", cmd_read_uuid, "<UUID> [start hnd] [end hnd]",
- "Characteristics Value/Descriptor Read by UUID" },
- { "char-write-req", cmd_char_write, "<handle> <new value>",
- "Characteristic Value Write (Write Request)" },
- { "char-write-cmd", cmd_char_write, "<handle> <new value>",
- "Characteristic Value Write (No response)" },
- { "sec-level", cmd_sec_level, "[low | medium | high]",
- "Set security level. Default: low" },
- { "mtu", cmd_mtu, "<value>",
- "Exchange MTU for GATT/ATT" },
- { NULL, NULL, NULL}
-};
-
-static void cmd_help(int argcp, char **argvp)
-{
- int i;
-
- for (i = 0; commands[i].cmd; i++)
- rl_printf("%-15s %-30s %s\n", commands[i].cmd,
- commands[i].params, commands[i].desc);
-}
-
-static void parse_line(char *line_read)
-{
- char **argvp;
- int argcp;
- int i;
-
- if (line_read == NULL) {
- rl_printf("\n");
- cmd_exit(0, NULL);
- return;
- }
-
- line_read = g_strstrip(line_read);
-
- if (*line_read == '\0')
- goto done;
-
- add_history(line_read);
-
- if (g_shell_parse_argv(line_read, &argcp, &argvp, NULL) == FALSE)
- goto done;
-
- for (i = 0; commands[i].cmd; i++)
- if (strcasecmp(commands[i].cmd, argvp[0]) == 0)
- break;
-
- if (commands[i].cmd)
- commands[i].func(argcp, argvp);
- else
- error("%s: command not found\n", argvp[0]);
-
- g_strfreev(argvp);
-
-done:
- free(line_read);
-}
-
-static gboolean prompt_read(GIOChannel *chan, GIOCondition cond,
- gpointer user_data)
-{
- if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
- g_io_channel_unref(chan);
- return FALSE;
- }
-
- rl_callback_read_char();
-
- return TRUE;
-}
-
-static char *completion_generator(const char *text, int state)
-{
- static int index = 0, len = 0;
- const char *cmd = NULL;
-
- if (state == 0) {
- index = 0;
- len = strlen(text);
- }
-
- while ((cmd = commands[index].cmd) != NULL) {
- index++;
- if (strncmp(cmd, text, len) == 0)
- return strdup(cmd);
- }
-
- return NULL;
-}
-
-static char **commands_completion(const char *text, int start, int end)
-{
- if (start == 0)
- return rl_completion_matches(text, &completion_generator);
- else
- return NULL;
-}
-
-static guint setup_standard_input(void)
-{
- GIOChannel *channel;
- guint source;
-
- channel = g_io_channel_unix_new(fileno(stdin));
-
- source = g_io_add_watch(channel,
- G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- prompt_read, NULL);
-
- g_io_channel_unref(channel);
-
- return source;
-}
-
-static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
- gpointer user_data)
-{
- static unsigned int __terminated = 0;
- struct signalfd_siginfo si;
- ssize_t result;
- int fd;
-
- if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
- g_main_loop_quit(event_loop);
- return FALSE;
- }
-
- fd = g_io_channel_unix_get_fd(channel);
-
- result = read(fd, &si, sizeof(si));
- if (result != sizeof(si))
- return FALSE;
-
- switch (si.ssi_signo) {
- case SIGINT:
- rl_replace_line("", 0);
- rl_crlf();
- rl_on_new_line();
- rl_redisplay();
- break;
- case SIGTERM:
- if (__terminated == 0) {
- rl_replace_line("", 0);
- rl_crlf();
- g_main_loop_quit(event_loop);
- }
-
- __terminated = 1;
- break;
- }
-
- return TRUE;
-}
-
-static guint setup_signalfd(void)
-{
- GIOChannel *channel;
- guint source;
- sigset_t mask;
- int fd;
-
- sigemptyset(&mask);
- sigaddset(&mask, SIGINT);
- sigaddset(&mask, SIGTERM);
-
- if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
- perror("Failed to set signal mask");
- return 0;
- }
-
- fd = signalfd(-1, &mask, 0);
- if (fd < 0) {
- perror("Failed to create signal descriptor");
- return 0;
- }
-
- channel = g_io_channel_unix_new(fd);
-
- g_io_channel_set_close_on_unref(channel, TRUE);
- g_io_channel_set_encoding(channel, NULL, NULL);
- g_io_channel_set_buffered(channel, FALSE);
-
- source = g_io_add_watch(channel,
- G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- signal_handler, NULL);
-
- g_io_channel_unref(channel);
-
- return source;
-}
-
-int interactive(const char *src, const char *dst,
- const char *dst_type, int psm)
-{
- guint input;
- guint signal;
-
- opt_sec_level = g_strdup("low");
-
- opt_src = g_strdup(src);
- opt_dst = g_strdup(dst);
- opt_dst_type = g_strdup(dst_type);
- opt_psm = psm;
-
- prompt = g_string_new(NULL);
-
- event_loop = g_main_loop_new(NULL, FALSE);
-
- input = setup_standard_input();
- signal = setup_signalfd();
-
- rl_attempted_completion_function = commands_completion;
- rl_erase_empty_line = 1;
- rl_callback_handler_install(get_prompt(), parse_line);
-
- g_main_loop_run(event_loop);
-
- rl_callback_handler_remove();
- cmd_disconnect(0, NULL);
- g_source_remove(input);
- g_source_remove(signal);
- g_main_loop_unref(event_loop);
- g_string_free(prompt, TRUE);
-
- g_free(opt_src);
- g_free(opt_dst);
- g_free(opt_sec_level);
-
- return 0;
-}
diff --git a/attrib/utils.c b/attrib/utils.c
deleted file mode 100644
index ca05baaa1e8a..000000000000
--- a/attrib/utils.c
+++ /dev/null
@@ -1,110 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2011 Nokia Corporation
- *
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-
-#include <glib.h>
-
-#include "bluetooth/bluetooth.h"
-#include "bluetooth/hci.h"
-#include "bluetooth/hci_lib.h"
-#include "bluetooth/sdp.h"
-#include "bluetooth/uuid.h"
-
-#include "src/shared/att-types.h"
-#include "btio/btio.h"
-#include "att.h"
-#include "gattrib.h"
-#include "gatt.h"
-#include "gatttool.h"
-
-GIOChannel *gatt_connect(const char *src, const char *dst,
- const char *dst_type, const char *sec_level,
- int psm, int mtu, BtIOConnect connect_cb,
- GError **gerr)
-{
- GIOChannel *chan;
- bdaddr_t sba, dba;
- uint8_t dest_type;
- GError *tmp_err = NULL;
- BtIOSecLevel sec;
-
- str2ba(dst, &dba);
-
- /* Local adapter */
- if (src != NULL) {
- if (!strncmp(src, "hci", 3))
- hci_devba(atoi(src + 3), &sba);
- else
- str2ba(src, &sba);
- } else
- bacpy(&sba, BDADDR_ANY);
-
- /* Not used for BR/EDR */
- if (strcmp(dst_type, "random") == 0)
- dest_type = BDADDR_LE_RANDOM;
- else
- dest_type = BDADDR_LE_PUBLIC;
-
- if (strcmp(sec_level, "medium") == 0)
- sec = BT_IO_SEC_MEDIUM;
- else if (strcmp(sec_level, "high") == 0)
- sec = BT_IO_SEC_HIGH;
- else
- sec = BT_IO_SEC_LOW;
-
- if (psm == 0)
- chan = bt_io_connect(connect_cb, NULL, NULL, &tmp_err,
- BT_IO_OPT_SOURCE_BDADDR, &sba,
- BT_IO_OPT_SOURCE_TYPE, BDADDR_LE_PUBLIC,
- BT_IO_OPT_DEST_BDADDR, &dba,
- BT_IO_OPT_DEST_TYPE, dest_type,
- BT_IO_OPT_CID, BT_ATT_CID,
- BT_IO_OPT_SEC_LEVEL, sec,
- BT_IO_OPT_INVALID);
- else
- chan = bt_io_connect(connect_cb, NULL, NULL, &tmp_err,
- BT_IO_OPT_SOURCE_BDADDR, &sba,
- BT_IO_OPT_DEST_BDADDR, &dba,
- BT_IO_OPT_PSM, psm,
- BT_IO_OPT_IMTU, mtu,
- BT_IO_OPT_SEC_LEVEL, sec,
- BT_IO_OPT_INVALID);
-
- if (tmp_err) {
- g_propagate_error(gerr, tmp_err);
- return NULL;
- }
-
- return chan;
-}
-
-size_t gatt_attr_data_from_string(const char *str, uint8_t **data)
-{
- char tmp[3];
- size_t size, i;
-
- size = strlen(str) / 2;
- *data = g_try_malloc0(size);
- if (*data == NULL)
- return 0;
-
- tmp[2] = '\0';
- for (i = 0; i < size; i++) {
- memcpy(tmp, str + (i * 2), 2);
- (*data)[i] = (uint8_t) strtol(tmp, NULL, 16);
- }
-
- return size;
-}
diff --git a/unit/test-gattrib.c b/unit/test-gattrib.c
deleted file mode 100644
index 81573dfde142..000000000000
--- a/unit/test-gattrib.c
+++ /dev/null
@@ -1,552 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- *
- * BlueZ - Bluetooth protocol stack for Linux
- *
- * Copyright (C) 2014 Google, Inc.
- *
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <inttypes.h>
-#include <string.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-
-#include <glib.h>
-
-#include "src/shared/util.h"
-#include "bluetooth/bluetooth.h"
-#include "bluetooth/uuid.h"
-#include "attrib/att.h"
-#include "attrib/gattrib.h"
-#include "src/log.h"
-
-#define DEFAULT_MTU 23
-
-#define data(args...) ((const unsigned char[]) { args })
-
-struct test_pdu {
- bool valid;
- bool sent;
- bool received;
- const uint8_t *data;
- size_t size;
-};
-
-#define pdu(args...) \
- { \
- .valid = true, \
- .sent = false, \
- .received = false, \
- .data = data(args), \
- .size = sizeof(data(args)), \
- }
-
-struct context {
- GMainLoop *main_loop;
- GIOChannel *att_io;
- GIOChannel *server_io;
- GAttrib *att;
-};
-
-static void setup_context(struct context *cxt, gconstpointer data)
-{
- int err, sv[2];
-
- cxt->main_loop = g_main_loop_new(NULL, FALSE);
- g_assert(cxt->main_loop != NULL);
-
- err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
- g_assert(err == 0);
-
- cxt->att_io = g_io_channel_unix_new(sv[0]);
- g_assert(cxt->att_io != NULL);
-
- g_io_channel_set_close_on_unref(cxt->att_io, TRUE);
-
- cxt->server_io = g_io_channel_unix_new(sv[1]);
- g_assert(cxt->server_io != NULL);
-
- g_io_channel_set_close_on_unref(cxt->server_io, TRUE);
- g_io_channel_set_encoding(cxt->server_io, NULL, NULL);
- g_io_channel_set_buffered(cxt->server_io, FALSE);
-
- cxt->att = g_attrib_new(cxt->att_io, DEFAULT_MTU, false);
- g_assert(cxt->att != NULL);
-}
-
-static void teardown_context(struct context *cxt, gconstpointer data)
-{
- if (cxt->att)
- g_attrib_unref(cxt->att);
-
- g_io_channel_unref(cxt->server_io);
-
- g_io_channel_unref(cxt->att_io);
-
- g_main_loop_unref(cxt->main_loop);
-}
-
-
-static void test_debug(const char *str, void *user_data)
-{
- const char *prefix = user_data;
-
- g_print("%s%s\n", prefix, str);
-}
-
-static void destroy_canary_increment(gpointer data)
-{
- int *canary = data;
- (*canary)++;
-}
-
-static void test_refcount(struct context *cxt, gconstpointer unused)
-{
- GAttrib *extra_ref;
- int destroy_canary = 0;
-
- g_attrib_set_destroy_function(cxt->att, destroy_canary_increment,
- &destroy_canary);
-
- extra_ref = g_attrib_ref(cxt->att);
-
- g_assert(extra_ref == cxt->att);
-
- g_assert(destroy_canary == 0);
-
- g_attrib_unref(extra_ref);
-
- g_assert(destroy_canary == 0);
-
- g_attrib_unref(cxt->att);
-
- g_assert(destroy_canary == 1);
-
- /* Avoid a double-free from the teardown function */
- cxt->att = NULL;
-}
-
-static void test_get_channel(struct context *cxt, gconstpointer unused)
-{
- GIOChannel *chan;
-
- chan = g_attrib_get_channel(cxt->att);
-
- g_assert(chan == cxt->att_io);
-}
-
-struct expect_response {
- struct test_pdu expect;
- struct test_pdu respond;
- GSourceFunc receive_cb;
- gpointer user_data;
-};
-
-static gboolean test_client(GIOChannel *channel, GIOCondition cond,
- gpointer data)
-{
- struct expect_response *cr = data;
- int fd;
- uint8_t buf[256];
- ssize_t len;
- int cmp;
-
- if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
- return FALSE;
-
- fd = g_io_channel_unix_get_fd(channel);
-
- len = read(fd, buf, sizeof(buf));
-
- g_assert(len > 0);
- g_assert_cmpint(len, ==, cr->expect.size);
-
- if (g_test_verbose())
- util_hexdump('?', cr->expect.data, cr->expect.size,
- test_debug, "test_client: ");
-
- cmp = memcmp(cr->expect.data, buf, len);
-
- g_assert(cmp == 0);
-
- cr->expect.received = true;
-
- if (cr->receive_cb != NULL)
- cr->receive_cb(cr->user_data);
-
- if (cr->respond.valid) {
- if (g_test_verbose())
- util_hexdump('<', cr->respond.data, cr->respond.size,
- test_debug, "test_client: ");
- len = write(fd, cr->respond.data, cr->respond.size);
-
- g_assert_cmpint(len, ==, cr->respond.size);
-
- cr->respond.sent = true;
- }
-
- return TRUE;
-}
-
-struct result_data {
- guint8 status;
- guint8 *pdu;
- guint16 len;
- GSourceFunc complete_cb;
- gpointer user_data;
-};
-
-static void result_canary(guint8 status, const guint8 *pdu, guint16 len,
- gpointer data)
-{
- struct result_data *result = data;
-
- result->status = status;
- result->pdu = g_malloc0(len);
- memcpy(result->pdu, pdu, len);
- result->len = len;
-
- if (g_test_verbose())
- util_hexdump('<', pdu, len, test_debug, "result_canary: ");
-
- if (result->complete_cb != NULL)
- result->complete_cb(result->user_data);
-}
-
-static gboolean context_stop_main_loop(gpointer user_data)
-{
- struct context *cxt = user_data;
-
- g_main_loop_quit(cxt->main_loop);
- return FALSE;
-}
-
-static void test_send(struct context *cxt, gconstpointer unused)
-{
- int cmp;
- struct result_data results;
- struct expect_response data = {
- .expect = pdu(0x02, 0x00, 0x02),
- .respond = pdu(0x03, 0x02, 0x03, 0x04),
- .receive_cb = NULL,
- .user_data = NULL,
- };
-
- g_io_add_watch(cxt->server_io, G_IO_IN | G_IO_HUP | G_IO_ERR |
- G_IO_NVAL, test_client, &data);
-
- results.complete_cb = context_stop_main_loop;
- results.user_data = cxt;
-
- g_attrib_send(cxt->att, 0, data.expect.data, data.expect.size,
- result_canary, (gpointer) &results, NULL);
-
- g_main_loop_run(cxt->main_loop);
-
- g_assert(results.pdu != NULL);
-
- g_assert_cmpint(results.len, ==, data.respond.size);
-
- cmp = memcmp(results.pdu, data.respond.data, results.len);
-
- g_assert(cmp == 0);
-
- g_free(results.pdu);
-}
-
-struct event_info {
- struct context *context;
- int event_id;
-};
-
-static gboolean cancel_existing_attrib_event(gpointer user_data)
-{
- struct event_info *info = user_data;
- gboolean canceled;
-
- canceled = g_attrib_cancel(info->context->att, info->event_id);
-
- g_assert(canceled);
-
- g_idle_add(context_stop_main_loop, info->context);
-
- return FALSE;
-}
-
-static void test_cancel(struct context *cxt, gconstpointer unused)
-{
- gboolean canceled;
- struct result_data results;
- struct event_info info;
- struct expect_response data = {
- .expect = pdu(0x02, 0x00, 0x02),
- .respond = pdu(0x03, 0x02, 0x03, 0x04),
- };
-
- g_io_add_watch(cxt->server_io,
- G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- test_client, &data);
-
- results.pdu = NULL;
-
- info.context = cxt;
- info.event_id = g_attrib_send(cxt->att, 0, data.expect.data,
- data.expect.size, result_canary,
- &results, NULL);
-
- data.receive_cb = cancel_existing_attrib_event;
- data.user_data = &info;
-
- g_main_loop_run(cxt->main_loop);
-
- g_assert(results.pdu == NULL);
-
- results.pdu = NULL;
- data.expect.received = false;
- data.respond.sent = false;
-
- info.event_id = g_attrib_send(cxt->att, 0, data.expect.data,
- data.expect.size, result_canary,
- &results, NULL);
-
- canceled = g_attrib_cancel(cxt->att, info.event_id);
- g_assert(canceled);
-
- g_idle_add(context_stop_main_loop, info.context);
-
- g_main_loop_run(cxt->main_loop);
-
- g_assert(!data.expect.received);
- g_assert(!data.respond.sent);
- g_assert(results.pdu == NULL);
-
- /* Invalid ID */
- canceled = g_attrib_cancel(cxt->att, 42);
- g_assert(!canceled);
-}
-
-static void send_test_pdus(gpointer context, struct test_pdu *pdus)
-{
- struct context *cxt = context;
- size_t len;
- int fd;
- struct test_pdu *cur_pdu;
-
- fd = g_io_channel_unix_get_fd(cxt->server_io);
-
- for (cur_pdu = pdus; cur_pdu->valid; cur_pdu++)
- cur_pdu->sent = false;
-
- for (cur_pdu = pdus; cur_pdu->valid; cur_pdu++) {
- if (g_test_verbose())
- util_hexdump('>', cur_pdu->data, cur_pdu->size,
- test_debug, "send_test_pdus: ");
- len = write(fd, cur_pdu->data, cur_pdu->size);
- g_assert_cmpint(len, ==, cur_pdu->size);
- cur_pdu->sent = true;
- }
-
- g_idle_add(context_stop_main_loop, cxt);
- g_main_loop_run(cxt->main_loop);
-}
-
-#define PDU_MTU_RESP pdu(ATT_OP_MTU_RESP, 0x17)
-#define PDU_FIND_INFO_REQ pdu(ATT_OP_FIND_INFO_REQ, 0x01, 0x00, 0xFF, 0xFF)
-#define PDU_NO_ATT_ERR pdu(ATT_OP_ERROR, ATT_OP_FIND_INFO_REQ, 0x00, 0x00, 0x0A)
-#define PDU_IND_NODATA pdu(ATT_OP_HANDLE_IND, 0x01, 0x00)
-#define PDU_INVALID_IND pdu(ATT_OP_HANDLE_IND, 0x14)
-#define PDU_IND_DATA pdu(ATT_OP_HANDLE_IND, 0x14, 0x00, 0x01)
-
-struct expect_test_data {
- struct test_pdu *expected;
- GAttrib *att;
-};
-
-static void notify_canary_expect(const guint8 *pdu, guint16 len, gpointer data)
-{
- struct expect_test_data *expect = data;
- struct test_pdu *expected = expect->expected;
- int cmp;
-
- if (g_test_verbose())
- util_hexdump('<', pdu, len, test_debug,
- "notify_canary_expect: ");
-
- while (expected->valid && expected->received)
- expected++;
-
- g_assert(expected->valid);
-
- if (g_test_verbose())
- util_hexdump('?', expected->data, expected->size, test_debug,
- "notify_canary_expect: ");
-
- g_assert_cmpint(expected->size, ==, len);
-
- cmp = memcmp(pdu, expected->data, expected->size);
-
- g_assert(cmp == 0);
-
- expected->received = true;
-
- if (pdu[0] == ATT_OP_FIND_INFO_REQ) {
- struct test_pdu no_attributes = PDU_NO_ATT_ERR;
- int reqid;
-
- reqid = g_attrib_send(expect->att, 0, no_attributes.data,
- no_attributes.size, NULL, NULL, NULL);
- g_assert(reqid != 0);
- }
-}
-
-static void test_register(struct context *cxt, gconstpointer user_data)
-{
- guint reg_id;
- gboolean canceled;
- struct test_pdu pdus[] = {
- /*
- * Unmatched PDU opcode
- * Unmatched handle (GATTRIB_ALL_REQS) */
- PDU_FIND_INFO_REQ,
- /*
- * Matched PDU opcode
- * Unmatched handle (GATTRIB_ALL_HANDLES) */
- PDU_IND_NODATA,
- /*
- * Matched PDU opcode
- * Invalid length? */
- PDU_INVALID_IND,
- /*
- * Matched PDU opcode
- * Matched handle */
- PDU_IND_DATA,
- { },
- };
- struct test_pdu req_pdus[] = { PDU_FIND_INFO_REQ, { } };
- struct test_pdu all_ind_pdus[] = {
- PDU_IND_NODATA,
- PDU_INVALID_IND,
- PDU_IND_DATA,
- { },
- };
- struct test_pdu followed_ind_pdus[] = { PDU_IND_DATA, { } };
- struct test_pdu *current_pdu;
- struct expect_test_data expect;
-
- expect.att = cxt->att;
-
- /*
- * Without registering anything, should be able to ignore everything but
- * an unexpected response. */
- send_test_pdus(cxt, pdus);
-
- if (g_test_verbose())
- g_print("ALL_REQS, ALL_HANDLES\r\n");
-
- expect.expected = req_pdus;
- reg_id = g_attrib_register(cxt->att, GATTRIB_ALL_REQS,
- GATTRIB_ALL_HANDLES, notify_canary_expect,
- &expect, NULL);
-
- send_test_pdus(cxt, pdus);
-
- canceled = g_attrib_unregister(cxt->att, reg_id);
-
- g_assert(canceled);
-
- for (current_pdu = req_pdus; current_pdu->valid; current_pdu++)
- g_assert(current_pdu->received);
-
- if (g_test_verbose())
- g_print("IND, ALL_HANDLES\r\n");
-
- expect.expected = all_ind_pdus;
- reg_id = g_attrib_register(cxt->att, ATT_OP_HANDLE_IND,
- GATTRIB_ALL_HANDLES, notify_canary_expect,
- &expect, NULL);
-
- send_test_pdus(cxt, pdus);
-
- canceled = g_attrib_unregister(cxt->att, reg_id);
-
- g_assert(canceled);
-
- for (current_pdu = all_ind_pdus; current_pdu->valid; current_pdu++)
- g_assert(current_pdu->received);
-
- if (g_test_verbose())
- g_print("IND, 0x0014\r\n");
-
- expect.expected = followed_ind_pdus;
- reg_id = g_attrib_register(cxt->att, ATT_OP_HANDLE_IND, 0x0014,
- notify_canary_expect, &expect, NULL);
-
- send_test_pdus(cxt, pdus);
-
- canceled = g_attrib_unregister(cxt->att, reg_id);
-
- g_assert(canceled);
-
- for (current_pdu = followed_ind_pdus; current_pdu->valid; current_pdu++)
- g_assert(current_pdu->received);
-
- canceled = g_attrib_unregister(cxt->att, reg_id);
-
- g_assert(!canceled);
-}
-
-static void test_buffers(struct context *cxt, gconstpointer unused)
-{
- size_t buflen;
- uint8_t *buf;
- gboolean success;
-
- buf = g_attrib_get_buffer(cxt->att, &buflen);
- g_assert(buf != 0);
- g_assert_cmpint(buflen, ==, DEFAULT_MTU);
-
- success = g_attrib_set_mtu(cxt->att, 5);
- g_assert(!success);
-
- success = g_attrib_set_mtu(cxt->att, 255);
- g_assert(success);
-
- buf = g_attrib_get_buffer(cxt->att, &buflen);
- g_assert(buf != 0);
- g_assert_cmpint(buflen, ==, 255);
-}
-
-int main(int argc, char *argv[])
-{
- g_test_init(&argc, &argv, NULL);
-
- if (g_test_verbose())
- __btd_log_init("*", 0);
-
- /*
- * Test the GAttrib API behavior
- */
- g_test_add("/gattrib/refcount", struct context, NULL, setup_context,
- test_refcount, teardown_context);
- g_test_add("/gattrib/get_channel", struct context, NULL, setup_context,
- test_get_channel, teardown_context);
- g_test_add("/gattrib/send", struct context, NULL, setup_context,
- test_send, teardown_context);
- g_test_add("/gattrib/cancel", struct context, NULL, setup_context,
- test_cancel, teardown_context);
- g_test_add("/gattrib/register", struct context, NULL, setup_context,
- test_register, teardown_context);
- g_test_add("/gattrib/buffers", struct context, NULL, setup_context,
- test_buffers, teardown_context);
-
- return g_test_run();
-}
--
2.55.0
next prev parent reply other threads:[~2026-09-28 20:01 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-28 20:00 [PATCH BlueZ v6 00/23] Add HoG functional tests and shared/hog Luiz Augusto von Dentz
2026-09-28 20:00 ` [PATCH BlueZ v6 01/23] shared/gatt-client: Fix calling destroy after unregistering notify Luiz Augusto von Dentz
2026-09-28 22:26 ` Add HoG functional tests and shared/hog bluez.test.bot
2026-09-28 20:00 ` [PATCH BlueZ v6 02/23] client/gatt: Fix setting descriptor value from scripts Luiz Augusto von Dentz
2026-09-28 20:00 ` [PATCH BlueZ v6 03/23] client/mgmt: Print Connection Subrate event Luiz Augusto von Dentz
2026-09-28 20:00 ` [PATCH BlueZ v6 04/23] emulator: Default to the latest BR/EDR+LE version Luiz Augusto von Dentz
2026-09-28 20:00 ` [PATCH BlueZ v6 05/23] client/scripts: Add HoG device scripts Luiz Augusto von Dentz
2026-09-28 20:00 ` [PATCH BlueZ v6 06/23] doc: Add functional-hog documentation Luiz Augusto von Dentz
2026-09-28 20:00 ` [PATCH BlueZ v6 07/23] test: functional: add HoG tests Luiz Augusto von Dentz
2026-09-28 20:00 ` [PATCH BlueZ v6 08/23] test: functional: limit the workers by the memory available Luiz Augusto von Dentz
2026-09-28 20:00 ` [PATCH BlueZ v6 09/23] client/agent: Fix crash on Cancel with no pending request Luiz Augusto von Dentz
2026-09-28 20:00 ` [PATCH BlueZ v6 10/23] shared/uhid: Fix size of Get Report reply with a Report ID Luiz Augusto von Dentz
2026-09-28 20:00 ` [PATCH BlueZ v6 11/23] shared/uhid: Keep reading when an event is not available Luiz Augusto von Dentz
2026-09-28 20:00 ` [PATCH BlueZ v6 12/23] shared/tester: Allow expecting a PDU with no response Luiz Augusto von Dentz
2026-09-28 20:00 ` [PATCH BlueZ v6 13/23] shared/gatt-client: Fix calling idle callbacks again while notifying Luiz Augusto von Dentz
2026-09-28 20:00 ` [PATCH BlueZ v6 14/23] shared/gatt-client: Add bt_gatt_client_is_idle Luiz Augusto von Dentz
2026-09-28 20:00 ` [PATCH BlueZ v6 15/23] shared/hog: Add initial implementation Luiz Augusto von Dentz
2026-09-28 20:00 ` [PATCH BlueZ v6 16/23] unit/test-hog: Use shared/hog Luiz Augusto von Dentz
2026-09-28 20:00 ` [PATCH BlueZ v6 17/23] test: functional: change the HoG SCI mode with the HID Control Point Luiz Augusto von Dentz
2026-09-28 20:00 ` [PATCH BlueZ v6 18/23] input/hog: Use shared/hog Luiz Augusto von Dentz
2026-09-28 20:00 ` [PATCH BlueZ v6 19/23] doc: Add CONFIG_HIDRAW to the tester kernel config Luiz Augusto von Dentz
2026-09-28 20:00 ` [PATCH BlueZ v6 20/23] unit/test-uhid: Add Get Report tests Luiz Augusto von Dentz
2026-09-28 20:00 ` [PATCH BlueZ v6 21/23] device: Use bt_att instead of GAttrib Luiz Augusto von Dentz
2026-09-28 20:00 ` Luiz Augusto von Dentz [this message]
2026-09-28 20:00 ` [PATCH BlueZ v6 23/23] attrib: Remove directory Luiz Augusto von Dentz
2026-09-29 20:50 ` [PATCH BlueZ v6 00/23] Add HoG functional tests and shared/hog patchwork-bot+bluetooth
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260928200031.1209311-23-luiz.dentz@gmail.com \
--to=luiz.dentz@gmail.com \
--cc=linux-bluetooth@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox