All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH BlueZ v3 0/7] Csip - Client role
@ 2022-11-22 10:12 Sathish Narasimman
  2022-11-22 10:12 ` [PATCH BlueZ v3 1/7] shared/util: Update UUID database for Csip services Sathish Narasimman
                   ` (7 more replies)
  0 siblings, 8 replies; 16+ messages in thread
From: Sathish Narasimman @ 2022-11-22 10:12 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sathish Narasimman

This version of patch updated with
1. Added btmon decoded log in commit message
2. Fixed few of scan warnings

Sathish Narasimman (7):
  shared/util: Update UUID database for Csip services
  lib/uuid: Add CSIS UUIDs
  main.conf: Add CSIP profile configurable options
  shared/csip: Add initial code for handling CSIP
  profiles: Add initial code for csip plugin
  monitor/att: Add decoding support for CSIP
  tools: Add support to generate RSI using SIRK

 Makefile.am           |   1 +
 Makefile.plugins      |   5 +
 configure.ac          |   4 +
 lib/uuid.h            |   7 +
 monitor/att.c         |  73 ++++++
 profiles/audio/csip.c | 319 ++++++++++++++++++++++++
 src/btd.h             |   9 +
 src/main.c            | 113 +++++++++
 src/main.conf         |  24 ++
 src/shared/csip.c     | 554 ++++++++++++++++++++++++++++++++++++++++++
 src/shared/csip.h     |  44 ++++
 src/shared/util.c     |   3 +
 tools/advtest.c       |  80 +++++-
 13 files changed, 1234 insertions(+), 2 deletions(-)
 create mode 100644 profiles/audio/csip.c
 create mode 100644 src/shared/csip.c
 create mode 100644 src/shared/csip.h

-- 
2.25.1


^ permalink raw reply	[flat|nested] 16+ messages in thread

* [PATCH BlueZ v3 1/7] shared/util: Update UUID database for Csip services
  2022-11-22 10:12 [PATCH BlueZ v3 0/7] Csip - Client role Sathish Narasimman
@ 2022-11-22 10:12 ` Sathish Narasimman
  2022-11-22 12:38   ` Csip - Client role bluez.test.bot
  2022-11-22 20:03   ` [PATCH BlueZ v3 1/7] shared/util: Update UUID database for Csip services Luiz Augusto von Dentz
  2022-11-22 10:12 ` [PATCH BlueZ v3 2/7] lib/uuid: Add CSIS UUIDs Sathish Narasimman
                   ` (6 subsequent siblings)
  7 siblings, 2 replies; 16+ messages in thread
From: Sathish Narasimman @ 2022-11-22 10:12 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sathish Narasimman

This updates UUID database with the values from assigned numbers for
co-ordinated set identification services.
---
 src/shared/util.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/shared/util.c b/src/shared/util.c
index 333023e0dcac..d7fbd2322f7b 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -695,6 +695,9 @@ static const struct {
 	{ 0x2b82, "Volume Offset Control Point"			},
 	{ 0x2b83, "Audio Output Description"			},
 	{ 0x2b84, "Set Identity Resolving Key"			},
+	{ 0x2b85, "Csis Size"					},
+	{ 0x2b86, "Csis Lock"					},
+	{ 0x2b87, "Csis Rank"					},
 	{ 0x2b93, "Media Player Name"				},
 	{ 0x2b94, "Media Player Icon Object ID"			},
 	{ 0x2b95, "Media Player Icon URL"			},
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH BlueZ v3 2/7] lib/uuid: Add CSIS UUIDs
  2022-11-22 10:12 [PATCH BlueZ v3 0/7] Csip - Client role Sathish Narasimman
  2022-11-22 10:12 ` [PATCH BlueZ v3 1/7] shared/util: Update UUID database for Csip services Sathish Narasimman
@ 2022-11-22 10:12 ` Sathish Narasimman
  2022-11-22 10:12 ` [PATCH BlueZ v3 3/7] main.conf: Add CSIP profile configurable options Sathish Narasimman
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Sathish Narasimman @ 2022-11-22 10:12 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sathish Narasimman

This adds Coordinated Set Identification Service UUIDs which will
be used by Coordinated Set Identification Profile.
---
 lib/uuid.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/lib/uuid.h b/lib/uuid.h
index d5e5665e475c..84ff46cd8f36 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -186,6 +186,13 @@ extern "C" {
 #define MEDIA_CP_OP_SUPPORTED_CHRC_UUID         0x2ba5
 #define MEDIA_CONTENT_CONTROL_ID_CHRC_UUID      0x2bba
 
+/* Coordinated Set Identification Profile(CSIP) */
+#define CSIS_UUID					0x1846
+#define CS_SIRK						0x2B84
+#define CS_SIZE						0x2B85
+#define CS_LOCK						0x2B86
+#define CS_RANK						0x2B87
+
 typedef struct {
 	enum {
 		BT_UUID_UNSPEC = 0,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH BlueZ v3 3/7] main.conf: Add CSIP profile configurable options
  2022-11-22 10:12 [PATCH BlueZ v3 0/7] Csip - Client role Sathish Narasimman
  2022-11-22 10:12 ` [PATCH BlueZ v3 1/7] shared/util: Update UUID database for Csip services Sathish Narasimman
  2022-11-22 10:12 ` [PATCH BlueZ v3 2/7] lib/uuid: Add CSIS UUIDs Sathish Narasimman
@ 2022-11-22 10:12 ` Sathish Narasimman
  2022-11-22 20:13   ` Luiz Augusto von Dentz
  2022-11-22 10:12 ` [PATCH BlueZ v3 4/7] shared/csip: Add initial code for handling CSIP Sathish Narasimman
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 16+ messages in thread
From: Sathish Narasimman @ 2022-11-22 10:12 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sathish Narasimman

This introduces option to configure main.conf that can be used to
configure co-ordinated set identification profile.
---
 src/btd.h     |   9 ++++
 src/main.c    | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++
 src/main.conf |  24 +++++++++++
 3 files changed, 146 insertions(+)

diff --git a/src/btd.h b/src/btd.h
index 42cffcde43ca..a3683a098689 100644
--- a/src/btd.h
+++ b/src/btd.h
@@ -92,6 +92,13 @@ struct btd_defaults {
 	struct btd_le_defaults le;
 };
 
+struct btd_csis {
+	uint8_t sirk_type;
+	uint8_t sirk_val[16];
+	uint8_t cs_size;
+	uint8_t cs_rank;
+};
+
 struct btd_avdtp_opts {
 	uint8_t  session_mode;
 	uint8_t  stream_mode;
@@ -142,6 +149,8 @@ struct btd_opts {
 	enum jw_repairing_t jw_repairing;
 
 	struct btd_advmon_opts	advmon;
+
+	struct btd_csis csis_defaults;
 };
 
 extern struct btd_opts btd_opts;
diff --git a/src/main.c b/src/main.c
index 99d9c508ff91..abb422961f78 100644
--- a/src/main.c
+++ b/src/main.c
@@ -60,6 +60,9 @@
 #define DEFAULT_TEMPORARY_TIMEOUT         30 /* 30 seconds */
 #define DEFAULT_NAME_REQUEST_RETRY_DELAY 300 /* 5 minutes */
 
+/*CSIP Profile - Server */
+#define DEFAULT_SIRK "761FAE703ED681F0C50B34155B6434FB"
+
 #define SHUTDOWN_GRACE_SECONDS 10
 
 struct btd_opts btd_opts;
@@ -146,6 +149,14 @@ static const char *gatt_options[] = {
 	NULL
 };
 
+static const char *csip_options[] = {
+	"CsisSirkType",
+	"CsisSirkValue",
+	"CsisSize",
+	"CsisRank",
+	NULL
+};
+
 static const char *avdtp_options[] = {
 	"SessionMode",
 	"StreamMode",
@@ -166,11 +177,55 @@ static const struct group_table {
 	{ "LE",		le_options },
 	{ "Policy",	policy_options },
 	{ "GATT",	gatt_options },
+	{ "CSIP",	csip_options },
 	{ "AVDTP",	avdtp_options },
 	{ "AdvMon",	advmon_options },
 	{ }
 };
 
+#ifndef MIN
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+#endif
+
+static int8_t check_sirk_alpha_numeric(char *str)
+{
+	int8_t val = 0;
+	char *s = str;
+
+	if (strlen(s) != 32) /* 32 Bytes of Alpha numeric string */
+		return 0;
+
+	for ( ; *s; s++) {
+		if (((*s >= '0') & (*s <= '9'))
+			|| ((*s >= 'a') && (*s <= 'z'))
+			|| ((*s >= 'A') && (*s <= 'Z'))) {
+			val = 1;
+		} else {
+			val = 0;
+			break;
+		}
+	}
+
+	return val;
+}
+
+static size_t hex2bin(const char *hexstr, uint8_t *buf, size_t buflen)
+{
+	size_t i, len;
+
+	if (!hexstr)
+		return 0;
+
+	len = MIN((strlen(hexstr) / 2), buflen);
+	memset(buf, 0, len);
+
+	for (i = 0; i < len; i++) {
+		if (sscanf(hexstr + (i * 2), "%02hhX", &buf[i]) != 1)
+			continue;
+	}
+
+	return len;
+}
 
 GKeyFile *btd_get_main_conf(void)
 {
@@ -939,6 +994,58 @@ static void parse_config(GKeyFile *config)
 		btd_opts.gatt_channels = val;
 	}
 
+	val = g_key_file_get_integer(config, "CSIP", "CsisSirkType", &err);
+	if (err) {
+		DBG("%s", err->message);
+		g_clear_error(&err);
+	} else {
+		val = MIN(val, 2);
+		val = MAX(val, 1);
+		DBG("Csis Type: %u", val);
+		btd_opts.csis_defaults.cs_size = val;
+	}
+
+	str = g_key_file_get_string(config, "CSIP", "CsisSirkValue", &err);
+	if (err) {
+		DBG("%s", err->message);
+		g_clear_error(&err);
+	} else {
+		DBG("Csis Sirk: %s", str);
+
+		if (!check_sirk_alpha_numeric(str)) {
+			DBG("SIRK is not apha numeric Value");
+			return;
+		}
+
+		btd_opts.csis_defaults.sirk_type = 1; /* Plain Text - Type*/
+		hex2bin(str, btd_opts.csis_defaults.sirk_val,
+			sizeof(btd_opts.csis_defaults.sirk_val));
+
+		g_free(str);
+	}
+
+	val = g_key_file_get_integer(config, "CSIP", "CsisSize", &err);
+	if (err) {
+		DBG("%s", err->message);
+		g_clear_error(&err);
+	} else {
+		val = MIN(val, 0xFF);
+		val = MAX(val, 0);
+		DBG("Csis Size: %u", val);
+		btd_opts.csis_defaults.cs_size = val;
+	}
+
+	val = g_key_file_get_integer(config, "CSIP", "CsisRank", &err);
+	if (err) {
+		DBG("%s", err->message);
+		g_clear_error(&err);
+	} else {
+		val = MIN(val, 0xFF);
+		val = MAX(val, 0);
+		DBG("Csis Rank: %u", val);
+		btd_opts.csis_defaults.cs_rank = val;
+	}
+
 	str = g_key_file_get_string(config, "AVDTP", "SessionMode", &err);
 	if (err) {
 		DBG("%s", err->message);
@@ -1014,6 +1121,12 @@ static void init_defaults(void)
 	btd_opts.defaults.br.scan_type = 0xFFFF;
 	btd_opts.defaults.le.enable_advmon_interleave_scan = 0xFF;
 
+	btd_opts.csis_defaults.sirk_type = 1;
+	hex2bin(DEFAULT_SIRK, btd_opts.csis_defaults.sirk_val,
+			sizeof(btd_opts.csis_defaults.sirk_val));
+	btd_opts.csis_defaults.cs_size = 1;
+	btd_opts.csis_defaults.cs_rank = 1;
+
 	if (sscanf(VERSION, "%hhu.%hhu", &major, &minor) != 2)
 		return;
 
diff --git a/src/main.conf b/src/main.conf
index f187c9aaa482..5378472ef0d4 100644
--- a/src/main.conf
+++ b/src/main.conf
@@ -258,6 +258,30 @@
 # Default to 3
 #Channels = 3
 
+[CSIP]
+# CSIP - Co-ordinated Set Identification Profile
+# SIRK Types which determines the value type for CsisSirkValue
+# Possible values:
+# 1 - Plain text
+# 2 - encrypted
+#CsisSirkType = 1
+
+# CSIP - Co-ordinated Set Identification Profile
+# SIRK - Set Identification resolution key which is common for all the
+# sets. They SIRK key is used to identify its sets. This can be any
+# 128 bit value.
+# Possible Values:
+# 16 byte hexadecimal value
+#CsisSirkValue = 861FAE703ED681F0C50B34155B6434FB
+
+#CSIP - Size
+#Total no of sets belongs to this Profile
+#CsisSize = 1
+
+#CSIP - Rank
+#Rank for the device
+#CsisRank = 1
+
 [AVDTP]
 # AVDTP L2CAP Signalling Channel Mode.
 # Possible values:
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH BlueZ v3 4/7] shared/csip: Add initial code for handling CSIP
  2022-11-22 10:12 [PATCH BlueZ v3 0/7] Csip - Client role Sathish Narasimman
                   ` (2 preceding siblings ...)
  2022-11-22 10:12 ` [PATCH BlueZ v3 3/7] main.conf: Add CSIP profile configurable options Sathish Narasimman
@ 2022-11-22 10:12 ` Sathish Narasimman
  2022-11-22 20:37   ` Luiz Augusto von Dentz
  2022-11-22 10:12 ` [PATCH BlueZ v3 5/7] profiles: Add initial code for csip plugin Sathish Narasimman
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 16+ messages in thread
From: Sathish Narasimman @ 2022-11-22 10:12 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sathish Narasimman

This adds initial code for Coordinated Set Identification Profile.
---
 Makefile.am       |   1 +
 src/shared/csip.c | 554 ++++++++++++++++++++++++++++++++++++++++++++++
 src/shared/csip.h |  44 ++++
 3 files changed, 599 insertions(+)
 create mode 100644 src/shared/csip.c
 create mode 100644 src/shared/csip.h

diff --git a/Makefile.am b/Makefile.am
index aa3a5e053cd8..b546a1803dfd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -233,6 +233,7 @@ shared_sources = src/shared/io.h src/shared/timeout.h \
 			src/shared/bap.h src/shared/bap.c src/shared/ascs.h \
 			src/shared/mcs.h src/shared/mcp.h src/shared/mcp.c \
 			src/shared/vcp.c src/shared/vcp.h \
+			src/shared/csip.c src/shared/csip.h \
 			src/shared/lc3.h src/shared/tty.h
 
 if READLINE
diff --git a/src/shared/csip.c b/src/shared/csip.c
new file mode 100644
index 000000000000..98e42d914b16
--- /dev/null
+++ b/src/shared/csip.c
@@ -0,0 +1,554 @@
+// SPDX-License-Identifier: LGPL-2.1-or-later
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2022  Intel Corporation. All rights reserved.
+ *
+ */
+
+#define _GNU_SOURCE
+#include <inttypes.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/uuid.h"
+
+#include "src/shared/queue.h"
+#include "src/shared/util.h"
+#include "src/shared/timeout.h"
+#include "src/shared/att.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-server.h"
+#include "src/shared/gatt-client.h"
+#include "src/shared/csip.h"
+#include "src/btd.h"
+
+#define DBG(_csip, fmt, arg...) \
+	csip_debug(_csip, "%s:%s() " fmt, __FILE__, __func__, ## arg)
+
+/* SIRK is now hardcoded in the code. This can be moved
+ * to a configuration file. Since the code is to validate
+ * the CSIP use case of set member
+ */
+#define SIRK "761FAE703ED681F0C50B34155B6434FB"
+#define CSIS_SIZE	0x02
+#define CSIS_LOCK	0x01
+#define CSIS_RANK	0x01
+#define CSIS_PLAINTEXT	0x01
+#define CSIS_ENC	0x02
+
+struct bt_csip_db {
+	struct gatt_db *db;
+	struct bt_csis *csis;
+};
+
+struct csis_sirk {
+	uint8_t type;
+	uint8_t val[16];
+} __packed;
+
+struct bt_csis {
+	struct bt_csip_db *cdb;
+	struct csis_sirk *sirk;
+	uint8_t cs_size;
+	uint8_t cs_lock;
+	uint8_t cs_rank;
+	struct gatt_db_attribute *service;
+	struct gatt_db_attribute *csirk;
+	struct gatt_db_attribute *csize;
+	struct gatt_db_attribute *cslock;
+	struct gatt_db_attribute *cslock_ccc;
+	struct gatt_db_attribute *crank;
+};
+
+struct bt_csip_cb {
+	unsigned int id;
+	bt_csip_func_t attached;
+	bt_csip_func_t detached;
+	void *user_data;
+};
+
+struct bt_csip {
+	int ref_count;
+	struct bt_csip_db *ldb;
+	struct bt_csip_db *rdb;
+	struct bt_gatt_client *client;
+	struct bt_att *att;
+
+	struct queue *pending;
+
+	bt_csip_debug_func_t debug_func;
+	bt_csip_destroy_func_t debug_destroy;
+	void *debug_data;
+	void *user_data;
+};
+
+static struct queue *csip_db;
+static struct queue *csip_cbs;
+static struct queue *sessions;
+
+static void csip_detached(void *data, void *user_data)
+{
+	struct bt_csip_cb *cb = data;
+	struct bt_csip *csip = user_data;
+
+	cb->detached(csip, cb->user_data);
+}
+
+void bt_csip_detach(struct bt_csip *csip)
+{
+	if (!queue_remove(sessions, csip))
+		return;
+
+	bt_gatt_client_unref(csip->client);
+	csip->client = NULL;
+
+	queue_foreach(csip_cbs, csip_detached, csip);
+}
+
+static void csip_db_free(void *data)
+{
+	struct bt_csip_db *cdb = data;
+
+	if (!cdb)
+		return;
+
+	gatt_db_unref(cdb->db);
+
+	free(cdb->csis);
+	free(cdb);
+}
+static void csip_free(void *data)
+{
+	struct bt_csip *csip = data;
+
+	bt_csip_detach(csip);
+
+	csip_db_free(csip->rdb);
+
+	queue_destroy(csip->pending, NULL);
+
+	free(csip);
+}
+
+struct bt_att *bt_csip_get_att(struct bt_csip *csip)
+{
+	if (!csip)
+		return NULL;
+
+	if (csip->att)
+		return csip->att;
+
+	return bt_gatt_client_get_att(csip->client);
+}
+
+struct bt_csip *bt_csip_ref(struct bt_csip *csip)
+{
+	if (!csip)
+		return NULL;
+
+	__sync_fetch_and_add(&csip->ref_count, 1);
+
+	return csip;
+}
+
+void bt_csip_unref(struct bt_csip *csip)
+{
+	if (!csip)
+		return;
+
+	if (__sync_sub_and_fetch(&csip->ref_count, 1))
+		return;
+
+	csip_free(csip);
+}
+
+static void csip_debug(struct bt_csip *csip, const char *format, ...)
+{
+	va_list ap;
+
+	if (!csip || !format || !csip->debug_func)
+		return;
+
+	va_start(ap, format);
+	util_debug_va(csip->debug_func, csip->debug_data, format, ap);
+	va_end(ap);
+}
+
+static void csis_sirk_read(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	struct bt_csis *csis = user_data;
+	struct iovec iov;
+
+	iov.iov_base = csis->sirk;
+	iov.iov_len = sizeof(struct csis_sirk);
+
+	gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base,
+							iov.iov_len);
+}
+
+static void csis_size_read(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	struct bt_csis *csis = user_data;
+	struct iovec iov;
+
+	iov.iov_base = &csis->cs_size;
+	iov.iov_len = sizeof(csis->cs_size);
+
+	gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base,
+							iov.iov_len);
+}
+
+static void csis_lock_read_cb(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	uint8_t value = CSIS_LOCK;
+
+	gatt_db_attribute_read_result(attrib, id, 0, &value, sizeof(value));
+}
+
+static void csis_lock_write_cb(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				const uint8_t *value, size_t len,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	gatt_db_attribute_write_result(attrib, id, 0);
+}
+
+static void csis_rank_read_cb(struct gatt_db_attribute *attrib,
+				unsigned int id, uint16_t offset,
+				uint8_t opcode, struct bt_att *att,
+				void *user_data)
+{
+	uint8_t value = CSIS_RANK;
+
+	gatt_db_attribute_read_result(attrib, id, 0, &value, sizeof(value));
+}
+
+static struct bt_csis *csis_new(struct gatt_db *db)
+{
+	struct bt_csis *csis;
+	struct csis_sirk *sirk;
+	bt_uuid_t uuid;
+
+	/* For Common Audio Service*/
+	struct gatt_db_attribute *service;
+
+	if (!db)
+		return NULL;
+
+	csis = new0(struct bt_csis, 1);
+	sirk = new0(struct csis_sirk, 1);
+
+	sirk->type = btd_opts.csis_defaults.sirk_type;
+	memcpy(sirk->val, btd_opts.csis_defaults.sirk_val,
+			sizeof(sirk->val));
+	csis->sirk = sirk;
+	csis->cs_size = btd_opts.csis_defaults.cs_size;
+	csis->cs_lock = 1;
+	csis->cs_rank = btd_opts.csis_defaults.cs_rank;
+
+	/* Populate DB with CSIS attributes */
+	bt_uuid16_create(&uuid, CSIS_UUID);
+	csis->service = gatt_db_add_service(db, &uuid, true, 10);
+
+	bt_uuid16_create(&uuid, CS_SIRK);
+	csis->csirk = gatt_db_service_add_characteristic(csis->service,
+					&uuid,
+					BT_ATT_PERM_READ,
+					BT_GATT_CHRC_PROP_READ,
+					csis_sirk_read, NULL,
+					csis);
+
+	bt_uuid16_create(&uuid, CS_SIZE);
+	csis->csize = gatt_db_service_add_characteristic(csis->service,
+					&uuid,
+					BT_ATT_PERM_READ,
+					BT_GATT_CHRC_PROP_READ,
+					csis_size_read, NULL,
+					csis);
+
+	/* Lock */
+	bt_uuid16_create(&uuid, CS_LOCK);
+	csis->cslock = gatt_db_service_add_characteristic(csis->service, &uuid,
+					BT_ATT_PERM_READ,
+					BT_GATT_CHRC_PROP_READ |
+					BT_GATT_CHRC_PROP_WRITE |
+					BT_GATT_CHRC_PROP_NOTIFY,
+					csis_lock_read_cb,
+					csis_lock_write_cb,
+					csis);
+
+	csis->cslock_ccc = gatt_db_service_add_ccc(csis->service,
+					BT_ATT_PERM_READ | BT_ATT_PERM_WRITE);
+
+	/* Rank */
+	bt_uuid16_create(&uuid, CS_RANK);
+	csis->crank = gatt_db_service_add_characteristic(csis->service, &uuid,
+					BT_ATT_PERM_READ,
+					BT_GATT_CHRC_PROP_READ,
+					csis_rank_read_cb,
+					NULL, csis);
+
+	/* Add the CAS service */
+	bt_uuid16_create(&uuid, 0x1853);
+	service = gatt_db_add_service(db, &uuid, true, 2);
+	gatt_db_service_add_included(service, csis->service);
+	gatt_db_service_set_active(service, true);
+	gatt_db_service_add_included(service, csis->service);
+
+	gatt_db_service_set_active(csis->service, true);
+
+	return csis;
+}
+
+static struct bt_csip_db *csip_db_new(struct gatt_db *db)
+{
+	struct bt_csip_db *cdb;
+
+	if (!db)
+		return NULL;
+
+	cdb = new0(struct bt_csip_db, 1);
+	cdb->db = gatt_db_ref(db);
+
+	if (!csip_db)
+		csip_db = queue_new();
+
+	cdb->csis = csis_new(db);
+	cdb->csis->cdb = cdb;
+
+	queue_push_tail(csip_db, cdb);
+
+	return cdb;
+}
+
+bool bt_csip_set_user_data(struct bt_csip *csip, void *user_data)
+{
+	if (!csip)
+		return false;
+
+	csip->user_data = user_data;
+
+	return true;
+}
+
+static bool csip_db_match(const void *data, const void *match_data)
+{
+	const struct bt_csip_db *cdb = data;
+	const struct gatt_db *db = match_data;
+
+	return (cdb->db == db);
+}
+
+static struct bt_csip_db *csip_get_db(struct gatt_db *db)
+{
+	struct bt_csip_db *cdb;
+
+	cdb = queue_find(csip_db, csip_db_match, db);
+	if (cdb)
+		return cdb;
+
+	return csip_db_new(db);
+}
+
+void bt_csip_add_db(struct gatt_db *db)
+{
+	csip_db_new(db);
+}
+
+bool bt_csip_set_debug(struct bt_csip *csip, bt_csip_debug_func_t func,
+			void *user_data, bt_csip_destroy_func_t destroy)
+{
+	if (!csip)
+		return false;
+
+	if (csip->debug_destroy)
+		csip->debug_destroy(csip->debug_data);
+
+	csip->debug_func = func;
+	csip->debug_destroy = destroy;
+	csip->debug_data = user_data;
+
+	return true;
+}
+
+unsigned int bt_csip_register(bt_csip_func_t attached, bt_csip_func_t detached,
+							void *user_data)
+{
+	struct bt_csip_cb *cb;
+	static unsigned int id;
+
+	if (!attached && !detached)
+		return 0;
+
+	if (!csip_cbs)
+		csip_cbs = queue_new();
+
+	cb = new0(struct bt_csip_cb, 1);
+	cb->id = ++id ? id : ++id;
+	cb->attached = attached;
+	cb->detached = detached;
+	cb->user_data = user_data;
+
+	queue_push_tail(csip_cbs, cb);
+
+	return cb->id;
+}
+
+static bool match_id(const void *data, const void *match_data)
+{
+	const struct bt_csip_cb *cb = data;
+	unsigned int id = PTR_TO_UINT(match_data);
+
+	return (cb->id == id);
+}
+
+bool bt_csip_unregister(unsigned int id)
+{
+	struct bt_csip_cb *cb;
+
+	cb = queue_remove_if(csip_cbs, match_id, UINT_TO_PTR(id));
+	if (!cb)
+		return false;
+
+	free(cb);
+
+	return true;
+}
+
+struct bt_csip *bt_csip_new(struct gatt_db *ldb, struct gatt_db *rdb)
+{
+	struct bt_csip *csip;
+	struct bt_csip_db *db;
+
+	if (!ldb)
+		return NULL;
+
+	db = csip_get_db(ldb);
+	if (!db)
+		return NULL;
+
+	csip = new0(struct bt_csip, 1);
+	csip->ldb = db;
+	csip->pending = queue_new();
+
+	if (!rdb)
+		goto done;
+
+	db = new0(struct bt_csip_db, 1);
+	db->db = gatt_db_ref(rdb);
+
+	csip->rdb = db;
+
+done:
+	bt_csip_ref(csip);
+
+	return csip;
+}
+
+static struct bt_csis *csip_get_csis(struct bt_csip *csip)
+{
+	if (!csip)
+		return NULL;
+
+	if (csip->rdb->csis)
+		return csip->rdb->csis;
+
+	csip->rdb->csis = new0(struct bt_csis, 1);
+	csip->rdb->csis->cdb = csip->rdb;
+
+	return csip->rdb->csis;
+}
+
+static void foreach_csis_char(struct gatt_db_attribute *attr, void *user_data)
+{
+	struct bt_csip *csip = user_data;
+	uint16_t value_handle;
+	bt_uuid_t uuid, uuid_csirk, uuid_csize;
+	struct bt_csis *csis;
+
+	if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle,
+						NULL, NULL, &uuid))
+		return;
+
+	bt_uuid16_create(&uuid_csirk, CS_SIRK);
+	bt_uuid16_create(&uuid_csize, CS_SIZE);
+
+	if (!bt_uuid_cmp(&uuid, &uuid_csirk)) {
+		DBG(csip, "CSIS IRK found: handle 0x%04x", value_handle);
+
+		csis = csip_get_csis(csip);
+		if (!csis || csis->sirk)
+			return;
+
+		csis->csirk = attr;
+		return;
+	}
+
+	if (!bt_uuid_cmp(&uuid, &uuid_csize)) {
+		DBG(csip, "CSIS SIZE found: handle 0x%04x", value_handle);
+
+		csis = csip_get_csis(csip);
+		if (!csis)
+			return;
+
+		csis->csize = attr;
+	}
+
+}
+static void foreach_csis_service(struct gatt_db_attribute *attr,
+						void *user_data)
+{
+	struct bt_csip *csip = user_data;
+	struct bt_csis *csis = csip_get_csis(csip);
+
+	csis->service = attr;
+
+	gatt_db_service_set_claimed(attr, true);
+
+	gatt_db_service_foreach_char(attr, foreach_csis_char, csip);
+}
+
+bool bt_csip_attach(struct bt_csip *csip, struct bt_gatt_client *client)
+{
+	bt_uuid_t uuid;
+
+	if (!sessions)
+		sessions = queue_new();
+
+	queue_push_tail(sessions, csip);
+
+	if (!client)
+		return true;
+
+	if (csip->client)
+		return false;
+
+	csip->client = bt_gatt_client_clone(client);
+	if (!csip->client)
+		return false;
+
+	bt_uuid16_create(&uuid, CSIS_UUID);
+	gatt_db_foreach_service(csip->ldb->db, &uuid, foreach_csis_service,
+				csip);
+
+	return true;
+}
+
diff --git a/src/shared/csip.h b/src/shared/csip.h
new file mode 100644
index 000000000000..bd88ccf3a0b2
--- /dev/null
+++ b/src/shared/csip.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2022  Intel Corporation. All rights reserved.
+ *
+ */
+
+#include <stdbool.h>
+#include <inttypes.h>
+
+#include "src/shared/io.h"
+
+#ifndef __packed
+#define __packed __attribute__((packed))
+#endif
+
+struct bt_csip;
+
+typedef void (*bt_csip_destroy_func_t)(void *user_data);
+typedef void (*bt_csip_debug_func_t)(const char *str, void *user_data);
+typedef void (*bt_csip_func_t)(struct bt_csip *csip, void *user_data);
+struct bt_csip *bt_csip_ref(struct bt_csip *csip);
+void bt_csip_unref(struct bt_csip *csip);
+
+void bt_csip_add_db(struct gatt_db *db);
+
+bool bt_csip_attach(struct bt_csip *csip, struct bt_gatt_client *client);
+void bt_csip_detach(struct bt_csip *csip);
+
+bool bt_csip_set_debug(struct bt_csip *csip, bt_csip_debug_func_t func,
+			void *user_data, bt_csip_destroy_func_t destroy);
+
+struct bt_att *bt_csip_get_att(struct bt_csip *csip);
+
+bool bt_csip_set_user_data(struct bt_csip *csip, void *user_data);
+
+/* Session related function */
+unsigned int bt_csip_register(bt_csip_func_t added, bt_csip_func_t removed,
+							void *user_data);
+bool bt_csip_unregister(unsigned int id);
+struct bt_csip *bt_csip_new(struct gatt_db *ldb, struct gatt_db *rdb);
+
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH BlueZ v3 5/7] profiles: Add initial code for csip plugin
  2022-11-22 10:12 [PATCH BlueZ v3 0/7] Csip - Client role Sathish Narasimman
                   ` (3 preceding siblings ...)
  2022-11-22 10:12 ` [PATCH BlueZ v3 4/7] shared/csip: Add initial code for handling CSIP Sathish Narasimman
@ 2022-11-22 10:12 ` Sathish Narasimman
  2022-11-22 20:30   ` Luiz Augusto von Dentz
  2022-11-22 10:12 ` [PATCH BlueZ v3 6/7] monitor/att: Add decoding support for CSIP Sathish Narasimman
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 16+ messages in thread
From: Sathish Narasimman @ 2022-11-22 10:12 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sathish Narasimman

This adds initial code for csip plugin which handles Coordinated
set identification Profile and Coordinated Set Identification
Service.
---
 Makefile.plugins      |   5 +
 configure.ac          |   4 +
 profiles/audio/csip.c | 319 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 328 insertions(+)
 create mode 100644 profiles/audio/csip.c

diff --git a/Makefile.plugins b/Makefile.plugins
index 20cac384ef44..0f119e8714b7 100644
--- a/Makefile.plugins
+++ b/Makefile.plugins
@@ -131,3 +131,8 @@ if VCP
 builtin_modules += vcp
 builtin_sources += profiles/audio/vcp.c
 endif
+
+if CSIP
+builtin_modules += csip
+builtin_sources += profiles/audio/csip.c
+endif
diff --git a/configure.ac b/configure.ac
index f9f0faf573ca..17c5f904a5c2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -207,6 +207,10 @@ AC_ARG_ENABLE(vcp, AS_HELP_STRING([--disable-vcp],
 		[disable VCP profile]), [enable_vcp=${enableval}])
 AM_CONDITIONAL(VCP, test "${enable_vcp}" != "no")
 
+AC_ARG_ENABLE(csip, AS_HELP_STRING([--disable-csip],
+		[disable CSIP profile]), [enable_csip=${enableval}])
+AM_CONDITIONAL(CSIP, test "${enable_csip}" != "no")
+
 AC_ARG_ENABLE(tools, AS_HELP_STRING([--disable-tools],
 		[disable Bluetooth tools]), [enable_tools=${enableval}])
 AM_CONDITIONAL(TOOLS, test "${enable_tools}" != "no")
diff --git a/profiles/audio/csip.c b/profiles/audio/csip.c
new file mode 100644
index 000000000000..c00065bda676
--- /dev/null
+++ b/profiles/audio/csip.c
@@ -0,0 +1,319 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2022 Intel Corporation. All rights reserved.
+ *
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define _GNU_SOURCE
+
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "gdbus/gdbus.h"
+
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/sdp.h"
+#include "lib/uuid.h"
+
+#include "src/dbus-common.h"
+#include "src/shared/util.h"
+#include "src/shared/att.h"
+#include "src/shared/queue.h"
+#include "src/shared/gatt-db.h"
+#include "src/shared/gatt-client.h"
+#include "src/shared/gatt-server.h"
+#include "src/shared/csip.h"
+
+#include "btio/btio.h"
+#include "src/plugin.h"
+#include "src/adapter.h"
+#include "src/gatt-database.h"
+#include "src/device.h"
+#include "src/profile.h"
+#include "src/service.h"
+#include "src/log.h"
+#include "src/error.h"
+
+#define CSIS_UUID_STR "00001846-0000-1000-8000-00805f9b34fb"
+
+struct csip_data {
+	struct btd_device *device;
+	struct btd_service *service;
+	struct bt_csip *csip;
+};
+
+static struct queue *sessions;
+
+static void csip_debug(const char *str, void *user_data)
+{
+	DBG_IDX(0xffff, "%s", str);
+}
+
+static struct csip_data *csip_data_new(struct btd_device *device)
+{
+	struct csip_data *data;
+
+	data = new0(struct csip_data, 1);
+	data->device = device;
+
+	return data;
+}
+
+static void csip_data_add(struct csip_data *data)
+{
+	DBG("data %p", data);
+
+	if (queue_find(sessions, NULL, data)) {
+		error("data %p already added", data);
+		return;
+	}
+
+	bt_csip_set_debug(data->csip, csip_debug, NULL, NULL);
+
+	if (!sessions)
+		sessions = queue_new();
+
+	queue_push_tail(sessions, data);
+
+	if (data->service)
+		btd_service_set_user_data(data->service, data);
+}
+
+static int csip_disconnect(struct btd_service *service)
+{
+	DBG("");
+	return 0;
+}
+
+static bool match_data(const void *data, const void *match_data)
+{
+	const struct csip_data *vdata = data;
+	const struct bt_csip *csip = match_data;
+
+	return vdata->csip == csip;
+}
+
+static void csip_data_free(struct csip_data *data)
+{
+	if (data->service) {
+		btd_service_set_user_data(data->service, NULL);
+		bt_csip_set_user_data(data->csip, NULL);
+	}
+
+	bt_csip_unref(data->csip);
+	free(data);
+}
+
+
+static void csip_data_remove(struct csip_data *data)
+{
+	DBG("data %p", data);
+
+	if (!queue_remove(sessions, data))
+		return;
+
+	csip_data_free(data);
+
+	if (queue_isempty(sessions)) {
+		queue_destroy(sessions, NULL);
+		sessions = NULL;
+	}
+}
+
+static void csip_detached(struct bt_csip *csip, void *user_data)
+{
+	struct csip_data *data;
+
+	DBG("%p", csip);
+
+	data = queue_find(sessions, match_data, csip);
+	if (!data) {
+		error("Unable to find csip session");
+		return;
+	}
+
+	csip_data_remove(data);
+}
+
+static void csip_attached(struct bt_csip *csip, void *user_data)
+{
+	struct csip_data *data;
+	struct bt_att *att;
+	struct btd_device *device;
+
+	DBG("%p", csip);
+
+	data = queue_find(sessions, match_data, csip);
+	if (data)
+		return;
+
+	att = bt_csip_get_att(csip);
+	if (!att)
+		return;
+
+	device = btd_adapter_find_device_by_fd(bt_att_get_fd(att));
+	if (!device) {
+		error("Unable to find device");
+		return;
+	}
+
+	data = csip_data_new(device);
+	data->csip = csip;
+
+	csip_data_add(data);
+
+}
+
+static int csip_server_probe(struct btd_profile *p,
+				struct btd_adapter *adapter)
+{
+	struct btd_gatt_database *database = btd_adapter_get_database(adapter);
+
+	DBG("CSIP path %s", adapter_get_path(adapter));
+
+	bt_csip_add_db(btd_gatt_database_get_db(database));
+
+	return 0;
+}
+
+static void csip_server_remove(struct btd_profile *p,
+					struct btd_adapter *adapter)
+{
+	DBG("CSIP remove Adapter");
+}
+
+static int csip_accept(struct btd_service *service)
+{
+	struct btd_device *device = btd_service_get_device(service);
+	struct bt_gatt_client *client = btd_device_get_gatt_client(device);
+	struct csip_data *data = btd_service_get_user_data(service);
+	char addr[18];
+
+	ba2str(device_get_address(device), addr);
+	DBG("%s", addr);
+
+	if (!data) {
+		error("CSIP service not handled by profile");
+		return -EINVAL;
+	}
+
+	if (!bt_csip_attach(data->csip, client)) {
+		error("CSIP unable to attach");
+		return -EINVAL;
+	}
+
+	btd_service_connecting_complete(service, 0);
+
+	return 0;
+}
+
+static int csip_probe(struct btd_service *service)
+{
+	struct btd_device *device = btd_service_get_device(service);
+	struct btd_adapter *adapter = device_get_adapter(device);
+	struct btd_gatt_database *database = btd_adapter_get_database(adapter);
+	struct csip_data *data = btd_service_get_user_data(service);
+	char addr[18];
+
+	ba2str(device_get_address(device), addr);
+	DBG("%s", addr);
+
+	/* Ignore, if we were probed for this device already */
+	if (data) {
+		error("Profile probed twice for the same device!");
+		return -EINVAL;
+	}
+
+	data = csip_data_new(device);
+	data->service = service;
+
+	data->csip = bt_csip_new(btd_gatt_database_get_db(database),
+					btd_device_get_gatt_db(device));
+	if (!data->csip) {
+		error("Unable to create CSIP instance");
+		free(data);
+		return -EINVAL;
+	}
+
+	csip_data_add(data);
+
+	bt_csip_set_user_data(data->csip, service);
+
+	return 0;
+}
+
+static void csip_remove(struct btd_service *service)
+{
+	struct btd_device *device = btd_service_get_device(service);
+	struct csip_data *data;
+	char addr[18];
+
+	ba2str(device_get_address(device), addr);
+	DBG("%s", addr);
+
+	data = btd_service_get_user_data(service);
+	if (!data) {
+		error("CSIP service not handled by profile");
+		return;
+	}
+
+	csip_data_remove(data);
+}
+
+static struct btd_profile csip_profile = {
+	.name		= "csip",
+	.priority	= BTD_PROFILE_PRIORITY_MEDIUM,
+	.remote_uuid	= CSIS_UUID_STR,
+
+	.device_probe	= csip_probe,
+	.device_remove	= csip_remove,
+
+	.accept		= csip_accept,
+	.disconnect	= csip_disconnect,
+
+	.adapter_probe	= csip_server_probe,
+	.adapter_remove	= csip_server_remove,
+};
+
+static unsigned int csip_id;
+
+static int csip_init(void)
+{
+	if (!(g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL)) {
+		warn("D-Bus experimental not enabled");
+		return -ENOTSUP;
+	}
+
+	btd_profile_register(&csip_profile);
+	csip_id = bt_csip_register(csip_attached, csip_detached, NULL);
+
+	return 0;
+}
+
+static void csip_exit(void)
+{
+	if (g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL) {
+		btd_profile_unregister(&csip_profile);
+		bt_csip_unregister(csip_id);
+	}
+}
+
+BLUETOOTH_PLUGIN_DEFINE(csip, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+						csip_init, csip_exit)
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH BlueZ v3 6/7] monitor/att: Add decoding support for CSIP
  2022-11-22 10:12 [PATCH BlueZ v3 0/7] Csip - Client role Sathish Narasimman
                   ` (4 preceding siblings ...)
  2022-11-22 10:12 ` [PATCH BlueZ v3 5/7] profiles: Add initial code for csip plugin Sathish Narasimman
@ 2022-11-22 10:12 ` Sathish Narasimman
  2022-11-22 10:12 ` [PATCH BlueZ v3 7/7] tools: Add support to generate RSI using SIRK Sathish Narasimman
  2022-12-20 23:40 ` [PATCH BlueZ v3 0/7] Csip - Client role patchwork-bot+bluetooth
  7 siblings, 0 replies; 16+ messages in thread
From: Sathish Narasimman @ 2022-11-22 10:12 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sathish Narasimman

This adds decoding support for CSIS attributes
> ACL Data RX: Handle 3585 flags 0x02 dlen 7
      ATT: Read Request (0x0a) len 2
        Handle: 0x0017 Type: Set Identity Resolving Key (0x2b84)
< ACL Data TX: Handle 3585 flags 0x00 dlen 22
      ATT: Read Response (0x0b) len 17
        Value: 01761fae703ed681f0c50b34155b6434fb
        Handle: 0x0017 Type: Set Identity Resolving Key (0x2b84)
          SIRK: 01761fae703ed681f0c50b34155b6434fb
> ACL Data RX: Handle 3585 flags 0x02 dlen 7
      ATT: Read Request (0x0a) len 2
        Handle: 0x001b Type: Csis Lock (0x2b86)
< ACL Data TX: Handle 3585 flags 0x00 dlen 6
      ATT: Read Response (0x0b) len 1
        Value: 01
        Handle: 0x001b Type: Csis Lock (0x2b86)
            CSIP LOCK: 1
> ACL Data RX: Handle 3585 flags 0x02 dlen 7
      ATT: Read Request (0x0a) len 2
        Handle: 0x001e Type: Csis Rank (0x2b87)
< ACL Data TX: Handle 3585 flags 0x00 dlen 6
      ATT: Read Response (0x0b) len 1
        Value: 01
        Handle: 0x001e Type: Csis Rank (0x2b87)
            CSIP Rank: 1
---
 monitor/att.c | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 73 insertions(+)

diff --git a/monitor/att.c b/monitor/att.c
index d14cbd165697..6fd740aa4cd4 100644
--- a/monitor/att.c
+++ b/monitor/att.c
@@ -1733,6 +1733,73 @@ static void pac_context_notify(const struct l2cap_frame *frame)
 	print_pac_context(frame);
 }
 
+static void csip_rank_read(const struct l2cap_frame *frame)
+{
+	uint8_t rank;
+
+	if (!l2cap_frame_get_u8((void *)frame, &rank)) {
+		print_text(COLOR_ERROR, "CSIP Rank: invalid size");
+		goto done;
+	}
+	print_field("    CSIP Rank: %u", rank);
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void csip_lock_read(const struct l2cap_frame *frame)
+{
+	uint8_t lock;
+
+	if (!l2cap_frame_get_u8((void *)frame, &lock)) {
+		print_text(COLOR_ERROR, "CSIP LOCK: invalid size");
+		goto done;
+	}
+	print_field("    CSIP LOCK: %u", lock);
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void print_csip_size(const struct l2cap_frame *frame)
+{
+	uint8_t size;
+
+	if (!l2cap_frame_get_u8((void *)frame, &size)) {
+		print_text(COLOR_ERROR, "CSIP SIZE: invalid size");
+		goto done;
+	}
+	print_field("    CSIP SIZE: %u", size);
+
+done:
+	if (frame->size)
+		print_hex_field("  Data", frame->data, frame->size);
+}
+
+static void csip_size_read(const struct l2cap_frame *frame)
+{
+	print_csip_size(frame);
+}
+
+static void csip_size_notify(const struct l2cap_frame *frame)
+{
+	print_csip_size(frame);
+}
+
+static void csip_sirk_read(const struct l2cap_frame *frame)
+{
+	if (frame->size)
+		print_hex_field("  SIRK", frame->data, frame->size);
+}
+
+static void csip_sirk_notify(const struct l2cap_frame *frame)
+{
+	if (frame->size)
+		print_hex_field("  SIRK", frame->data, frame->size);
+}
+
 static void print_vcs_state(const struct l2cap_frame *frame)
 {
 	uint8_t vol_set, mute, chng_ctr;
@@ -2413,6 +2480,12 @@ struct gatt_handler {
 	GATT_HANDLER(0x2b7d, vol_state_read, NULL, vol_state_notify),
 	GATT_HANDLER(0x2b7e, NULL, vol_cp_write, NULL),
 	GATT_HANDLER(0x2b7f, vol_flag_read, NULL, vol_flag_notify),
+
+	GATT_HANDLER(0x2b84, csip_sirk_read, NULL, csip_sirk_notify),
+	GATT_HANDLER(0x2b85, csip_size_read, NULL, csip_size_notify),
+	GATT_HANDLER(0x2b86, csip_lock_read, NULL, NULL),
+	GATT_HANDLER(0x2b87, csip_rank_read, NULL, NULL),
+
 	GATT_HANDLER(0x2b93, mp_name_read, NULL, mp_name_notify),
 	GATT_HANDLER(0x2b96, NULL, NULL, track_changed_notify),
 	GATT_HANDLER(0x2b97, track_title_read, NULL, track_title_notify),
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* [PATCH BlueZ v3 7/7] tools: Add support to generate RSI using SIRK
  2022-11-22 10:12 [PATCH BlueZ v3 0/7] Csip - Client role Sathish Narasimman
                   ` (5 preceding siblings ...)
  2022-11-22 10:12 ` [PATCH BlueZ v3 6/7] monitor/att: Add decoding support for CSIP Sathish Narasimman
@ 2022-11-22 10:12 ` Sathish Narasimman
  2022-11-22 20:19   ` Luiz Augusto von Dentz
  2022-12-20 23:40 ` [PATCH BlueZ v3 0/7] Csip - Client role patchwork-bot+bluetooth
  7 siblings, 1 reply; 16+ messages in thread
From: Sathish Narasimman @ 2022-11-22 10:12 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sathish Narasimman

The patch helps to generate Resolvable set identifier adv data.
which can be used as ADV data during advertisement.
It will be used to identify the device as part of setmember for
Coordinated set identification profile.
Example:
$<path to advtest/>advtest -i "761FAE703ED681F0C50B34155B6434FB"
SIRK: 761FAE703ED681F0C50B34155B6434FB
  RSI:  0x71 0xcb 0xbc 0x7e 0x01 0x84
    Random: bccb71
    Hash:   84017e
---
 tools/advtest.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 78 insertions(+), 2 deletions(-)

diff --git a/tools/advtest.c b/tools/advtest.c
index de036e783325..9ef69ed5124a 100644
--- a/tools/advtest.c
+++ b/tools/advtest.c
@@ -13,6 +13,13 @@
 #include <config.h>
 #endif
 
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
 #include <getopt.h>
 
 #include "lib/bluetooth.h"
@@ -32,6 +39,9 @@
 			"\xe1\x23\x99\xc1\xca\x9a\xc3\x31"
 #define SCAN_IRK	"\xfa\x73\x09\x11\x3f\x03\x37\x0f" \
 			"\xf4\xf9\x93\x1e\xf9\xa3\x63\xa6"
+#ifndef MIN
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+#endif
 
 static struct mgmt *mgmt;
 static uint16_t index1 = MGMT_INDEX_NONE;
@@ -43,13 +53,73 @@ static struct bt_hci *scan_dev;
 
 static void print_rpa(const uint8_t addr[6])
 {
-	printf("  Address:  %02x:%02x:%02x:%02x:%02x:%02x\n",
+	printf("  RSI:\t0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
 					addr[5], addr[4], addr[3],
 					addr[2], addr[1], addr[0]);
 	printf("    Random: %02x%02x%02x\n", addr[3], addr[4], addr[5]);
 	printf("    Hash:   %02x%02x%02x\n", addr[0], addr[1], addr[2]);
 }
 
+static size_t hex2bin(const char *hexstr, uint8_t *buf, size_t buflen)
+{
+	size_t i, len;
+
+	len = MIN((strlen(hexstr) / 2), buflen);
+	memset(buf, 0, len);
+
+	for (i = 0; i < len; i++)
+		if (sscanf(hexstr + (i * 2), "%02hhX", &buf[i]) != 1)
+			continue;
+
+
+	return len;
+}
+
+static bool get_random_bytes(void *buf, size_t num_bytes)
+{
+	ssize_t len;
+	int fd;
+
+	fd = open("/dev/urandom", O_RDONLY);
+	if (fd < 0)
+		return false;
+
+	len = read(fd, buf, num_bytes);
+
+	close(fd);
+
+	if (len < 0)
+		return false;
+
+	return true;
+}
+
+static void generate_rsi(char *val)
+{
+	uint8_t sirk[16], hash[3];
+	uint8_t  rsi[6] = {0};
+
+	hex2bin(val, sirk, sizeof(sirk));
+
+	get_random_bytes(&rsi[3], 3);
+
+	rsi[5] &= 0x3f; /* Clear 2 msb */
+	rsi[5] |= 0x40; /* Set 2nd msb */
+
+	crypto = bt_crypto_new();
+	if (!crypto) {
+		fprintf(stderr, "Failed to open crypto interface\n");
+		mainloop_exit_failure();
+		return;
+	}
+
+	bt_crypto_ah(crypto, sirk, rsi + 3, hash);
+	memcpy(rsi, hash, 3);
+
+	print_rpa(rsi);
+}
+
+
 static void scan_le_adv_report(const void *data, uint8_t size,
 							void *user_data)
 {
@@ -351,9 +421,11 @@ static void usage(void)
 	printf("\tadvtest [options]\n");
 	printf("options:\n"
 		"\t-h, --help             Show help options\n");
+	printf(" \t-i  <128bit SIRK>,     Generate RSI ADV Data\n");
 }
 
 static const struct option main_options[] = {
+	{ "hash",   no_argument,       NULL, 'i' },
 	{ "version",   no_argument,       NULL, 'v' },
 	{ "help",      no_argument,       NULL, 'h' },
 	{ }
@@ -366,11 +438,15 @@ int main(int argc ,char *argv[])
 	for (;;) {
 		int opt;
 
-		opt = getopt_long(argc, argv, "vh", main_options, NULL);
+		opt = getopt_long(argc, argv, "i:vh", main_options, NULL);
 		if (opt < 0)
 			break;
 
 		switch (opt) {
+		case 'i':
+			printf("SIRK: %s\n", optarg);
+			generate_rsi(optarg);
+			return EXIT_SUCCESS;
 		case 'v':
 			printf("%s\n", VERSION);
 			return EXIT_SUCCESS;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 16+ messages in thread

* RE: Csip - Client role
  2022-11-22 10:12 ` [PATCH BlueZ v3 1/7] shared/util: Update UUID database for Csip services Sathish Narasimman
@ 2022-11-22 12:38   ` bluez.test.bot
  2022-11-22 20:03   ` [PATCH BlueZ v3 1/7] shared/util: Update UUID database for Csip services Luiz Augusto von Dentz
  1 sibling, 0 replies; 16+ messages in thread
From: bluez.test.bot @ 2022-11-22 12:38 UTC (permalink / raw)
  To: linux-bluetooth, sathish.narasimman

[-- Attachment #1: Type: text/plain, Size: 2664 bytes --]

This is automated email and please do not reply to this email!

Dear submitter,

Thank you for submitting the patches to the linux bluetooth mailing list.
This is a CI test results with your patch series:
PW Link:https://patchwork.kernel.org/project/bluetooth/list/?series=698015

---Test result---

Test Summary:
CheckPatch                    FAIL      5.01 seconds
GitLint                       PASS      2.58 seconds
BuildEll                      PASS      32.32 seconds
BluezMake                     PASS      986.05 seconds
MakeCheck                     PASS      12.80 seconds
MakeDistcheck                 PASS      174.43 seconds
CheckValgrind                 PASS      290.29 seconds
bluezmakeextell               PASS      114.13 seconds
IncrementalBuild              PASS      5622.11 seconds
ScanBuild                     PASS      1194.14 seconds

Details
##############################
Test: CheckPatch - FAIL
Desc: Run checkpatch.pl script
Output:
[BlueZ,v3,3/7] main.conf: Add CSIP profile configurable options
WARNING:STATIC_CONST_CHAR_ARRAY: static const char * array should probably be static const char * const
#119: FILE: src/main.c:152:
+static const char *csip_options[] = {

/github/workspace/src/src/13052136.patch total: 0 errors, 1 warnings, 199 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/src/13052136.patch has style problems, please review.

NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.


[BlueZ,v3,4/7] shared/csip: Add initial code for handling CSIP
WARNING:PREFER_DEFINED_ATTRIBUTE_MACRO: Prefer __packed over __attribute__((packed))
#668: FILE: src/shared/csip.h:16:
+#define __packed __attribute__((packed))

/github/workspace/src/src/13052137.patch total: 0 errors, 1 warnings, 605 lines checked

NOTE: For some of the reported defects, checkpatch may be able to
      mechanically convert to the typical style using --fix or --fix-inplace.

/github/workspace/src/src/13052137.patch has style problems, please review.

NOTE: Ignored message types: COMMIT_MESSAGE COMPLEX_MACRO CONST_STRUCT FILE_PATH_CHANGES MISSING_SIGN_OFF PREFER_PACKED SPDX_LICENSE_TAG SPLIT_STRING SSCANF_TO_KSTRTO

NOTE: If any of the errors are false positives, please report
      them to the maintainer, see CHECKPATCH in MAINTAINERS.




---
Regards,
Linux Bluetooth


^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH BlueZ v3 1/7] shared/util: Update UUID database for Csip services
  2022-11-22 10:12 ` [PATCH BlueZ v3 1/7] shared/util: Update UUID database for Csip services Sathish Narasimman
  2022-11-22 12:38   ` Csip - Client role bluez.test.bot
@ 2022-11-22 20:03   ` Luiz Augusto von Dentz
  1 sibling, 0 replies; 16+ messages in thread
From: Luiz Augusto von Dentz @ 2022-11-22 20:03 UTC (permalink / raw)
  To: Sathish Narasimman; +Cc: linux-bluetooth

Hi Sathish,

On Tue, Nov 22, 2022 at 2:16 AM Sathish Narasimman
<sathish.narasimman@intel.com> wrote:
>
> This updates UUID database with the values from assigned numbers for
> co-ordinated set identification services.
> ---
>  src/shared/util.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/src/shared/util.c b/src/shared/util.c
> index 333023e0dcac..d7fbd2322f7b 100644
> --- a/src/shared/util.c
> +++ b/src/shared/util.c
> @@ -695,6 +695,9 @@ static const struct {
>         { 0x2b82, "Volume Offset Control Point"                 },
>         { 0x2b83, "Audio Output Description"                    },
>         { 0x2b84, "Set Identity Resolving Key"                  },
> +       { 0x2b85, "Csis Size"                                   },
> +       { 0x2b86, "Csis Lock"                                   },
> +       { 0x2b87, "Csis Rank"                                   },

Use the actual attribute name rather than its services e.g:
Coordinated Set Size, etc.

>         { 0x2b93, "Media Player Name"                           },
>         { 0x2b94, "Media Player Icon Object ID"                 },
>         { 0x2b95, "Media Player Icon URL"                       },
> --
> 2.25.1
>


-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH BlueZ v3 3/7] main.conf: Add CSIP profile configurable options
  2022-11-22 10:12 ` [PATCH BlueZ v3 3/7] main.conf: Add CSIP profile configurable options Sathish Narasimman
@ 2022-11-22 20:13   ` Luiz Augusto von Dentz
  2022-11-23  0:07     ` Luiz Augusto von Dentz
  0 siblings, 1 reply; 16+ messages in thread
From: Luiz Augusto von Dentz @ 2022-11-22 20:13 UTC (permalink / raw)
  To: Sathish Narasimman; +Cc: linux-bluetooth

Hi Sathish,


On Tue, Nov 22, 2022 at 2:17 AM Sathish Narasimman
<sathish.narasimman@intel.com> wrote:
>
> This introduces option to configure main.conf that can be used to
> configure co-ordinated set identification profile.
> ---
>  src/btd.h     |   9 ++++
>  src/main.c    | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  src/main.conf |  24 +++++++++++
>  3 files changed, 146 insertions(+)
>
> diff --git a/src/btd.h b/src/btd.h
> index 42cffcde43ca..a3683a098689 100644
> --- a/src/btd.h
> +++ b/src/btd.h
> @@ -92,6 +92,13 @@ struct btd_defaults {
>         struct btd_le_defaults le;
>  };
>
> +struct btd_csis {
> +       uint8_t sirk_type;
> +       uint8_t sirk_val[16];
> +       uint8_t cs_size;
> +       uint8_t cs_rank;
> +};
> +
>  struct btd_avdtp_opts {
>         uint8_t  session_mode;
>         uint8_t  stream_mode;
> @@ -142,6 +149,8 @@ struct btd_opts {
>         enum jw_repairing_t jw_repairing;
>
>         struct btd_advmon_opts  advmon;
> +
> +       struct btd_csis csis_defaults;
>  };
>
>  extern struct btd_opts btd_opts;
> diff --git a/src/main.c b/src/main.c
> index 99d9c508ff91..abb422961f78 100644
> --- a/src/main.c
> +++ b/src/main.c
> @@ -60,6 +60,9 @@
>  #define DEFAULT_TEMPORARY_TIMEOUT         30 /* 30 seconds */
>  #define DEFAULT_NAME_REQUEST_RETRY_DELAY 300 /* 5 minutes */
>
> +/*CSIP Profile - Server */
> +#define DEFAULT_SIRK "761FAE703ED681F0C50B34155B6434FB"
> +
>  #define SHUTDOWN_GRACE_SECONDS 10
>
>  struct btd_opts btd_opts;
> @@ -146,6 +149,14 @@ static const char *gatt_options[] = {
>         NULL
>  };
>
> +static const char *csip_options[] = {
> +       "CsisSirkType",
> +       "CsisSirkValue",
> +       "CsisSize",
> +       "CsisRank",
> +       NULL
> +};
> +
>  static const char *avdtp_options[] = {
>         "SessionMode",
>         "StreamMode",
> @@ -166,11 +177,55 @@ static const struct group_table {
>         { "LE",         le_options },
>         { "Policy",     policy_options },
>         { "GATT",       gatt_options },
> +       { "CSIP",       csip_options },
>         { "AVDTP",      avdtp_options },
>         { "AdvMon",     advmon_options },
>         { }
>  };
>
> +#ifndef MIN
> +#define MIN(x, y) ((x) < (y) ? (x) : (y))
> +#endif
> +
> +static int8_t check_sirk_alpha_numeric(char *str)
> +{
> +       int8_t val = 0;
> +       char *s = str;
> +
> +       if (strlen(s) != 32) /* 32 Bytes of Alpha numeric string */
> +               return 0;
> +
> +       for ( ; *s; s++) {
> +               if (((*s >= '0') & (*s <= '9'))
> +                       || ((*s >= 'a') && (*s <= 'z'))
> +                       || ((*s >= 'A') && (*s <= 'Z'))) {
> +                       val = 1;
> +               } else {
> +                       val = 0;
> +                       break;
> +               }
> +       }
> +
> +       return val;
> +}
> +
> +static size_t hex2bin(const char *hexstr, uint8_t *buf, size_t buflen)
> +{
> +       size_t i, len;
> +
> +       if (!hexstr)
> +               return 0;
> +
> +       len = MIN((strlen(hexstr) / 2), buflen);
> +       memset(buf, 0, len);
> +
> +       for (i = 0; i < len; i++) {
> +               if (sscanf(hexstr + (i * 2), "%02hhX", &buf[i]) != 1)
> +                       continue;
> +       }
> +
> +       return len;
> +}
>
>  GKeyFile *btd_get_main_conf(void)
>  {
> @@ -939,6 +994,58 @@ static void parse_config(GKeyFile *config)
>                 btd_opts.gatt_channels = val;
>         }
>
> +       val = g_key_file_get_integer(config, "CSIP", "CsisSirkType", &err);
> +       if (err) {
> +               DBG("%s", err->message);
> +               g_clear_error(&err);
> +       } else {
> +               val = MIN(val, 2);
> +               val = MAX(val, 1);
> +               DBG("Csis Type: %u", val);
> +               btd_opts.csis_defaults.cs_size = val;
> +       }
> +
> +       str = g_key_file_get_string(config, "CSIP", "CsisSirkValue", &err);
> +       if (err) {
> +               DBG("%s", err->message);
> +               g_clear_error(&err);
> +       } else {
> +               DBG("Csis Sirk: %s", str);
> +
> +               if (!check_sirk_alpha_numeric(str)) {
> +                       DBG("SIRK is not apha numeric Value");
> +                       return;
> +               }
> +
> +               btd_opts.csis_defaults.sirk_type = 1; /* Plain Text - Type*/
> +               hex2bin(str, btd_opts.csis_defaults.sirk_val,
> +                       sizeof(btd_opts.csis_defaults.sirk_val));
> +
> +               g_free(str);
> +       }
> +
> +       val = g_key_file_get_integer(config, "CSIP", "CsisSize", &err);
> +       if (err) {
> +               DBG("%s", err->message);
> +               g_clear_error(&err);
> +       } else {
> +               val = MIN(val, 0xFF);
> +               val = MAX(val, 0);
> +               DBG("Csis Size: %u", val);
> +               btd_opts.csis_defaults.cs_size = val;
> +       }
> +
> +       val = g_key_file_get_integer(config, "CSIP", "CsisRank", &err);
> +       if (err) {
> +               DBG("%s", err->message);
> +               g_clear_error(&err);
> +       } else {
> +               val = MIN(val, 0xFF);
> +               val = MAX(val, 0);
> +               DBG("Csis Rank: %u", val);
> +               btd_opts.csis_defaults.cs_rank = val;
> +       }
> +
>         str = g_key_file_get_string(config, "AVDTP", "SessionMode", &err);
>         if (err) {
>                 DBG("%s", err->message);
> @@ -1014,6 +1121,12 @@ static void init_defaults(void)
>         btd_opts.defaults.br.scan_type = 0xFFFF;
>         btd_opts.defaults.le.enable_advmon_interleave_scan = 0xFF;
>
> +       btd_opts.csis_defaults.sirk_type = 1;
> +       hex2bin(DEFAULT_SIRK, btd_opts.csis_defaults.sirk_val,
> +                       sizeof(btd_opts.csis_defaults.sirk_val));
> +       btd_opts.csis_defaults.cs_size = 1;
> +       btd_opts.csis_defaults.cs_rank = 1;
> +
>         if (sscanf(VERSION, "%hhu.%hhu", &major, &minor) != 2)
>                 return;
>
> diff --git a/src/main.conf b/src/main.conf
> index f187c9aaa482..5378472ef0d4 100644
> --- a/src/main.conf
> +++ b/src/main.conf
> @@ -258,6 +258,30 @@
>  # Default to 3
>  #Channels = 3
>
> +[CSIP]

Let's use Set as a group name.

> +# CSIP - Co-ordinated Set Identification Profile
> +# SIRK Types which determines the value type for CsisSirkValue
> +# Possible values:
> +# 1 - Plain text
> +# 2 - encrypted
> +#CsisSirkType = 1

Let's not use the type directly here so perhaps something like
KeyType=plaintext,encrypted, etc, and it is important to say what is
the default value.

> +
> +# CSIP - Co-ordinated Set Identification Profile
> +# SIRK - Set Identification resolution key which is common for all the
> +# sets. They SIRK key is used to identify its sets. This can be any
> +# 128 bit value.
> +# Possible Values:
> +# 16 byte hexadecimal value
> +#CsisSirkValue = 861FAE703ED681F0C50B34155B6434FB

Let's use Key instead, since this would belong to [Set] group that is
enough to disambiguate.

> +
> +#CSIP - Size
> +#Total no of sets belongs to this Profile
> +#CsisSize = 1

Size

> +#CSIP - Rank
> +#Rank for the device
> +#CsisRank = 1

Rank

>  [AVDTP]
>  # AVDTP L2CAP Signalling Channel Mode.
>  # Possible values:
> --
> 2.25.1
>


--
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH BlueZ v3 7/7] tools: Add support to generate RSI using SIRK
  2022-11-22 10:12 ` [PATCH BlueZ v3 7/7] tools: Add support to generate RSI using SIRK Sathish Narasimman
@ 2022-11-22 20:19   ` Luiz Augusto von Dentz
  0 siblings, 0 replies; 16+ messages in thread
From: Luiz Augusto von Dentz @ 2022-11-22 20:19 UTC (permalink / raw)
  To: Sathish Narasimman; +Cc: linux-bluetooth

Hi Sathish,

On Tue, Nov 22, 2022 at 2:16 AM Sathish Narasimman
<sathish.narasimman@intel.com> wrote:
>
> The patch helps to generate Resolvable set identifier adv data.
> which can be used as ADV data during advertisement.
> It will be used to identify the device as part of setmember for
> Coordinated set identification profile.
> Example:
> $<path to advtest/>advtest -i "761FAE703ED681F0C50B34155B6434FB"
> SIRK: 761FAE703ED681F0C50B34155B6434FB
>   RSI:  0x71 0xcb 0xbc 0x7e 0x01 0x84
>     Random: bccb71
>     Hash:   84017e
> ---
>  tools/advtest.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 78 insertions(+), 2 deletions(-)
>
> diff --git a/tools/advtest.c b/tools/advtest.c
> index de036e783325..9ef69ed5124a 100644
> --- a/tools/advtest.c
> +++ b/tools/advtest.c
> @@ -13,6 +13,13 @@
>  #include <config.h>
>  #endif
>
> +#include <stdlib.h>
> +
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +
>  #include <getopt.h>
>
>  #include "lib/bluetooth.h"
> @@ -32,6 +39,9 @@
>                         "\xe1\x23\x99\xc1\xca\x9a\xc3\x31"
>  #define SCAN_IRK       "\xfa\x73\x09\x11\x3f\x03\x37\x0f" \
>                         "\xf4\xf9\x93\x1e\xf9\xa3\x63\xa6"
> +#ifndef MIN
> +#define MIN(x, y) ((x) < (y) ? (x) : (y))
> +#endif
>
>  static struct mgmt *mgmt;
>  static uint16_t index1 = MGMT_INDEX_NONE;
> @@ -43,13 +53,73 @@ static struct bt_hci *scan_dev;
>
>  static void print_rpa(const uint8_t addr[6])
>  {
> -       printf("  Address:  %02x:%02x:%02x:%02x:%02x:%02x\n",
> +       printf("  RSI:\t0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
>                                         addr[5], addr[4], addr[3],
>                                         addr[2], addr[1], addr[0]);
>         printf("    Random: %02x%02x%02x\n", addr[3], addr[4], addr[5]);
>         printf("    Hash:   %02x%02x%02x\n", addr[0], addr[1], addr[2]);
>  }
>
> +static size_t hex2bin(const char *hexstr, uint8_t *buf, size_t buflen)
> +{
> +       size_t i, len;
> +
> +       len = MIN((strlen(hexstr) / 2), buflen);
> +       memset(buf, 0, len);
> +
> +       for (i = 0; i < len; i++)
> +               if (sscanf(hexstr + (i * 2), "%02hhX", &buf[i]) != 1)
> +                       continue;
> +
> +
> +       return len;
> +}
> +
> +static bool get_random_bytes(void *buf, size_t num_bytes)
> +{
> +       ssize_t len;
> +       int fd;
> +
> +       fd = open("/dev/urandom", O_RDONLY);
> +       if (fd < 0)
> +               return false;
> +
> +       len = read(fd, buf, num_bytes);
> +
> +       close(fd);
> +
> +       if (len < 0)
> +               return false;
> +
> +       return true;
> +}
> +
> +static void generate_rsi(char *val)
> +{
> +       uint8_t sirk[16], hash[3];
> +       uint8_t  rsi[6] = {0};
> +
> +       hex2bin(val, sirk, sizeof(sirk));
> +
> +       get_random_bytes(&rsi[3], 3);
> +
> +       rsi[5] &= 0x3f; /* Clear 2 msb */
> +       rsi[5] |= 0x40; /* Set 2nd msb */
> +
> +       crypto = bt_crypto_new();
> +       if (!crypto) {
> +               fprintf(stderr, "Failed to open crypto interface\n");
> +               mainloop_exit_failure();
> +               return;
> +       }
> +
> +       bt_crypto_ah(crypto, sirk, rsi + 3, hash);
> +       memcpy(rsi, hash, 3);
> +
> +       print_rpa(rsi);
> +}
> +
> +
>  static void scan_le_adv_report(const void *data, uint8_t size,
>                                                         void *user_data)
>  {
> @@ -351,9 +421,11 @@ static void usage(void)
>         printf("\tadvtest [options]\n");
>         printf("options:\n"
>                 "\t-h, --help             Show help options\n");
> +       printf(" \t-i  <128bit SIRK>,     Generate RSI ADV Data\n");
>  }
>
>  static const struct option main_options[] = {
> +       { "hash",   no_argument,       NULL, 'i' },
>         { "version",   no_argument,       NULL, 'v' },
>         { "help",      no_argument,       NULL, 'h' },
>         { }
> @@ -366,11 +438,15 @@ int main(int argc ,char *argv[])
>         for (;;) {
>                 int opt;
>
> -               opt = getopt_long(argc, argv, "vh", main_options, NULL);
> +               opt = getopt_long(argc, argv, "i:vh", main_options, NULL);
>                 if (opt < 0)
>                         break;
>
>                 switch (opt) {
> +               case 'i':
> +                       printf("SIRK: %s\n", optarg);
> +                       generate_rsi(optarg);
> +                       return EXIT_SUCCESS;
>                 case 'v':
>                         printf("%s\n", VERSION);
>                         return EXIT_SUCCESS;
> --
> 2.25.1

I think it would be better if bluetoothd generates the RSI if a
Set.Key has been programmed into the main.conf, that can then check if
there is enough space to enter the RSI in either the ad or scan
response, in the future we may consider having the Sirk be passed on
to the kernel so we can leave it to generate the RSI.

-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH BlueZ v3 5/7] profiles: Add initial code for csip plugin
  2022-11-22 10:12 ` [PATCH BlueZ v3 5/7] profiles: Add initial code for csip plugin Sathish Narasimman
@ 2022-11-22 20:30   ` Luiz Augusto von Dentz
  0 siblings, 0 replies; 16+ messages in thread
From: Luiz Augusto von Dentz @ 2022-11-22 20:30 UTC (permalink / raw)
  To: Sathish Narasimman; +Cc: linux-bluetooth

Hi Sathish,

On Tue, Nov 22, 2022 at 2:16 AM Sathish Narasimman
<sathish.narasimman@intel.com> wrote:
>
> This adds initial code for csip plugin which handles Coordinated
> set identification Profile and Coordinated Set Identification
> Service.
> ---
>  Makefile.plugins      |   5 +
>  configure.ac          |   4 +
>  profiles/audio/csip.c | 319 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 328 insertions(+)
>  create mode 100644 profiles/audio/csip.c
>
> diff --git a/Makefile.plugins b/Makefile.plugins
> index 20cac384ef44..0f119e8714b7 100644
> --- a/Makefile.plugins
> +++ b/Makefile.plugins
> @@ -131,3 +131,8 @@ if VCP
>  builtin_modules += vcp
>  builtin_sources += profiles/audio/vcp.c
>  endif
> +
> +if CSIP
> +builtin_modules += csip
> +builtin_sources += profiles/audio/csip.c
> +endif
> diff --git a/configure.ac b/configure.ac
> index f9f0faf573ca..17c5f904a5c2 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -207,6 +207,10 @@ AC_ARG_ENABLE(vcp, AS_HELP_STRING([--disable-vcp],
>                 [disable VCP profile]), [enable_vcp=${enableval}])
>  AM_CONDITIONAL(VCP, test "${enable_vcp}" != "no")
>
> +AC_ARG_ENABLE(csip, AS_HELP_STRING([--disable-csip],
> +               [disable CSIP profile]), [enable_csip=${enableval}])
> +AM_CONDITIONAL(CSIP, test "${enable_csip}" != "no")
> +
>  AC_ARG_ENABLE(tools, AS_HELP_STRING([--disable-tools],
>                 [disable Bluetooth tools]), [enable_tools=${enableval}])
>  AM_CONDITIONAL(TOOLS, test "${enable_tools}" != "no")
> diff --git a/profiles/audio/csip.c b/profiles/audio/csip.c
> new file mode 100644
> index 000000000000..c00065bda676
> --- /dev/null
> +++ b/profiles/audio/csip.c
> @@ -0,0 +1,319 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + *
> + * BlueZ - Bluetooth protocol stack for Linux
> + *
> + * Copyright (C) 2022 Intel Corporation. All rights reserved.
> + *
> + *
> + */
> +
> +#ifdef HAVE_CONFIG_H
> +#include <config.h>
> +#endif
> +
> +#define _GNU_SOURCE
> +
> +#include <ctype.h>
> +#include <stdbool.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +#include <errno.h>
> +
> +#include <glib.h>
> +
> +#include "gdbus/gdbus.h"
> +
> +#include "lib/bluetooth.h"
> +#include "lib/hci.h"
> +#include "lib/sdp.h"
> +#include "lib/uuid.h"
> +
> +#include "src/dbus-common.h"
> +#include "src/shared/util.h"
> +#include "src/shared/att.h"
> +#include "src/shared/queue.h"
> +#include "src/shared/gatt-db.h"
> +#include "src/shared/gatt-client.h"
> +#include "src/shared/gatt-server.h"
> +#include "src/shared/csip.h"
> +
> +#include "btio/btio.h"
> +#include "src/plugin.h"
> +#include "src/adapter.h"
> +#include "src/gatt-database.h"
> +#include "src/device.h"
> +#include "src/profile.h"
> +#include "src/service.h"
> +#include "src/log.h"
> +#include "src/error.h"
> +
> +#define CSIS_UUID_STR "00001846-0000-1000-8000-00805f9b34fb"
> +
> +struct csip_data {
> +       struct btd_device *device;
> +       struct btd_service *service;
> +       struct bt_csip *csip;
> +};
> +
> +static struct queue *sessions;
> +
> +static void csip_debug(const char *str, void *user_data)
> +{
> +       DBG_IDX(0xffff, "%s", str);
> +}
> +
> +static struct csip_data *csip_data_new(struct btd_device *device)
> +{
> +       struct csip_data *data;
> +
> +       data = new0(struct csip_data, 1);
> +       data->device = device;
> +
> +       return data;
> +}
> +
> +static void csip_data_add(struct csip_data *data)
> +{
> +       DBG("data %p", data);
> +
> +       if (queue_find(sessions, NULL, data)) {
> +               error("data %p already added", data);
> +               return;
> +       }
> +
> +       bt_csip_set_debug(data->csip, csip_debug, NULL, NULL);
> +
> +       if (!sessions)
> +               sessions = queue_new();
> +
> +       queue_push_tail(sessions, data);
> +
> +       if (data->service)
> +               btd_service_set_user_data(data->service, data);
> +}
> +
> +static int csip_disconnect(struct btd_service *service)
> +{
> +       DBG("");
> +       return 0;
> +}
> +
> +static bool match_data(const void *data, const void *match_data)
> +{
> +       const struct csip_data *vdata = data;
> +       const struct bt_csip *csip = match_data;
> +
> +       return vdata->csip == csip;
> +}
> +
> +static void csip_data_free(struct csip_data *data)
> +{
> +       if (data->service) {
> +               btd_service_set_user_data(data->service, NULL);
> +               bt_csip_set_user_data(data->csip, NULL);
> +       }
> +
> +       bt_csip_unref(data->csip);
> +       free(data);
> +}
> +
> +
> +static void csip_data_remove(struct csip_data *data)
> +{
> +       DBG("data %p", data);
> +
> +       if (!queue_remove(sessions, data))
> +               return;
> +
> +       csip_data_free(data);
> +
> +       if (queue_isempty(sessions)) {
> +               queue_destroy(sessions, NULL);
> +               sessions = NULL;
> +       }
> +}
> +
> +static void csip_detached(struct bt_csip *csip, void *user_data)
> +{
> +       struct csip_data *data;
> +
> +       DBG("%p", csip);
> +
> +       data = queue_find(sessions, match_data, csip);
> +       if (!data) {
> +               error("Unable to find csip session");
> +               return;
> +       }
> +
> +       csip_data_remove(data);
> +}
> +
> +static void csip_attached(struct bt_csip *csip, void *user_data)
> +{
> +       struct csip_data *data;
> +       struct bt_att *att;
> +       struct btd_device *device;
> +
> +       DBG("%p", csip);
> +
> +       data = queue_find(sessions, match_data, csip);
> +       if (data)
> +               return;
> +
> +       att = bt_csip_get_att(csip);
> +       if (!att)
> +               return;
> +
> +       device = btd_adapter_find_device_by_fd(bt_att_get_fd(att));
> +       if (!device) {
> +               error("Unable to find device");
> +               return;
> +       }
> +
> +       data = csip_data_new(device);
> +       data->csip = csip;
> +
> +       csip_data_add(data);
> +
> +}
> +
> +static int csip_server_probe(struct btd_profile *p,
> +                               struct btd_adapter *adapter)
> +{
> +       struct btd_gatt_database *database = btd_adapter_get_database(adapter);
> +
> +       DBG("CSIP path %s", adapter_get_path(adapter));
> +
> +       bt_csip_add_db(btd_gatt_database_get_db(database));
> +
> +       return 0;
> +}
> +
> +static void csip_server_remove(struct btd_profile *p,
> +                                       struct btd_adapter *adapter)
> +{
> +       DBG("CSIP remove Adapter");
> +}
> +
> +static int csip_accept(struct btd_service *service)
> +{
> +       struct btd_device *device = btd_service_get_device(service);
> +       struct bt_gatt_client *client = btd_device_get_gatt_client(device);
> +       struct csip_data *data = btd_service_get_user_data(service);
> +       char addr[18];
> +
> +       ba2str(device_get_address(device), addr);
> +       DBG("%s", addr);
> +
> +       if (!data) {
> +               error("CSIP service not handled by profile");
> +               return -EINVAL;
> +       }
> +
> +       if (!bt_csip_attach(data->csip, client)) {
> +               error("CSIP unable to attach");
> +               return -EINVAL;
> +       }
> +
> +       btd_service_connecting_complete(service, 0);
> +
> +       return 0;
> +}
> +
> +static int csip_probe(struct btd_service *service)
> +{
> +       struct btd_device *device = btd_service_get_device(service);
> +       struct btd_adapter *adapter = device_get_adapter(device);
> +       struct btd_gatt_database *database = btd_adapter_get_database(adapter);
> +       struct csip_data *data = btd_service_get_user_data(service);
> +       char addr[18];
> +
> +       ba2str(device_get_address(device), addr);
> +       DBG("%s", addr);
> +
> +       /* Ignore, if we were probed for this device already */
> +       if (data) {
> +               error("Profile probed twice for the same device!");
> +               return -EINVAL;
> +       }
> +
> +       data = csip_data_new(device);
> +       data->service = service;
> +
> +       data->csip = bt_csip_new(btd_gatt_database_get_db(database),
> +                                       btd_device_get_gatt_db(device));
> +       if (!data->csip) {
> +               error("Unable to create CSIP instance");
> +               free(data);
> +               return -EINVAL;
> +       }
> +
> +       csip_data_add(data);
> +
> +       bt_csip_set_user_data(data->csip, service);
> +
> +       return 0;
> +}
> +
> +static void csip_remove(struct btd_service *service)
> +{
> +       struct btd_device *device = btd_service_get_device(service);
> +       struct csip_data *data;
> +       char addr[18];
> +
> +       ba2str(device_get_address(device), addr);
> +       DBG("%s", addr);
> +
> +       data = btd_service_get_user_data(service);
> +       if (!data) {
> +               error("CSIP service not handled by profile");
> +               return;
> +       }
> +
> +       csip_data_remove(data);
> +}
> +
> +static struct btd_profile csip_profile = {
> +       .name           = "csip",
> +       .priority       = BTD_PROFILE_PRIORITY_MEDIUM,
> +       .remote_uuid    = CSIS_UUID_STR,
> +
> +       .device_probe   = csip_probe,
> +       .device_remove  = csip_remove,
> +
> +       .accept         = csip_accept,
> +       .disconnect     = csip_disconnect,
> +
> +       .adapter_probe  = csip_server_probe,
> +       .adapter_remove = csip_server_remove,
> +};
> +
> +static unsigned int csip_id;
> +
> +static int csip_init(void)
> +{
> +       if (!(g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL)) {
> +               warn("D-Bus experimental not enabled");
> +               return -ENOTSUP;
> +       }
> +
> +       btd_profile_register(&csip_profile);
> +       csip_id = bt_csip_register(csip_attached, csip_detached, NULL);
> +
> +       return 0;
> +}
> +
> +static void csip_exit(void)
> +{
> +       if (g_dbus_get_flags() & G_DBUS_FLAG_ENABLE_EXPERIMENTAL) {
> +               btd_profile_unregister(&csip_profile);
> +               bt_csip_unregister(csip_id);
> +       }
> +}
> +
> +BLUETOOTH_PLUGIN_DEFINE(csip, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
> +                                               csip_init, csip_exit)
> --
> 2.25.1

This seems to be handling just the discovery of the CSIS, which is
fine for now, but we probably need a way to expose the SIRK to the
daemon core which can then expose via D-Bus, or perhaps you have
something like that already on the works? I was thinking on something
like the following:

https://gist.github.com/Vudentz/55a7982b82c7a1156619b2a653969cac

I think as the object path we may need to use the SIRK or something
that uniquely identifies the set.

-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH BlueZ v3 4/7] shared/csip: Add initial code for handling CSIP
  2022-11-22 10:12 ` [PATCH BlueZ v3 4/7] shared/csip: Add initial code for handling CSIP Sathish Narasimman
@ 2022-11-22 20:37   ` Luiz Augusto von Dentz
  0 siblings, 0 replies; 16+ messages in thread
From: Luiz Augusto von Dentz @ 2022-11-22 20:37 UTC (permalink / raw)
  To: Sathish Narasimman; +Cc: linux-bluetooth

Hi Sathish,

On Tue, Nov 22, 2022 at 2:16 AM Sathish Narasimman
<sathish.narasimman@intel.com> wrote:
>
> This adds initial code for Coordinated Set Identification Profile.
> ---
>  Makefile.am       |   1 +
>  src/shared/csip.c | 554 ++++++++++++++++++++++++++++++++++++++++++++++
>  src/shared/csip.h |  44 ++++
>  3 files changed, 599 insertions(+)
>  create mode 100644 src/shared/csip.c
>  create mode 100644 src/shared/csip.h
>
> diff --git a/Makefile.am b/Makefile.am
> index aa3a5e053cd8..b546a1803dfd 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -233,6 +233,7 @@ shared_sources = src/shared/io.h src/shared/timeout.h \
>                         src/shared/bap.h src/shared/bap.c src/shared/ascs.h \
>                         src/shared/mcs.h src/shared/mcp.h src/shared/mcp.c \
>                         src/shared/vcp.c src/shared/vcp.h \
> +                       src/shared/csip.c src/shared/csip.h \
>                         src/shared/lc3.h src/shared/tty.h
>
>  if READLINE
> diff --git a/src/shared/csip.c b/src/shared/csip.c
> new file mode 100644
> index 000000000000..98e42d914b16
> --- /dev/null
> +++ b/src/shared/csip.c
> @@ -0,0 +1,554 @@
> +// SPDX-License-Identifier: LGPL-2.1-or-later
> +/*
> + *
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  Copyright (C) 2022  Intel Corporation. All rights reserved.
> + *
> + */
> +
> +#define _GNU_SOURCE
> +#include <inttypes.h>
> +#include <string.h>
> +#include <stdlib.h>
> +#include <stdbool.h>
> +#include <unistd.h>
> +#include <errno.h>
> +
> +#include <glib.h>
> +
> +#include "lib/bluetooth.h"
> +#include "lib/uuid.h"
> +
> +#include "src/shared/queue.h"
> +#include "src/shared/util.h"
> +#include "src/shared/timeout.h"
> +#include "src/shared/att.h"
> +#include "src/shared/gatt-db.h"
> +#include "src/shared/gatt-server.h"
> +#include "src/shared/gatt-client.h"
> +#include "src/shared/csip.h"
> +#include "src/btd.h"
> +
> +#define DBG(_csip, fmt, arg...) \
> +       csip_debug(_csip, "%s:%s() " fmt, __FILE__, __func__, ## arg)
> +
> +/* SIRK is now hardcoded in the code. This can be moved
> + * to a configuration file. Since the code is to validate
> + * the CSIP use case of set member
> + */
> +#define SIRK "761FAE703ED681F0C50B34155B6434FB"
> +#define CSIS_SIZE      0x02
> +#define CSIS_LOCK      0x01
> +#define CSIS_RANK      0x01
> +#define CSIS_PLAINTEXT 0x01
> +#define CSIS_ENC       0x02
> +
> +struct bt_csip_db {
> +       struct gatt_db *db;
> +       struct bt_csis *csis;
> +};
> +
> +struct csis_sirk {
> +       uint8_t type;
> +       uint8_t val[16];
> +} __packed;
> +
> +struct bt_csis {
> +       struct bt_csip_db *cdb;
> +       struct csis_sirk *sirk;
> +       uint8_t cs_size;
> +       uint8_t cs_lock;
> +       uint8_t cs_rank;
> +       struct gatt_db_attribute *service;
> +       struct gatt_db_attribute *csirk;
> +       struct gatt_db_attribute *csize;
> +       struct gatt_db_attribute *cslock;
> +       struct gatt_db_attribute *cslock_ccc;
> +       struct gatt_db_attribute *crank;
> +};
> +
> +struct bt_csip_cb {
> +       unsigned int id;
> +       bt_csip_func_t attached;
> +       bt_csip_func_t detached;
> +       void *user_data;
> +};
> +
> +struct bt_csip {
> +       int ref_count;
> +       struct bt_csip_db *ldb;
> +       struct bt_csip_db *rdb;
> +       struct bt_gatt_client *client;
> +       struct bt_att *att;
> +
> +       struct queue *pending;
> +
> +       bt_csip_debug_func_t debug_func;
> +       bt_csip_destroy_func_t debug_destroy;
> +       void *debug_data;
> +       void *user_data;
> +};
> +
> +static struct queue *csip_db;
> +static struct queue *csip_cbs;
> +static struct queue *sessions;
> +
> +static void csip_detached(void *data, void *user_data)
> +{
> +       struct bt_csip_cb *cb = data;
> +       struct bt_csip *csip = user_data;
> +
> +       cb->detached(csip, cb->user_data);
> +}
> +
> +void bt_csip_detach(struct bt_csip *csip)
> +{
> +       if (!queue_remove(sessions, csip))
> +               return;
> +
> +       bt_gatt_client_unref(csip->client);
> +       csip->client = NULL;
> +
> +       queue_foreach(csip_cbs, csip_detached, csip);
> +}
> +
> +static void csip_db_free(void *data)
> +{
> +       struct bt_csip_db *cdb = data;
> +
> +       if (!cdb)
> +               return;
> +
> +       gatt_db_unref(cdb->db);
> +
> +       free(cdb->csis);
> +       free(cdb);
> +}
> +static void csip_free(void *data)
> +{
> +       struct bt_csip *csip = data;
> +
> +       bt_csip_detach(csip);
> +
> +       csip_db_free(csip->rdb);
> +
> +       queue_destroy(csip->pending, NULL);
> +
> +       free(csip);
> +}
> +
> +struct bt_att *bt_csip_get_att(struct bt_csip *csip)
> +{
> +       if (!csip)
> +               return NULL;
> +
> +       if (csip->att)
> +               return csip->att;
> +
> +       return bt_gatt_client_get_att(csip->client);
> +}
> +
> +struct bt_csip *bt_csip_ref(struct bt_csip *csip)
> +{
> +       if (!csip)
> +               return NULL;
> +
> +       __sync_fetch_and_add(&csip->ref_count, 1);
> +
> +       return csip;
> +}
> +
> +void bt_csip_unref(struct bt_csip *csip)
> +{
> +       if (!csip)
> +               return;
> +
> +       if (__sync_sub_and_fetch(&csip->ref_count, 1))
> +               return;
> +
> +       csip_free(csip);
> +}
> +
> +static void csip_debug(struct bt_csip *csip, const char *format, ...)
> +{
> +       va_list ap;
> +
> +       if (!csip || !format || !csip->debug_func)
> +               return;
> +
> +       va_start(ap, format);
> +       util_debug_va(csip->debug_func, csip->debug_data, format, ap);
> +       va_end(ap);
> +}
> +
> +static void csis_sirk_read(struct gatt_db_attribute *attrib,
> +                               unsigned int id, uint16_t offset,
> +                               uint8_t opcode, struct bt_att *att,
> +                               void *user_data)
> +{
> +       struct bt_csis *csis = user_data;
> +       struct iovec iov;
> +
> +       iov.iov_base = csis->sirk;
> +       iov.iov_len = sizeof(struct csis_sirk);
> +
> +       gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base,
> +                                                       iov.iov_len);
> +}
> +
> +static void csis_size_read(struct gatt_db_attribute *attrib,
> +                               unsigned int id, uint16_t offset,
> +                               uint8_t opcode, struct bt_att *att,
> +                               void *user_data)
> +{
> +       struct bt_csis *csis = user_data;
> +       struct iovec iov;
> +
> +       iov.iov_base = &csis->cs_size;
> +       iov.iov_len = sizeof(csis->cs_size);
> +
> +       gatt_db_attribute_read_result(attrib, id, 0, iov.iov_base,
> +                                                       iov.iov_len);
> +}
> +
> +static void csis_lock_read_cb(struct gatt_db_attribute *attrib,
> +                               unsigned int id, uint16_t offset,
> +                               uint8_t opcode, struct bt_att *att,
> +                               void *user_data)
> +{
> +       uint8_t value = CSIS_LOCK;
> +
> +       gatt_db_attribute_read_result(attrib, id, 0, &value, sizeof(value));
> +}
> +
> +static void csis_lock_write_cb(struct gatt_db_attribute *attrib,
> +                               unsigned int id, uint16_t offset,
> +                               const uint8_t *value, size_t len,
> +                               uint8_t opcode, struct bt_att *att,
> +                               void *user_data)
> +{
> +       gatt_db_attribute_write_result(attrib, id, 0);
> +}
> +
> +static void csis_rank_read_cb(struct gatt_db_attribute *attrib,
> +                               unsigned int id, uint16_t offset,
> +                               uint8_t opcode, struct bt_att *att,
> +                               void *user_data)
> +{
> +       uint8_t value = CSIS_RANK;
> +
> +       gatt_db_attribute_read_result(attrib, id, 0, &value, sizeof(value));
> +}
> +
> +static struct bt_csis *csis_new(struct gatt_db *db)
> +{
> +       struct bt_csis *csis;
> +       struct csis_sirk *sirk;
> +       bt_uuid_t uuid;
> +
> +       /* For Common Audio Service*/
> +       struct gatt_db_attribute *service;
> +
> +       if (!db)
> +               return NULL;
> +
> +       csis = new0(struct bt_csis, 1);
> +       sirk = new0(struct csis_sirk, 1);
> +
> +       sirk->type = btd_opts.csis_defaults.sirk_type;
> +       memcpy(sirk->val, btd_opts.csis_defaults.sirk_val,
> +                       sizeof(sirk->val));
> +       csis->sirk = sirk;
> +       csis->cs_size = btd_opts.csis_defaults.cs_size;
> +       csis->cs_lock = 1;
> +       csis->cs_rank = btd_opts.csis_defaults.cs_rank;

We can't have the shared code depending directly on the daemon code
(e.g. btd_opts) since we want this code to be testable via unit
testing framework (see unit/test-bap.c), so you probably want to pass
these values via function parameter.

> +       /* Populate DB with CSIS attributes */
> +       bt_uuid16_create(&uuid, CSIS_UUID);
> +       csis->service = gatt_db_add_service(db, &uuid, true, 10);
> +
> +       bt_uuid16_create(&uuid, CS_SIRK);
> +       csis->csirk = gatt_db_service_add_characteristic(csis->service,
> +                                       &uuid,
> +                                       BT_ATT_PERM_READ,
> +                                       BT_GATT_CHRC_PROP_READ,
> +                                       csis_sirk_read, NULL,
> +                                       csis);
> +
> +       bt_uuid16_create(&uuid, CS_SIZE);
> +       csis->csize = gatt_db_service_add_characteristic(csis->service,
> +                                       &uuid,
> +                                       BT_ATT_PERM_READ,
> +                                       BT_GATT_CHRC_PROP_READ,
> +                                       csis_size_read, NULL,
> +                                       csis);
> +
> +       /* Lock */
> +       bt_uuid16_create(&uuid, CS_LOCK);
> +       csis->cslock = gatt_db_service_add_characteristic(csis->service, &uuid,
> +                                       BT_ATT_PERM_READ,
> +                                       BT_GATT_CHRC_PROP_READ |
> +                                       BT_GATT_CHRC_PROP_WRITE |
> +                                       BT_GATT_CHRC_PROP_NOTIFY,
> +                                       csis_lock_read_cb,
> +                                       csis_lock_write_cb,
> +                                       csis);
> +
> +       csis->cslock_ccc = gatt_db_service_add_ccc(csis->service,
> +                                       BT_ATT_PERM_READ | BT_ATT_PERM_WRITE);
> +
> +       /* Rank */
> +       bt_uuid16_create(&uuid, CS_RANK);
> +       csis->crank = gatt_db_service_add_characteristic(csis->service, &uuid,
> +                                       BT_ATT_PERM_READ,
> +                                       BT_GATT_CHRC_PROP_READ,
> +                                       csis_rank_read_cb,
> +                                       NULL, csis);
> +
> +       /* Add the CAS service */
> +       bt_uuid16_create(&uuid, 0x1853);
> +       service = gatt_db_add_service(db, &uuid, true, 2);
> +       gatt_db_service_add_included(service, csis->service);
> +       gatt_db_service_set_active(service, true);
> +       gatt_db_service_add_included(service, csis->service);
> +
> +       gatt_db_service_set_active(csis->service, true);
> +
> +       return csis;
> +}
> +
> +static struct bt_csip_db *csip_db_new(struct gatt_db *db)
> +{
> +       struct bt_csip_db *cdb;
> +
> +       if (!db)
> +               return NULL;
> +
> +       cdb = new0(struct bt_csip_db, 1);
> +       cdb->db = gatt_db_ref(db);
> +
> +       if (!csip_db)
> +               csip_db = queue_new();
> +
> +       cdb->csis = csis_new(db);
> +       cdb->csis->cdb = cdb;
> +
> +       queue_push_tail(csip_db, cdb);
> +
> +       return cdb;
> +}
> +
> +bool bt_csip_set_user_data(struct bt_csip *csip, void *user_data)
> +{
> +       if (!csip)
> +               return false;
> +
> +       csip->user_data = user_data;
> +
> +       return true;
> +}
> +
> +static bool csip_db_match(const void *data, const void *match_data)
> +{
> +       const struct bt_csip_db *cdb = data;
> +       const struct gatt_db *db = match_data;
> +
> +       return (cdb->db == db);
> +}
> +
> +static struct bt_csip_db *csip_get_db(struct gatt_db *db)
> +{
> +       struct bt_csip_db *cdb;
> +
> +       cdb = queue_find(csip_db, csip_db_match, db);
> +       if (cdb)
> +               return cdb;
> +
> +       return csip_db_new(db);
> +}
> +
> +void bt_csip_add_db(struct gatt_db *db)
> +{
> +       csip_db_new(db);
> +}
> +
> +bool bt_csip_set_debug(struct bt_csip *csip, bt_csip_debug_func_t func,
> +                       void *user_data, bt_csip_destroy_func_t destroy)
> +{
> +       if (!csip)
> +               return false;
> +
> +       if (csip->debug_destroy)
> +               csip->debug_destroy(csip->debug_data);
> +
> +       csip->debug_func = func;
> +       csip->debug_destroy = destroy;
> +       csip->debug_data = user_data;
> +
> +       return true;
> +}
> +
> +unsigned int bt_csip_register(bt_csip_func_t attached, bt_csip_func_t detached,
> +                                                       void *user_data)
> +{
> +       struct bt_csip_cb *cb;
> +       static unsigned int id;
> +
> +       if (!attached && !detached)
> +               return 0;
> +
> +       if (!csip_cbs)
> +               csip_cbs = queue_new();
> +
> +       cb = new0(struct bt_csip_cb, 1);
> +       cb->id = ++id ? id : ++id;
> +       cb->attached = attached;
> +       cb->detached = detached;
> +       cb->user_data = user_data;
> +
> +       queue_push_tail(csip_cbs, cb);
> +
> +       return cb->id;
> +}
> +
> +static bool match_id(const void *data, const void *match_data)
> +{
> +       const struct bt_csip_cb *cb = data;
> +       unsigned int id = PTR_TO_UINT(match_data);
> +
> +       return (cb->id == id);
> +}
> +
> +bool bt_csip_unregister(unsigned int id)
> +{
> +       struct bt_csip_cb *cb;
> +
> +       cb = queue_remove_if(csip_cbs, match_id, UINT_TO_PTR(id));
> +       if (!cb)
> +               return false;
> +
> +       free(cb);
> +
> +       return true;
> +}
> +
> +struct bt_csip *bt_csip_new(struct gatt_db *ldb, struct gatt_db *rdb)
> +{
> +       struct bt_csip *csip;
> +       struct bt_csip_db *db;
> +
> +       if (!ldb)
> +               return NULL;
> +
> +       db = csip_get_db(ldb);
> +       if (!db)
> +               return NULL;
> +
> +       csip = new0(struct bt_csip, 1);
> +       csip->ldb = db;
> +       csip->pending = queue_new();
> +
> +       if (!rdb)
> +               goto done;
> +
> +       db = new0(struct bt_csip_db, 1);
> +       db->db = gatt_db_ref(rdb);
> +
> +       csip->rdb = db;
> +
> +done:
> +       bt_csip_ref(csip);
> +
> +       return csip;
> +}
> +
> +static struct bt_csis *csip_get_csis(struct bt_csip *csip)
> +{
> +       if (!csip)
> +               return NULL;
> +
> +       if (csip->rdb->csis)
> +               return csip->rdb->csis;
> +
> +       csip->rdb->csis = new0(struct bt_csis, 1);
> +       csip->rdb->csis->cdb = csip->rdb;
> +
> +       return csip->rdb->csis;
> +}
> +
> +static void foreach_csis_char(struct gatt_db_attribute *attr, void *user_data)
> +{
> +       struct bt_csip *csip = user_data;
> +       uint16_t value_handle;
> +       bt_uuid_t uuid, uuid_csirk, uuid_csize;
> +       struct bt_csis *csis;
> +
> +       if (!gatt_db_attribute_get_char_data(attr, NULL, &value_handle,
> +                                               NULL, NULL, &uuid))
> +               return;
> +
> +       bt_uuid16_create(&uuid_csirk, CS_SIRK);
> +       bt_uuid16_create(&uuid_csize, CS_SIZE);
> +
> +       if (!bt_uuid_cmp(&uuid, &uuid_csirk)) {
> +               DBG(csip, "CSIS IRK found: handle 0x%04x", value_handle);
> +
> +               csis = csip_get_csis(csip);
> +               if (!csis || csis->sirk)
> +                       return;
> +
> +               csis->csirk = attr;
> +               return;
> +       }
> +
> +       if (!bt_uuid_cmp(&uuid, &uuid_csize)) {
> +               DBG(csip, "CSIS SIZE found: handle 0x%04x", value_handle);
> +
> +               csis = csip_get_csis(csip);
> +               if (!csis)
> +                       return;
> +
> +               csis->csize = attr;
> +       }
> +
> +}
> +static void foreach_csis_service(struct gatt_db_attribute *attr,
> +                                               void *user_data)
> +{
> +       struct bt_csip *csip = user_data;
> +       struct bt_csis *csis = csip_get_csis(csip);
> +
> +       csis->service = attr;
> +
> +       gatt_db_service_set_claimed(attr, true);
> +
> +       gatt_db_service_foreach_char(attr, foreach_csis_char, csip);
> +}
> +
> +bool bt_csip_attach(struct bt_csip *csip, struct bt_gatt_client *client)
> +{
> +       bt_uuid_t uuid;
> +
> +       if (!sessions)
> +               sessions = queue_new();
> +
> +       queue_push_tail(sessions, csip);
> +
> +       if (!client)
> +               return true;
> +
> +       if (csip->client)
> +               return false;
> +
> +       csip->client = bt_gatt_client_clone(client);
> +       if (!csip->client)
> +               return false;
> +
> +       bt_uuid16_create(&uuid, CSIS_UUID);
> +       gatt_db_foreach_service(csip->ldb->db, &uuid, foreach_csis_service,
> +                               csip);
> +
> +       return true;
> +}
> +
> diff --git a/src/shared/csip.h b/src/shared/csip.h
> new file mode 100644
> index 000000000000..bd88ccf3a0b2
> --- /dev/null
> +++ b/src/shared/csip.h
> @@ -0,0 +1,44 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + *
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  Copyright (C) 2022  Intel Corporation. All rights reserved.
> + *
> + */
> +
> +#include <stdbool.h>
> +#include <inttypes.h>
> +
> +#include "src/shared/io.h"
> +
> +#ifndef __packed
> +#define __packed __attribute__((packed))
> +#endif
> +
> +struct bt_csip;
> +
> +typedef void (*bt_csip_destroy_func_t)(void *user_data);
> +typedef void (*bt_csip_debug_func_t)(const char *str, void *user_data);
> +typedef void (*bt_csip_func_t)(struct bt_csip *csip, void *user_data);
> +struct bt_csip *bt_csip_ref(struct bt_csip *csip);
> +void bt_csip_unref(struct bt_csip *csip);
> +
> +void bt_csip_add_db(struct gatt_db *db);
> +
> +bool bt_csip_attach(struct bt_csip *csip, struct bt_gatt_client *client);
> +void bt_csip_detach(struct bt_csip *csip);
> +
> +bool bt_csip_set_debug(struct bt_csip *csip, bt_csip_debug_func_t func,
> +                       void *user_data, bt_csip_destroy_func_t destroy);
> +
> +struct bt_att *bt_csip_get_att(struct bt_csip *csip);
> +
> +bool bt_csip_set_user_data(struct bt_csip *csip, void *user_data);
> +
> +/* Session related function */
> +unsigned int bt_csip_register(bt_csip_func_t added, bt_csip_func_t removed,
> +                                                       void *user_data);
> +bool bt_csip_unregister(unsigned int id);
> +struct bt_csip *bt_csip_new(struct gatt_db *ldb, struct gatt_db *rdb);
> +
> --
> 2.25.1
>


-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH BlueZ v3 3/7] main.conf: Add CSIP profile configurable options
  2022-11-22 20:13   ` Luiz Augusto von Dentz
@ 2022-11-23  0:07     ` Luiz Augusto von Dentz
  0 siblings, 0 replies; 16+ messages in thread
From: Luiz Augusto von Dentz @ 2022-11-23  0:07 UTC (permalink / raw)
  To: Sathish Narasimman; +Cc: linux-bluetooth

Hi Sathish,

On Tue, Nov 22, 2022 at 12:13 PM Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
>
> Hi Sathish,
>
>
> On Tue, Nov 22, 2022 at 2:17 AM Sathish Narasimman
> <sathish.narasimman@intel.com> wrote:
> >
> > This introduces option to configure main.conf that can be used to
> > configure co-ordinated set identification profile.
> > ---
> >  src/btd.h     |   9 ++++
> >  src/main.c    | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++
> >  src/main.conf |  24 +++++++++++
> >  3 files changed, 146 insertions(+)
> >
> > diff --git a/src/btd.h b/src/btd.h
> > index 42cffcde43ca..a3683a098689 100644
> > --- a/src/btd.h
> > +++ b/src/btd.h
> > @@ -92,6 +92,13 @@ struct btd_defaults {
> >         struct btd_le_defaults le;
> >  };
> >
> > +struct btd_csis {
> > +       uint8_t sirk_type;
> > +       uint8_t sirk_val[16];
> > +       uint8_t cs_size;
> > +       uint8_t cs_rank;
> > +};
> > +
> >  struct btd_avdtp_opts {
> >         uint8_t  session_mode;
> >         uint8_t  stream_mode;
> > @@ -142,6 +149,8 @@ struct btd_opts {
> >         enum jw_repairing_t jw_repairing;
> >
> >         struct btd_advmon_opts  advmon;
> > +
> > +       struct btd_csis csis_defaults;
> >  };
> >
> >  extern struct btd_opts btd_opts;
> > diff --git a/src/main.c b/src/main.c
> > index 99d9c508ff91..abb422961f78 100644
> > --- a/src/main.c
> > +++ b/src/main.c
> > @@ -60,6 +60,9 @@
> >  #define DEFAULT_TEMPORARY_TIMEOUT         30 /* 30 seconds */
> >  #define DEFAULT_NAME_REQUEST_RETRY_DELAY 300 /* 5 minutes */
> >
> > +/*CSIP Profile - Server */
> > +#define DEFAULT_SIRK "761FAE703ED681F0C50B34155B6434FB"
> > +
> >  #define SHUTDOWN_GRACE_SECONDS 10
> >
> >  struct btd_opts btd_opts;
> > @@ -146,6 +149,14 @@ static const char *gatt_options[] = {
> >         NULL
> >  };
> >
> > +static const char *csip_options[] = {
> > +       "CsisSirkType",
> > +       "CsisSirkValue",
> > +       "CsisSize",
> > +       "CsisRank",
> > +       NULL
> > +};
> > +
> >  static const char *avdtp_options[] = {
> >         "SessionMode",
> >         "StreamMode",
> > @@ -166,11 +177,55 @@ static const struct group_table {
> >         { "LE",         le_options },
> >         { "Policy",     policy_options },
> >         { "GATT",       gatt_options },
> > +       { "CSIP",       csip_options },
> >         { "AVDTP",      avdtp_options },
> >         { "AdvMon",     advmon_options },
> >         { }
> >  };
> >
> > +#ifndef MIN
> > +#define MIN(x, y) ((x) < (y) ? (x) : (y))
> > +#endif
> > +
> > +static int8_t check_sirk_alpha_numeric(char *str)
> > +{
> > +       int8_t val = 0;
> > +       char *s = str;
> > +
> > +       if (strlen(s) != 32) /* 32 Bytes of Alpha numeric string */
> > +               return 0;
> > +
> > +       for ( ; *s; s++) {
> > +               if (((*s >= '0') & (*s <= '9'))
> > +                       || ((*s >= 'a') && (*s <= 'z'))
> > +                       || ((*s >= 'A') && (*s <= 'Z'))) {
> > +                       val = 1;
> > +               } else {
> > +                       val = 0;
> > +                       break;
> > +               }
> > +       }
> > +
> > +       return val;
> > +}
> > +
> > +static size_t hex2bin(const char *hexstr, uint8_t *buf, size_t buflen)
> > +{
> > +       size_t i, len;
> > +
> > +       if (!hexstr)
> > +               return 0;
> > +
> > +       len = MIN((strlen(hexstr) / 2), buflen);
> > +       memset(buf, 0, len);
> > +
> > +       for (i = 0; i < len; i++) {
> > +               if (sscanf(hexstr + (i * 2), "%02hhX", &buf[i]) != 1)
> > +                       continue;
> > +       }
> > +
> > +       return len;
> > +}
> >
> >  GKeyFile *btd_get_main_conf(void)
> >  {
> > @@ -939,6 +994,58 @@ static void parse_config(GKeyFile *config)
> >                 btd_opts.gatt_channels = val;
> >         }
> >
> > +       val = g_key_file_get_integer(config, "CSIP", "CsisSirkType", &err);
> > +       if (err) {
> > +               DBG("%s", err->message);
> > +               g_clear_error(&err);
> > +       } else {
> > +               val = MIN(val, 2);
> > +               val = MAX(val, 1);
> > +               DBG("Csis Type: %u", val);
> > +               btd_opts.csis_defaults.cs_size = val;
> > +       }
> > +
> > +       str = g_key_file_get_string(config, "CSIP", "CsisSirkValue", &err);
> > +       if (err) {
> > +               DBG("%s", err->message);
> > +               g_clear_error(&err);
> > +       } else {
> > +               DBG("Csis Sirk: %s", str);
> > +
> > +               if (!check_sirk_alpha_numeric(str)) {
> > +                       DBG("SIRK is not apha numeric Value");
> > +                       return;
> > +               }
> > +
> > +               btd_opts.csis_defaults.sirk_type = 1; /* Plain Text - Type*/
> > +               hex2bin(str, btd_opts.csis_defaults.sirk_val,
> > +                       sizeof(btd_opts.csis_defaults.sirk_val));
> > +
> > +               g_free(str);
> > +       }
> > +
> > +       val = g_key_file_get_integer(config, "CSIP", "CsisSize", &err);
> > +       if (err) {
> > +               DBG("%s", err->message);
> > +               g_clear_error(&err);
> > +       } else {
> > +               val = MIN(val, 0xFF);
> > +               val = MAX(val, 0);
> > +               DBG("Csis Size: %u", val);
> > +               btd_opts.csis_defaults.cs_size = val;
> > +       }
> > +
> > +       val = g_key_file_get_integer(config, "CSIP", "CsisRank", &err);
> > +       if (err) {
> > +               DBG("%s", err->message);
> > +               g_clear_error(&err);
> > +       } else {
> > +               val = MIN(val, 0xFF);
> > +               val = MAX(val, 0);
> > +               DBG("Csis Rank: %u", val);
> > +               btd_opts.csis_defaults.cs_rank = val;
> > +       }
> > +
> >         str = g_key_file_get_string(config, "AVDTP", "SessionMode", &err);
> >         if (err) {
> >                 DBG("%s", err->message);
> > @@ -1014,6 +1121,12 @@ static void init_defaults(void)
> >         btd_opts.defaults.br.scan_type = 0xFFFF;
> >         btd_opts.defaults.le.enable_advmon_interleave_scan = 0xFF;
> >
> > +       btd_opts.csis_defaults.sirk_type = 1;
> > +       hex2bin(DEFAULT_SIRK, btd_opts.csis_defaults.sirk_val,
> > +                       sizeof(btd_opts.csis_defaults.sirk_val));
> > +       btd_opts.csis_defaults.cs_size = 1;
> > +       btd_opts.csis_defaults.cs_rank = 1;
> > +
> >         if (sscanf(VERSION, "%hhu.%hhu", &major, &minor) != 2)
> >                 return;
> >
> > diff --git a/src/main.conf b/src/main.conf
> > index f187c9aaa482..5378472ef0d4 100644
> > --- a/src/main.conf
> > +++ b/src/main.conf
> > @@ -258,6 +258,30 @@
> >  # Default to 3
> >  #Channels = 3
> >
> > +[CSIP]
>
> Let's use Set as a group name.
>
> > +# CSIP - Co-ordinated Set Identification Profile
> > +# SIRK Types which determines the value type for CsisSirkValue
> > +# Possible values:
> > +# 1 - Plain text
> > +# 2 - encrypted
> > +#CsisSirkType = 1
>
> Let's not use the type directly here so perhaps something like
> KeyType=plaintext,encrypted, etc, and it is important to say what is
> the default value.

Actually this doesn't make much sense, we can't really enter the key
in encrypt format since that has to be encrypted with device's LTK,
perhaps we should just have EncryptKey=y/n.

> > +
> > +# CSIP - Co-ordinated Set Identification Profile
> > +# SIRK - Set Identification resolution key which is common for all the
> > +# sets. They SIRK key is used to identify its sets. This can be any
> > +# 128 bit value.
> > +# Possible Values:
> > +# 16 byte hexadecimal value
> > +#CsisSirkValue = 861FAE703ED681F0C50B34155B6434FB
>
> Let's use Key instead, since this would belong to [Set] group that is
> enough to disambiguate.
>
> > +
> > +#CSIP - Size
> > +#Total no of sets belongs to this Profile
> > +#CsisSize = 1
>
> Size
>
> > +#CSIP - Rank
> > +#Rank for the device
> > +#CsisRank = 1
>
> Rank
>
> >  [AVDTP]
> >  # AVDTP L2CAP Signalling Channel Mode.
> >  # Possible values:
> > --
> > 2.25.1
> >
>
>
> --
> Luiz Augusto von Dentz



-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 16+ messages in thread

* Re: [PATCH BlueZ v3 0/7] Csip - Client role
  2022-11-22 10:12 [PATCH BlueZ v3 0/7] Csip - Client role Sathish Narasimman
                   ` (6 preceding siblings ...)
  2022-11-22 10:12 ` [PATCH BlueZ v3 7/7] tools: Add support to generate RSI using SIRK Sathish Narasimman
@ 2022-12-20 23:40 ` patchwork-bot+bluetooth
  7 siblings, 0 replies; 16+ messages in thread
From: patchwork-bot+bluetooth @ 2022-12-20 23:40 UTC (permalink / raw)
  To: Sathish Narasimman; +Cc: linux-bluetooth

Hello:

This series was applied to bluetooth/bluez.git (master)
by Luiz Augusto von Dentz <luiz.von.dentz@intel.com>:

On Tue, 22 Nov 2022 15:42:25 +0530 you wrote:
> This version of patch updated with
> 1. Added btmon decoded log in commit message
> 2. Fixed few of scan warnings
> 
> Sathish Narasimman (7):
>   shared/util: Update UUID database for Csip services
>   lib/uuid: Add CSIS UUIDs
>   main.conf: Add CSIP profile configurable options
>   shared/csip: Add initial code for handling CSIP
>   profiles: Add initial code for csip plugin
>   monitor/att: Add decoding support for CSIP
>   tools: Add support to generate RSI using SIRK
> 
> [...]

Here is the summary with links:
  - [BlueZ,v3,1/7] shared/util: Update UUID database for Csip services
    (no matching commit)
  - [BlueZ,v3,2/7] lib/uuid: Add CSIS UUIDs
    https://git.kernel.org/pub/scm/bluetooth/bluez.git/?id=b709058c6008
  - [BlueZ,v3,3/7] main.conf: Add CSIP profile configurable options
    (no matching commit)
  - [BlueZ,v3,4/7] shared/csip: Add initial code for handling CSIP
    (no matching commit)
  - [BlueZ,v3,5/7] profiles: Add initial code for csip plugin
    (no matching commit)
  - [BlueZ,v3,6/7] monitor/att: Add decoding support for CSIP
    (no matching commit)
  - [BlueZ,v3,7/7] tools: Add support to generate RSI using SIRK
    (no matching commit)

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 16+ messages in thread

end of thread, other threads:[~2022-12-20 23:40 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-22 10:12 [PATCH BlueZ v3 0/7] Csip - Client role Sathish Narasimman
2022-11-22 10:12 ` [PATCH BlueZ v3 1/7] shared/util: Update UUID database for Csip services Sathish Narasimman
2022-11-22 12:38   ` Csip - Client role bluez.test.bot
2022-11-22 20:03   ` [PATCH BlueZ v3 1/7] shared/util: Update UUID database for Csip services Luiz Augusto von Dentz
2022-11-22 10:12 ` [PATCH BlueZ v3 2/7] lib/uuid: Add CSIS UUIDs Sathish Narasimman
2022-11-22 10:12 ` [PATCH BlueZ v3 3/7] main.conf: Add CSIP profile configurable options Sathish Narasimman
2022-11-22 20:13   ` Luiz Augusto von Dentz
2022-11-23  0:07     ` Luiz Augusto von Dentz
2022-11-22 10:12 ` [PATCH BlueZ v3 4/7] shared/csip: Add initial code for handling CSIP Sathish Narasimman
2022-11-22 20:37   ` Luiz Augusto von Dentz
2022-11-22 10:12 ` [PATCH BlueZ v3 5/7] profiles: Add initial code for csip plugin Sathish Narasimman
2022-11-22 20:30   ` Luiz Augusto von Dentz
2022-11-22 10:12 ` [PATCH BlueZ v3 6/7] monitor/att: Add decoding support for CSIP Sathish Narasimman
2022-11-22 10:12 ` [PATCH BlueZ v3 7/7] tools: Add support to generate RSI using SIRK Sathish Narasimman
2022-11-22 20:19   ` Luiz Augusto von Dentz
2022-12-20 23:40 ` [PATCH BlueZ v3 0/7] Csip - Client role patchwork-bot+bluetooth

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.