Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH BlueZ 19/25] alert: Add support for calling SetRinger()
From: Anderson Lizardo @ 2012-09-24 18:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Eder Ruiz Maria
In-Reply-To: <1348509661-15967-1-git-send-email-anderson.lizardo@openbossa.org>

From: Eder Ruiz Maria <eder.ruiz@openbossa.org>

When BlueZ wants to call SetRinger() method from org.bluez.AlertAgent
interface for a registered agent, the function agent_ringer_set_ringer()
must be called.
---
 profiles/alert/server.c |   27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/profiles/alert/server.c b/profiles/alert/server.c
index 75eb414..952d982 100644
--- a/profiles/alert/server.c
+++ b/profiles/alert/server.c
@@ -426,6 +426,31 @@ static int agent_ringer_mute_once(void)
 	return 0;
 }
 
+static int agent_ringer_set_ringer(const char *mode)
+{
+	struct alert_data *alert;
+	DBusMessage *msg;
+
+	alert = get_alert_data_by_category("ringer");
+	if (!alert) {
+		DBG("Category ringer is not registered");
+		return -EINVAL;
+	}
+
+	msg = dbus_message_new_method_call(alert->srv, alert->path,
+					ALERT_AGENT_INTERFACE, "SetRinger");
+	if (!msg)
+		return -ENOMEM;
+
+	dbus_message_append_args(msg, DBUS_TYPE_STRING, &mode,
+							DBUS_TYPE_INVALID);
+
+	dbus_message_set_no_reply(msg, TRUE);
+	g_dbus_send_message(btd_get_dbus_connection(), msg);
+
+	return 0;
+}
+
 static void update_unread_alert(gpointer data, gpointer user_data)
 {
 	struct alert_adapter *al_adapter = data;
@@ -498,6 +523,7 @@ static uint8_t ringer_cp_write(struct attribute *a,
 	switch (a->data[0]) {
 	case RINGER_SILENT_MODE:
 		DBG("Silent Mode");
+		agent_ringer_set_ringer("disabled");
 		break;
 	case RINGER_MUTE_ONCE:
 		DBG("Mute Once");
@@ -505,6 +531,7 @@ static uint8_t ringer_cp_write(struct attribute *a,
 		break;
 	case RINGER_CANCEL_SILENT_MODE:
 		DBG("Cancel Silent Mode");
+		agent_ringer_set_ringer("enabled");
 		break;
 	default:
 		DBG("Invalid command (0x%02x)", a->data[0]);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ 18/25] alert: Add support for calling MuteOnce()
From: Anderson Lizardo @ 2012-09-24 18:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Eder Ruiz Maria
In-Reply-To: <1348509661-15967-1-git-send-email-anderson.lizardo@openbossa.org>

From: Eder Ruiz Maria <eder.ruiz@openbossa.org>

When BlueZ wants to call MuteOnce() method from org.bluez.AlertAgent
interface for a registered agent, the function agent_ringer_mute_once()
must be called.
---
 profiles/alert/server.c |   24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/profiles/alert/server.c b/profiles/alert/server.c
index bf67d7d..75eb414 100644
--- a/profiles/alert/server.c
+++ b/profiles/alert/server.c
@@ -61,6 +61,7 @@
 
 #define ALERT_OBJECT_PATH "/org/bluez"
 #define ALERT_INTERFACE   "org.bluez.Alert"
+#define ALERT_AGENT_INTERFACE "org.bluez.AlertAgent"
 
 /* Maximum length for "Text String Information" */
 #define NEW_ALERT_MAX_INFO_SIZE		18
@@ -403,6 +404,28 @@ static DBusMessage *new_alert(DBusConnection *conn, DBusMessage *msg,
 	return dbus_message_new_method_return(msg);
 }
 
+static int agent_ringer_mute_once(void)
+{
+	struct alert_data *alert;
+	DBusMessage *msg;
+
+	alert = get_alert_data_by_category("ringer");
+	if (!alert) {
+		DBG("Category ringer is not registered");
+		return -EINVAL;
+	}
+
+	msg = dbus_message_new_method_call(alert->srv, alert->path,
+					ALERT_AGENT_INTERFACE, "MuteOnce");
+	if (!msg)
+		return -ENOMEM;
+
+	dbus_message_set_no_reply(msg, TRUE);
+	g_dbus_send_message(btd_get_dbus_connection(), msg);
+
+	return 0;
+}
+
 static void update_unread_alert(gpointer data, gpointer user_data)
 {
 	struct alert_adapter *al_adapter = data;
@@ -478,6 +501,7 @@ static uint8_t ringer_cp_write(struct attribute *a,
 		break;
 	case RINGER_MUTE_ONCE:
 		DBG("Mute Once");
+		agent_ringer_mute_once();
 		break;
 	case RINGER_CANCEL_SILENT_MODE:
 		DBG("Cancel Silent Mode");
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ 17/25] alert: Implement MuteOnce command
From: Anderson Lizardo @ 2012-09-24 18:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1348509661-15967-1-git-send-email-anderson.lizardo@openbossa.org>

MuteOnce() is called by BlueZ to instruct the agent to mute the ringer
during a incoming call.
---
 profiles/alert/server.c |   25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/profiles/alert/server.c b/profiles/alert/server.c
index eede2fd..bf67d7d 100644
--- a/profiles/alert/server.c
+++ b/profiles/alert/server.c
@@ -76,6 +76,12 @@ enum {
 	NOTIFY_UNREAD_CAT,
 };
 
+enum {
+	RINGER_SILENT_MODE = 1,
+	RINGER_MUTE_ONCE,
+	RINGER_CANCEL_SILENT_MODE,
+};
+
 /* Ringer Setting characteristic values */
 enum {
 	RINGER_SILENT,
@@ -461,6 +467,25 @@ static uint8_t ringer_cp_write(struct attribute *a,
 {
 	DBG("a = %p", a);
 
+	if (a->len > 1) {
+		DBG("Invalid command size (%zu)", a->len);
+		return 0;
+	}
+
+	switch (a->data[0]) {
+	case RINGER_SILENT_MODE:
+		DBG("Silent Mode");
+		break;
+	case RINGER_MUTE_ONCE:
+		DBG("Mute Once");
+		break;
+	case RINGER_CANCEL_SILENT_MODE:
+		DBG("Cancel Silent Mode");
+		break;
+	default:
+		DBG("Invalid command (0x%02x)", a->data[0]);
+	}
+
 	return 0;
 }
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ 16/25] alert: Update unread alert characteristic value
From: Anderson Lizardo @ 2012-09-24 18:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1348509661-15967-1-git-send-email-anderson.lizardo@openbossa.org>

Update the attribute value when the unread alert count is changed.
---
 profiles/alert/server.c |   31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/profiles/alert/server.c b/profiles/alert/server.c
index 9e389d6..eede2fd 100644
--- a/profiles/alert/server.c
+++ b/profiles/alert/server.c
@@ -94,6 +94,7 @@ struct alert_adapter {
 	uint16_t supp_new_alert_cat_handle;
 	uint16_t supp_unread_alert_cat_handle;
 	uint16_t new_alert_handle;
+	uint16_t unread_alert_handle;
 };
 
 static GSList *registered_alerts = NULL;
@@ -396,12 +397,23 @@ static DBusMessage *new_alert(DBusConnection *conn, DBusMessage *msg,
 	return dbus_message_new_method_return(msg);
 }
 
+static void update_unread_alert(gpointer data, gpointer user_data)
+{
+	struct alert_adapter *al_adapter = data;
+	struct btd_adapter *adapter = al_adapter->adapter;
+	uint8_t *value = user_data;
+
+	attrib_db_update(adapter, al_adapter->unread_alert_handle, NULL, value,
+								2, NULL);
+}
+
 static DBusMessage *unread_alert(DBusConnection *conn, DBusMessage *msg,
 								void *data)
 {
 	const char *sender = dbus_message_get_sender(msg);
 	struct alert_data *alert;
 	const char *category;
+	unsigned int i;
 	uint16_t count;
 
 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &category,
@@ -415,12 +427,29 @@ static DBusMessage *unread_alert(DBusConnection *conn, DBusMessage *msg,
 		return btd_error_invalid_args(msg);
 	}
 
+	if (!valid_count(category, count)) {
+		DBG("Count %d is invalid for %s category", count, category);
+		return btd_error_invalid_args(msg);
+	}
+
 	if (!g_str_equal(alert->srv, sender)) {
 		DBG("Sender %s is not registered in category %s", sender,
 								category);
 		return btd_error_invalid_args(msg);
 	}
 
+	for (i = 0; i < G_N_ELEMENTS(anp_categories); i++) {
+		if (g_str_equal(anp_categories[i], category)) {
+			uint8_t value[2];
+
+			value[0] = i; /* Category ID */
+			value[1] = count; /* Unread count */
+
+			g_slist_foreach(alert_adapters, update_unread_alert,
+									value);
+		}
+	}
+
 	DBG("category %s, count %d", category, count);
 
 	return dbus_message_new_method_return(msg);
@@ -587,6 +616,8 @@ static void register_alert_notif_service(struct alert_adapter *al_adapter)
 			/* Unread Alert Status */
 			GATT_OPT_CHR_UUID, UNREAD_ALERT_CHR_UUID,
 			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_NOTIFY,
+			GATT_OPT_CHR_VALUE_GET_HANDLE,
+			&al_adapter->unread_alert_handle,
 			/* Alert Notification Control Point */
 			GATT_OPT_CHR_UUID, ALERT_NOTIF_CP_CHR_UUID,
 			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_WRITE,
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ 15/25] alert: Update new alert characteristic value
From: Anderson Lizardo @ 2012-09-24 18:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1348509661-15967-1-git-send-email-anderson.lizardo@openbossa.org>

Update the attribute value when a new alert is reported to BlueZ.
---
 profiles/alert/server.c |   39 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/profiles/alert/server.c b/profiles/alert/server.c
index f1021cc..9e389d6 100644
--- a/profiles/alert/server.c
+++ b/profiles/alert/server.c
@@ -64,6 +64,8 @@
 
 /* Maximum length for "Text String Information" */
 #define NEW_ALERT_MAX_INFO_SIZE		18
+/* Maximum length for New Alert Characteristic Value */
+#define NEW_ALERT_CHR_MAX_VALUE_SIZE	(NEW_ALERT_MAX_INFO_SIZE + 2)
 
 enum {
 	ENABLE_NEW_INCOMING,
@@ -91,6 +93,7 @@ struct alert_adapter {
 	struct btd_adapter *adapter;
 	uint16_t supp_new_alert_cat_handle;
 	uint16_t supp_unread_alert_cat_handle;
+	uint16_t new_alert_handle;
 };
 
 static GSList *registered_alerts = NULL;
@@ -318,6 +321,16 @@ static DBusMessage *register_alert(DBusConnection *conn, DBusMessage *msg,
 	return dbus_message_new_method_return(msg);
 }
 
+static void update_new_alert(gpointer data, gpointer user_data)
+{
+	struct alert_adapter *al_adapter = data;
+	struct btd_adapter *adapter = al_adapter->adapter;
+	uint8_t *value = user_data;
+
+	attrib_db_update(adapter, al_adapter->new_alert_handle, NULL, &value[1],
+								value[0], NULL);
+}
+
 static DBusMessage *new_alert(DBusConnection *conn, DBusMessage *msg,
 								void *data)
 {
@@ -325,6 +338,7 @@ static DBusMessage *new_alert(DBusConnection *conn, DBusMessage *msg,
 	const char *category, *description;
 	struct alert_data *alert;
 	uint16_t count;
+	unsigned int i;
 
 	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &category,
 			DBUS_TYPE_UINT16, &count, DBUS_TYPE_STRING,
@@ -354,6 +368,29 @@ static DBusMessage *new_alert(DBusConnection *conn, DBusMessage *msg,
 		return btd_error_invalid_args(msg);
 	}
 
+	for (i = 0; i < G_N_ELEMENTS(anp_categories); i++) {
+		if (g_str_equal(anp_categories[i], category)) {
+			uint8_t value[NEW_ALERT_CHR_MAX_VALUE_SIZE + 1];
+			size_t dlen = strlen(description);
+			uint8_t *ptr = value;
+
+			memset(value, 0, sizeof(value));
+
+			*ptr++ = 2; /* Attribute value size */
+			*ptr++ = i; /* Category ID (mandatory) */
+			*ptr++ = count; /* Number of New Alert (mandatory) */
+			/* Text String Information (optional) */
+			strncpy((char *) ptr, description,
+						NEW_ALERT_MAX_INFO_SIZE - 1);
+
+			if (dlen > 0)
+				*value += dlen + 1;
+
+			g_slist_foreach(alert_adapters, update_new_alert,
+									value);
+		}
+	}
+
 	DBG("NewAlert(\"%s\", %d, \"%s\")", category, count, description);
 
 	return dbus_message_new_method_return(msg);
@@ -538,6 +575,8 @@ static void register_alert_notif_service(struct alert_adapter *al_adapter)
 			/* New Alert */
 			GATT_OPT_CHR_UUID, NEW_ALERT_CHR_UUID,
 			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_NOTIFY,
+			GATT_OPT_CHR_VALUE_GET_HANDLE,
+			&al_adapter->new_alert_handle,
 			/* Supported Unread Alert Category */
 			GATT_OPT_CHR_UUID, SUPP_UNREAD_ALERT_CAT_CHR_UUID,
 			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ,
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ 14/25] alert: Update Supported New/Unread Category characteristic values
From: Anderson Lizardo @ 2012-09-24 18:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1348509661-15967-1-git-send-email-anderson.lizardo@openbossa.org>

The value is now kept up-to-date when new/unread alerts arrive. This
value is not notified yet.
---
 profiles/alert/server.c |   34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/profiles/alert/server.c b/profiles/alert/server.c
index fb95f09..f1021cc 100644
--- a/profiles/alert/server.c
+++ b/profiles/alert/server.c
@@ -89,7 +89,8 @@ struct alert_data {
 
 struct alert_adapter {
 	struct btd_adapter *adapter;
-	/* TODO: store characteristic value handles */
+	uint16_t supp_new_alert_cat_handle;
+	uint16_t supp_unread_alert_cat_handle;
 };
 
 static GSList *registered_alerts = NULL;
@@ -235,6 +236,29 @@ static gboolean valid_count(const char *category, uint16_t count)
 	return FALSE;
 }
 
+static void update_supported_categories(gpointer data, gpointer user_data)
+{
+	struct alert_adapter *al_adapter = data;
+	struct btd_adapter *adapter = al_adapter->adapter;
+	uint8_t value[2];
+	unsigned int i;
+
+	memset(value, 0, sizeof(value));
+
+	for (i = 0; i < G_N_ELEMENTS(anp_categories); i++) {
+		if (registered_category(anp_categories[i]))
+			hci_set_bit(i, value);
+	}
+
+	attrib_db_update(adapter, al_adapter->supp_new_alert_cat_handle, NULL,
+						value, sizeof(value), NULL);
+
+	/* FIXME: For now report all registered categories as supporting unread
+	 * status, until it is known which ones should be supported */
+	attrib_db_update(adapter, al_adapter->supp_unread_alert_cat_handle,
+					NULL, value, sizeof(value), NULL);
+}
+
 static void watcher_disconnect(DBusConnection *conn, void *user_data)
 {
 	struct alert_data *alert = user_data;
@@ -243,6 +267,8 @@ static void watcher_disconnect(DBusConnection *conn, void *user_data)
 
 	registered_alerts = g_slist_remove(registered_alerts, alert);
 	alert_data_destroy(alert);
+
+	g_slist_foreach(alert_adapters, update_supported_categories, NULL);
 }
 
 static DBusMessage *register_alert(DBusConnection *conn, DBusMessage *msg,
@@ -285,6 +311,8 @@ static DBusMessage *register_alert(DBusConnection *conn, DBusMessage *msg,
 
 	registered_alerts = g_slist_append(registered_alerts, alert);
 
+	g_slist_foreach(alert_adapters, update_supported_categories, NULL);
+
 	DBG("RegisterAlert(\"%s\", \"%s\")", alert->category, alert->path);
 
 	return dbus_message_new_method_return(msg);
@@ -505,6 +533,8 @@ static void register_alert_notif_service(struct alert_adapter *al_adapter)
 			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ,
 			GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
 			supp_new_alert_cat_read, al_adapter->adapter,
+			GATT_OPT_CHR_VALUE_GET_HANDLE,
+			&al_adapter->supp_new_alert_cat_handle,
 			/* New Alert */
 			GATT_OPT_CHR_UUID, NEW_ALERT_CHR_UUID,
 			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_NOTIFY,
@@ -513,6 +543,8 @@ static void register_alert_notif_service(struct alert_adapter *al_adapter)
 			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ,
 			GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
 			supp_unread_alert_cat_read, al_adapter->adapter,
+			GATT_OPT_CHR_VALUE_GET_HANDLE,
+			&al_adapter->supp_unread_alert_cat_handle,
 			/* Unread Alert Status */
 			GATT_OPT_CHR_UUID, UNREAD_ALERT_CHR_UUID,
 			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_NOTIFY,
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ 13/25] alert: Add per adapter attribute handle information
From: Anderson Lizardo @ 2012-09-24 18:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1348509661-15967-1-git-send-email-anderson.lizardo@openbossa.org>

Each adapter may have different GATT services running, therefore any
attribute handles (e.g. for updating characteristic values) need to be
saved per adapter.
---
 profiles/alert/server.c |   57 ++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 47 insertions(+), 10 deletions(-)

diff --git a/profiles/alert/server.c b/profiles/alert/server.c
index e6402b7..fb95f09 100644
--- a/profiles/alert/server.c
+++ b/profiles/alert/server.c
@@ -87,7 +87,13 @@ struct alert_data {
 	guint watcher;
 };
 
+struct alert_adapter {
+	struct btd_adapter *adapter;
+	/* TODO: store characteristic value handles */
+};
+
 static GSList *registered_alerts = NULL;
+static GSList *alert_adapters = NULL;
 static uint8_t ringer_setting = RINGER_NORMAL;
 static uint8_t alert_status = 0;
 
@@ -110,6 +116,21 @@ static const char *pasp_categories[] = {
 	"display",
 };
 
+static int adapter_cmp(gconstpointer a, gconstpointer b)
+{
+	const struct alert_adapter *al_adapter = a;
+	const struct btd_adapter *adapter = b;
+
+	return (al_adapter->adapter == adapter ? 0 : -1);
+}
+
+static struct alert_adapter *find_alert_adapter(struct btd_adapter *adapter)
+{
+	GSList *l = g_slist_find_custom(alert_adapters, adapter, adapter_cmp);
+
+	return (l ? l->data : NULL);
+}
+
 static void alert_data_destroy(gpointer user_data)
 {
 	struct alert_data *alert = user_data;
@@ -379,20 +400,20 @@ static uint8_t ringer_setting_read(struct attribute *a,
 	return 0;
 }
 
-static void register_phone_alert_service(struct btd_adapter *adapter)
+static void register_phone_alert_service(struct alert_adapter *al_adapter)
 {
 	bt_uuid_t uuid;
 
 	bt_uuid16_create(&uuid, PHONE_ALERT_STATUS_SVC_UUID);
 
 	/* Phone Alert Status Service */
-	gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid,
+	gatt_service_add(al_adapter->adapter, GATT_PRIM_SVC_UUID, &uuid,
 			/* Alert Status characteristic */
 			GATT_OPT_CHR_UUID, ALERT_STATUS_CHR_UUID,
 			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ |
 							ATT_CHAR_PROPER_NOTIFY,
 			GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
-			alert_status_read, adapter,
+			alert_status_read, al_adapter->adapter,
 			/* Ringer Control Point characteristic */
 			GATT_OPT_CHR_UUID, RINGER_CP_CHR_UUID,
 			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_WRITE_WITHOUT_RESP,
@@ -403,7 +424,7 @@ static void register_phone_alert_service(struct btd_adapter *adapter)
 			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ |
 							ATT_CHAR_PROPER_NOTIFY,
 			GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
-			ringer_setting_read, adapter,
+			ringer_setting_read, al_adapter->adapter,
 			GATT_OPT_INVALID);
 }
 
@@ -471,19 +492,19 @@ static uint8_t alert_notif_cp_write(struct attribute *a,
 	return 0;
 }
 
-static void register_alert_notif_service(struct btd_adapter *adapter)
+static void register_alert_notif_service(struct alert_adapter *al_adapter)
 {
 	bt_uuid_t uuid;
 
 	bt_uuid16_create(&uuid, ALERT_NOTIF_SVC_UUID);
 
 	/* Alert Notification Service */
-	gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid,
+	gatt_service_add(al_adapter->adapter, GATT_PRIM_SVC_UUID, &uuid,
 			/* Supported New Alert Category */
 			GATT_OPT_CHR_UUID, SUPP_NEW_ALERT_CAT_CHR_UUID,
 			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ,
 			GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
-			supp_new_alert_cat_read, adapter,
+			supp_new_alert_cat_read, al_adapter->adapter,
 			/* New Alert */
 			GATT_OPT_CHR_UUID, NEW_ALERT_CHR_UUID,
 			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_NOTIFY,
@@ -491,7 +512,7 @@ static void register_alert_notif_service(struct btd_adapter *adapter)
 			GATT_OPT_CHR_UUID, SUPP_UNREAD_ALERT_CAT_CHR_UUID,
 			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ,
 			GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
-			supp_unread_alert_cat_read, adapter,
+			supp_unread_alert_cat_read, al_adapter->adapter,
 			/* Unread Alert Status */
 			GATT_OPT_CHR_UUID, UNREAD_ALERT_CHR_UUID,
 			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_NOTIFY,
@@ -505,14 +526,30 @@ static void register_alert_notif_service(struct btd_adapter *adapter)
 
 static int alert_server_probe(struct btd_adapter *adapter)
 {
-	register_phone_alert_service(adapter);
-	register_alert_notif_service(adapter);
+	struct alert_adapter *al_adapter;
+
+	al_adapter = g_new0(struct alert_adapter, 1);
+	al_adapter->adapter = btd_adapter_ref(adapter);
+
+	alert_adapters = g_slist_append(alert_adapters, al_adapter);
+
+	register_phone_alert_service(al_adapter);
+	register_alert_notif_service(al_adapter);
 
 	return 0;
 }
 
 static void alert_server_remove(struct btd_adapter *adapter)
 {
+	struct alert_adapter *al_adapter;
+
+	al_adapter = find_alert_adapter(adapter);
+	if (!al_adapter)
+		return;
+
+	alert_adapters = g_slist_remove(alert_adapters, al_adapter);
+	btd_adapter_unref(al_adapter->adapter);
+	g_free(al_adapter);
 }
 
 static struct btd_profile alert_profile = {
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ 12/25] alert: Automatically unregister alert when agent leaves D-Bus
From: Anderson Lizardo @ 2012-09-24 18:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Eder Ruiz Maria
In-Reply-To: <1348509661-15967-1-git-send-email-anderson.lizardo@openbossa.org>

From: Eder Ruiz Maria <eder.ruiz@openbossa.org>

---
 profiles/alert/server.c |   23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/profiles/alert/server.c b/profiles/alert/server.c
index 8630931..e6402b7 100644
--- a/profiles/alert/server.c
+++ b/profiles/alert/server.c
@@ -84,6 +84,7 @@ struct alert_data {
 	const char *category;
 	char *srv;
 	char *path;
+	guint watcher;
 };
 
 static GSList *registered_alerts = NULL;
@@ -113,6 +114,9 @@ static void alert_data_destroy(gpointer user_data)
 {
 	struct alert_data *alert = user_data;
 
+	if (alert->watcher)
+		g_dbus_remove_watch(btd_get_dbus_connection(), alert->watcher);
+
 	g_free(alert->srv);
 	g_free(alert->path);
 	g_free(alert);
@@ -210,6 +214,16 @@ static gboolean valid_count(const char *category, uint16_t count)
 	return FALSE;
 }
 
+static void watcher_disconnect(DBusConnection *conn, void *user_data)
+{
+	struct alert_data *alert = user_data;
+
+	DBG("Category %s was disconnected", alert->category);
+
+	registered_alerts = g_slist_remove(registered_alerts, alert);
+	alert_data_destroy(alert);
+}
+
 static DBusMessage *register_alert(DBusConnection *conn, DBusMessage *msg,
 								void *data)
 {
@@ -238,6 +252,15 @@ static DBusMessage *register_alert(DBusConnection *conn, DBusMessage *msg,
 	alert->srv = g_strdup(sender);
 	alert->path = g_strdup(path);
 	alert->category = category;
+	alert->watcher = g_dbus_add_disconnect_watch(conn, alert->srv,
+					watcher_disconnect, alert, NULL);
+
+	if (alert->watcher == 0) {
+		alert_data_destroy(alert);
+		DBG("Could not register disconnect watcher");
+		return btd_error_failed(msg,
+				"Could not register disconnect watcher");
+	}
 
 	registered_alerts = g_slist_append(registered_alerts, alert);
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ 11/25] alert: Add initial support for UnreadAlert D-Bus method
From: Anderson Lizardo @ 2012-09-24 18:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1348509661-15967-1-git-send-email-anderson.lizardo@openbossa.org>

This method is used for updating the "unread" counter for categories
that support it.
---
 profiles/alert/server.c |   33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/profiles/alert/server.c b/profiles/alert/server.c
index d70f82a..8630931 100644
--- a/profiles/alert/server.c
+++ b/profiles/alert/server.c
@@ -287,6 +287,36 @@ static DBusMessage *new_alert(DBusConnection *conn, DBusMessage *msg,
 	return dbus_message_new_method_return(msg);
 }
 
+static DBusMessage *unread_alert(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	const char *sender = dbus_message_get_sender(msg);
+	struct alert_data *alert;
+	const char *category;
+	uint16_t count;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &category,
+						DBUS_TYPE_UINT16, &count,
+						DBUS_TYPE_INVALID))
+		return btd_error_invalid_args(msg);
+
+	alert = get_alert_data_by_category(category);
+	if (!alert) {
+		DBG("Category %s not registered", category);
+		return btd_error_invalid_args(msg);
+	}
+
+	if (!g_str_equal(alert->srv, sender)) {
+		DBG("Sender %s is not registered in category %s", sender,
+								category);
+		return btd_error_invalid_args(msg);
+	}
+
+	DBG("category %s, count %d", category, count);
+
+	return dbus_message_new_method_return(msg);
+}
+
 static uint8_t ringer_cp_write(struct attribute *a,
 						struct btd_device *device,
 						gpointer user_data)
@@ -478,6 +508,9 @@ static const GDBusMethodTable alert_methods[] = {
 				   { "count", "q" },
 				   { "description", "s" }), NULL,
 			new_alert) },
+	{ GDBUS_METHOD("UnreadAlert",
+			GDBUS_ARGS({ "category", "s" }, { "count", "q" }), NULL,
+			unread_alert) },
 	{ }
 };
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ 10/25] alert: Add initial support for NewAlert D-Bus method
From: Anderson Lizardo @ 2012-09-24 18:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Eder Ruiz Maria
In-Reply-To: <1348509661-15967-1-git-send-email-anderson.lizardo@openbossa.org>

From: Eder Ruiz Maria <eder.ruiz@openbossa.org>

NewAlert() is used for notifying BlueZ of new alert(s) for the given
category.
---
 profiles/alert/server.c |  106 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 105 insertions(+), 1 deletion(-)

diff --git a/profiles/alert/server.c b/profiles/alert/server.c
index 533d47e..d70f82a 100644
--- a/profiles/alert/server.c
+++ b/profiles/alert/server.c
@@ -62,6 +62,9 @@
 #define ALERT_OBJECT_PATH "/org/bluez"
 #define ALERT_INTERFACE   "org.bluez.Alert"
 
+/* Maximum length for "Text String Information" */
+#define NEW_ALERT_MAX_INFO_SIZE		18
+
 enum {
 	ENABLE_NEW_INCOMING,
 	ENABLE_UNREAD_CAT,
@@ -138,7 +141,7 @@ static const char *valid_category(const char *category)
 	return NULL;
 }
 
-static gboolean registered_category(const char *category)
+static struct alert_data *get_alert_data_by_category(const char *category)
 {
 	GSList *l;
 	struct alert_data *alert;
@@ -146,9 +149,64 @@ static gboolean registered_category(const char *category)
 	for (l = registered_alerts; l; l = g_slist_next(l)) {
 		alert = l->data;
 		if (g_str_equal(alert->category, category))
+			return alert;
+	}
+
+	return NULL;
+}
+
+static gboolean registered_category(const char *category)
+{
+	struct alert_data *alert;
+
+	alert = get_alert_data_by_category(category);
+	if (alert)
+		return TRUE;
+
+	return FALSE;
+}
+
+static gboolean pasp_category(const char *category)
+{
+	unsigned i;
+
+	for (i = 0; i < G_N_ELEMENTS(pasp_categories); i++)
+		if (g_str_equal(category, pasp_categories[i]))
 			return TRUE;
+
+	return FALSE;
+}
+
+static gboolean valid_description(const char *category,
+							const char *description)
+{
+	if (!pasp_category(category)) {
+		if (strlen(description) >= NEW_ALERT_MAX_INFO_SIZE)
+			return FALSE;
+
+		return TRUE;
 	}
 
+	if (g_str_equal(description, "active") ||
+					g_str_equal(description, "not active"))
+		return TRUE;
+
+	if (g_str_equal(category, "ringer"))
+		if (g_str_equal(description, "enabled") ||
+					g_str_equal(description, "disabled"))
+			return TRUE;
+
+	return FALSE;
+}
+
+static gboolean valid_count(const char *category, uint16_t count)
+{
+	if (!pasp_category(category) && count > 0 && count <= 255)
+		return TRUE;
+
+	if (pasp_category(category) && count == 1)
+		return TRUE;
+
 	return FALSE;
 }
 
@@ -188,6 +246,47 @@ static DBusMessage *register_alert(DBusConnection *conn, DBusMessage *msg,
 	return dbus_message_new_method_return(msg);
 }
 
+static DBusMessage *new_alert(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	const char *sender = dbus_message_get_sender(msg);
+	const char *category, *description;
+	struct alert_data *alert;
+	uint16_t count;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &category,
+			DBUS_TYPE_UINT16, &count, DBUS_TYPE_STRING,
+			&description, DBUS_TYPE_INVALID))
+		return btd_error_invalid_args(msg);
+
+	alert = get_alert_data_by_category(category);
+	if (!alert) {
+		DBG("Category %s not registered", category);
+		return btd_error_invalid_args(msg);
+	}
+
+	if (!g_str_equal(alert->srv, sender)) {
+		DBG("Sender %s is not registered in category %s", sender,
+								category);
+		return btd_error_invalid_args(msg);
+	}
+
+	if (!valid_description(category, description)) {
+		DBG("Description %s is invalid for %s category",
+							description, category);
+		return btd_error_invalid_args(msg);
+	}
+
+	if (!valid_count(category, count)) {
+		DBG("Count %d is invalid for %s category", count, category);
+		return btd_error_invalid_args(msg);
+	}
+
+	DBG("NewAlert(\"%s\", %d, \"%s\")", category, count, description);
+
+	return dbus_message_new_method_return(msg);
+}
+
 static uint8_t ringer_cp_write(struct attribute *a,
 						struct btd_device *device,
 						gpointer user_data)
@@ -374,6 +473,11 @@ static const GDBusMethodTable alert_methods[] = {
 			GDBUS_ARGS({ "category", "s" },
 				   { "agent", "o" }), NULL,
 			register_alert) },
+	{ GDBUS_METHOD("NewAlert",
+			GDBUS_ARGS({ "category", "s" },
+				   { "count", "q" },
+				   { "description", "s" }), NULL,
+			new_alert) },
 	{ }
 };
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ 09/25] alert: Implement category registration in RegisterAlert()
From: Anderson Lizardo @ 2012-09-24 18:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Eder Ruiz Maria
In-Reply-To: <1348509661-15967-1-git-send-email-anderson.lizardo@openbossa.org>

From: Eder Ruiz Maria <eder.ruiz@openbossa.org>

The given alert category is now validated and registered.
---
 profiles/alert/server.c |  102 +++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 98 insertions(+), 4 deletions(-)

diff --git a/profiles/alert/server.c b/profiles/alert/server.c
index 0df77c5..533d47e 100644
--- a/profiles/alert/server.c
+++ b/profiles/alert/server.c
@@ -77,19 +77,113 @@ enum {
 	RINGER_NORMAL,
 };
 
+struct alert_data {
+	const char *category;
+	char *srv;
+	char *path;
+};
+
+static GSList *registered_alerts = NULL;
 static uint8_t ringer_setting = RINGER_NORMAL;
 static uint8_t alert_status = 0;
 
+static const char *anp_categories[] = {
+	"simple",
+	"email",
+	"news",
+	"call",
+	"missed_call",
+	"sms_mms",
+	"voice_mail",
+	"schedule",
+	"high_priority",
+	"instant_message",
+};
+
+static const char *pasp_categories[] = {
+	"ringer",
+	"vibrate",
+	"display",
+};
+
+static void alert_data_destroy(gpointer user_data)
+{
+	struct alert_data *alert = user_data;
+
+	g_free(alert->srv);
+	g_free(alert->path);
+	g_free(alert);
+}
+
+static void alert_destroy(gpointer user_data)
+{
+	g_slist_free_full(registered_alerts, alert_data_destroy);
+	registered_alerts = NULL;
+}
+
+static const char *valid_category(const char *category)
+{
+	unsigned i;
+
+	for (i = 0; i < G_N_ELEMENTS(anp_categories); i++) {
+		if (g_str_equal(anp_categories[i], category))
+			return anp_categories[i];
+	}
+
+	for (i = 0; i < G_N_ELEMENTS(pasp_categories); i++) {
+		if (g_str_equal(pasp_categories[i], category))
+			return pasp_categories[i];
+	}
+
+	return NULL;
+}
+
+static gboolean registered_category(const char *category)
+{
+	GSList *l;
+	struct alert_data *alert;
+
+	for (l = registered_alerts; l; l = g_slist_next(l)) {
+		alert = l->data;
+		if (g_str_equal(alert->category, category))
+			return TRUE;
+	}
+
+	return FALSE;
+}
+
 static DBusMessage *register_alert(DBusConnection *conn, DBusMessage *msg,
 								void *data)
 {
+	const char *sender = dbus_message_get_sender(msg);
+	char *path;
 	const char *category;
+	const char *c;
+	struct alert_data *alert;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &c,
+			DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID))
+		return btd_error_invalid_args(msg);
 
-	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &category,
-							DBUS_TYPE_INVALID))
+	category = valid_category(c);
+	if (!category) {
+		DBG("Invalid category: %s", c);
 		return btd_error_invalid_args(msg);
+	}
+
+	if (registered_category(category)) {
+		DBG("Category %s already registered", category);
+		return dbus_message_new_method_return(msg);
+	}
+
+	alert = g_new0(struct alert_data, 1);
+	alert->srv = g_strdup(sender);
+	alert->path = g_strdup(path);
+	alert->category = category;
+
+	registered_alerts = g_slist_append(registered_alerts, alert);
 
-	DBG("RegisterAlert: %s", category);
+	DBG("RegisterAlert(\"%s\", \"%s\")", alert->category, alert->path);
 
 	return dbus_message_new_method_return(msg);
 }
@@ -288,7 +382,7 @@ int alert_server_init(void)
 	if (!g_dbus_register_interface(btd_get_dbus_connection(),
 					ALERT_OBJECT_PATH, ALERT_INTERFACE,
 					alert_methods, NULL, NULL, NULL,
-					NULL)) {
+					alert_destroy)) {
 		error("D-Bus failed to register %s interface",
 							ALERT_INTERFACE);
 		return -EIO;
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ 08/25] alert: Initial Alert Notification
From: Anderson Lizardo @ 2012-09-24 18:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1348509661-15967-1-git-send-email-anderson.lizardo@openbossa.org>

Initial implementation for Alert Notification Profile (ANP).
---
 profiles/alert/server.c |  154 +++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 154 insertions(+)

diff --git a/profiles/alert/server.c b/profiles/alert/server.c
index 0dcefbb..0df77c5 100644
--- a/profiles/alert/server.c
+++ b/profiles/alert/server.c
@@ -27,9 +27,12 @@
 #endif
 
 #include <stdbool.h>
+#include <errno.h>
+#include <gdbus.h>
 #include <glib.h>
 #include <bluetooth/uuid.h>
 
+#include "dbus-common.h"
 #include "att.h"
 #include "adapter.h"
 #include "device.h"
@@ -41,13 +44,33 @@
 #include "gatt.h"
 #include "server.h"
 #include "profile.h"
+#include "error.h"
 
 #define PHONE_ALERT_STATUS_SVC_UUID		0x180E
+#define ALERT_NOTIF_SVC_UUID			0x1811
 
 #define ALERT_STATUS_CHR_UUID		0x2A3F
 #define RINGER_CP_CHR_UUID		0x2A40
 #define RINGER_SETTING_CHR_UUID		0x2A41
 
+#define ALERT_NOTIF_CP_CHR_UUID		0x2A44
+#define UNREAD_ALERT_CHR_UUID		0x2A45
+#define NEW_ALERT_CHR_UUID		0x2A46
+#define SUPP_NEW_ALERT_CAT_CHR_UUID	0x2A47
+#define SUPP_UNREAD_ALERT_CAT_CHR_UUID	0x2A48
+
+#define ALERT_OBJECT_PATH "/org/bluez"
+#define ALERT_INTERFACE   "org.bluez.Alert"
+
+enum {
+	ENABLE_NEW_INCOMING,
+	ENABLE_UNREAD_CAT,
+	DISABLE_NEW_INCOMING,
+	DISABLE_UNREAD_CAT,
+	NOTIFY_NEW_INCOMING,
+	NOTIFY_UNREAD_CAT,
+};
+
 /* Ringer Setting characteristic values */
 enum {
 	RINGER_SILENT,
@@ -57,6 +80,20 @@ enum {
 static uint8_t ringer_setting = RINGER_NORMAL;
 static uint8_t alert_status = 0;
 
+static DBusMessage *register_alert(DBusConnection *conn, DBusMessage *msg,
+								void *data)
+{
+	const char *category;
+
+	if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &category,
+							DBUS_TYPE_INVALID))
+		return btd_error_invalid_args(msg);
+
+	DBG("RegisterAlert: %s", category);
+
+	return dbus_message_new_method_return(msg);
+}
+
 static uint8_t ringer_cp_write(struct attribute *a,
 						struct btd_device *device,
 						gpointer user_data)
@@ -124,9 +161,106 @@ static void register_phone_alert_service(struct btd_adapter *adapter)
 			GATT_OPT_INVALID);
 }
 
+static uint8_t supp_new_alert_cat_read(struct attribute *a,
+						struct btd_device *device,
+						gpointer user_data)
+{
+	struct btd_adapter *adapter = user_data;
+	uint8_t value[] = {0x00, 0x00};
+
+	DBG("a = %p", a);
+
+	if (a->data == NULL)
+		attrib_db_update(adapter, a->handle, NULL, value, sizeof(value),
+									NULL);
+
+	return 0;
+}
+
+static uint8_t supp_unread_alert_cat_read(struct attribute *a,
+						struct btd_device *device,
+						gpointer user_data)
+{
+	struct btd_adapter *adapter = user_data;
+	uint8_t value[] = {0x00, 0x00};
+
+	DBG("a = %p", a);
+
+	if (a->data == NULL)
+		attrib_db_update(adapter, a->handle, NULL, value, sizeof(value),
+									NULL);
+
+	return 0;
+}
+
+static uint8_t alert_notif_cp_write(struct attribute *a,
+						struct btd_device *device,
+						gpointer user_data)
+{
+	DBG("a = %p", a);
+
+	switch (a->data[0]) {
+	case ENABLE_NEW_INCOMING:
+		DBG("ENABLE_NEW_INCOMING: 0x%02x", a->data[1]);
+		break;
+	case ENABLE_UNREAD_CAT:
+		DBG("ENABLE_UNREAD_CAT: 0x%02x", a->data[1]);
+		break;
+	case DISABLE_NEW_INCOMING:
+		DBG("DISABLE_NEW_INCOMING: 0x%02x", a->data[1]);
+		break;
+	case DISABLE_UNREAD_CAT:
+		DBG("DISABLE_UNREAD_CAT: 0x%02x", a->data[1]);
+		break;
+	case NOTIFY_NEW_INCOMING:
+		DBG("NOTIFY_NEW_INCOMING: 0x%02x", a->data[1]);
+		break;
+	case NOTIFY_UNREAD_CAT:
+		DBG("NOTIFY_UNREAD_CAT: 0x%02x", a->data[1]);
+		break;
+	default:
+		DBG("0x%02x 0x%02x", a->data[0], a->data[1]);
+	}
+
+	return 0;
+}
+
+static void register_alert_notif_service(struct btd_adapter *adapter)
+{
+	bt_uuid_t uuid;
+
+	bt_uuid16_create(&uuid, ALERT_NOTIF_SVC_UUID);
+
+	/* Alert Notification Service */
+	gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid,
+			/* Supported New Alert Category */
+			GATT_OPT_CHR_UUID, SUPP_NEW_ALERT_CAT_CHR_UUID,
+			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ,
+			GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
+			supp_new_alert_cat_read, adapter,
+			/* New Alert */
+			GATT_OPT_CHR_UUID, NEW_ALERT_CHR_UUID,
+			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_NOTIFY,
+			/* Supported Unread Alert Category */
+			GATT_OPT_CHR_UUID, SUPP_UNREAD_ALERT_CAT_CHR_UUID,
+			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ,
+			GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
+			supp_unread_alert_cat_read, adapter,
+			/* Unread Alert Status */
+			GATT_OPT_CHR_UUID, UNREAD_ALERT_CHR_UUID,
+			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_NOTIFY,
+			/* Alert Notification Control Point */
+			GATT_OPT_CHR_UUID, ALERT_NOTIF_CP_CHR_UUID,
+			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_WRITE,
+			GATT_OPT_CHR_VALUE_CB, ATTRIB_WRITE,
+			alert_notif_cp_write, NULL,
+			GATT_OPT_INVALID);
+}
+
 static int alert_server_probe(struct btd_adapter *adapter)
 {
 	register_phone_alert_service(adapter);
+	register_alert_notif_service(adapter);
 
 	return 0;
 }
@@ -141,8 +275,25 @@ static struct btd_profile alert_profile = {
 	.adapter_remove = alert_server_remove,
 };
 
+static const GDBusMethodTable alert_methods[] = {
+	{ GDBUS_METHOD("RegisterAlert",
+			GDBUS_ARGS({ "category", "s" },
+				   { "agent", "o" }), NULL,
+			register_alert) },
+	{ }
+};
+
 int alert_server_init(void)
 {
+	if (!g_dbus_register_interface(btd_get_dbus_connection(),
+					ALERT_OBJECT_PATH, ALERT_INTERFACE,
+					alert_methods, NULL, NULL, NULL,
+					NULL)) {
+		error("D-Bus failed to register %s interface",
+							ALERT_INTERFACE);
+		return -EIO;
+	}
+
 	btd_profile_register(&alert_profile);
 
 	return 0;
@@ -151,4 +302,7 @@ int alert_server_init(void)
 void alert_server_exit(void)
 {
 	btd_profile_unregister(&alert_profile);
+
+	g_dbus_unregister_interface(btd_get_dbus_connection(),
+					ALERT_OBJECT_PATH, ALERT_INTERFACE);
 }
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ 07/25] alert: Add Alert Status characteristic
From: Anderson Lizardo @ 2012-09-24 18:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1348509661-15967-1-git-send-email-anderson.lizardo@openbossa.org>

From: Bruna Moreira <bruna.moreira@openbossa.org>

This characteristic allows to read/notify the status of the ringer,
display and vibration motor.
---
 profiles/alert/server.c |   24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/profiles/alert/server.c b/profiles/alert/server.c
index a66d431..0dcefbb 100644
--- a/profiles/alert/server.c
+++ b/profiles/alert/server.c
@@ -43,6 +43,8 @@
 #include "profile.h"
 
 #define PHONE_ALERT_STATUS_SVC_UUID		0x180E
+
+#define ALERT_STATUS_CHR_UUID		0x2A3F
 #define RINGER_CP_CHR_UUID		0x2A40
 #define RINGER_SETTING_CHR_UUID		0x2A41
 
@@ -53,6 +55,7 @@ enum {
 };
 
 static uint8_t ringer_setting = RINGER_NORMAL;
+static uint8_t alert_status = 0;
 
 static uint8_t ringer_cp_write(struct attribute *a,
 						struct btd_device *device,
@@ -63,6 +66,21 @@ static uint8_t ringer_cp_write(struct attribute *a,
 	return 0;
 }
 
+static uint8_t alert_status_read(struct attribute *a,
+						struct btd_device *device,
+						gpointer user_data)
+{
+	struct btd_adapter *adapter = user_data;
+
+	DBG("a = %p", a);
+
+	if (a->data == NULL || a->data[0] != alert_status)
+		attrib_db_update(adapter, a->handle, NULL, &alert_status,
+						sizeof(alert_status), NULL);
+
+	return 0;
+}
+
 static uint8_t ringer_setting_read(struct attribute *a,
 						struct btd_device *device,
 						gpointer user_data)
@@ -86,6 +104,12 @@ static void register_phone_alert_service(struct btd_adapter *adapter)
 
 	/* Phone Alert Status Service */
 	gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid,
+			/* Alert Status characteristic */
+			GATT_OPT_CHR_UUID, ALERT_STATUS_CHR_UUID,
+			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ |
+							ATT_CHAR_PROPER_NOTIFY,
+			GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
+			alert_status_read, adapter,
 			/* Ringer Control Point characteristic */
 			GATT_OPT_CHR_UUID, RINGER_CP_CHR_UUID,
 			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_WRITE_WITHOUT_RESP,
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ 06/25] alert: Add Ringer Setting characteristic
From: Anderson Lizardo @ 2012-09-24 18:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1348509661-15967-1-git-send-email-anderson.lizardo@openbossa.org>

From: Bruna Moreira <bruna.moreira@openbossa.org>

This characteristic allows to read or notify the ringer mode (silent or
normal).
---
 profiles/alert/server.c |   31 +++++++++++++++++++++++++++++++
 1 file changed, 31 insertions(+)

diff --git a/profiles/alert/server.c b/profiles/alert/server.c
index 68ef0c0..a66d431 100644
--- a/profiles/alert/server.c
+++ b/profiles/alert/server.c
@@ -37,12 +37,22 @@
 #include "log.h"
 #include "gatt-service.h"
 #include "gattrib.h"
+#include "attrib-server.h"
 #include "gatt.h"
 #include "server.h"
 #include "profile.h"
 
 #define PHONE_ALERT_STATUS_SVC_UUID		0x180E
 #define RINGER_CP_CHR_UUID		0x2A40
+#define RINGER_SETTING_CHR_UUID		0x2A41
+
+/* Ringer Setting characteristic values */
+enum {
+	RINGER_SILENT,
+	RINGER_NORMAL,
+};
+
+static uint8_t ringer_setting = RINGER_NORMAL;
 
 static uint8_t ringer_cp_write(struct attribute *a,
 						struct btd_device *device,
@@ -53,6 +63,21 @@ static uint8_t ringer_cp_write(struct attribute *a,
 	return 0;
 }
 
+static uint8_t ringer_setting_read(struct attribute *a,
+						struct btd_device *device,
+						gpointer user_data)
+{
+	struct btd_adapter *adapter = user_data;
+
+	DBG("a = %p", a);
+
+	if (a->data == NULL || a->data[0] != ringer_setting)
+		attrib_db_update(adapter, a->handle, NULL, &ringer_setting,
+						sizeof(ringer_setting), NULL);
+
+	return 0;
+}
+
 static void register_phone_alert_service(struct btd_adapter *adapter)
 {
 	bt_uuid_t uuid;
@@ -66,6 +91,12 @@ static void register_phone_alert_service(struct btd_adapter *adapter)
 			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_WRITE_WITHOUT_RESP,
 			GATT_OPT_CHR_VALUE_CB, ATTRIB_WRITE,
 			ringer_cp_write, NULL,
+			/* Ringer Setting characteristic */
+			GATT_OPT_CHR_UUID, RINGER_SETTING_CHR_UUID,
+			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ |
+							ATT_CHAR_PROPER_NOTIFY,
+			GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
+			ringer_setting_read, adapter,
 			GATT_OPT_INVALID);
 }
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ 05/25] alert: Add Ringer Control Point characteristic
From: Anderson Lizardo @ 2012-09-24 18:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1348509661-15967-1-git-send-email-anderson.lizardo@openbossa.org>

From: Bruna Moreira <bruna.moreira@openbossa.org>

Ringer CP characteristic is used for configuring "silent mode" or muting
the ringer once.
---
 profiles/alert/server.c |   18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/profiles/alert/server.c b/profiles/alert/server.c
index a35da99..68ef0c0 100644
--- a/profiles/alert/server.c
+++ b/profiles/alert/server.c
@@ -32,6 +32,9 @@
 
 #include "att.h"
 #include "adapter.h"
+#include "device.h"
+#include "att-database.h"
+#include "log.h"
 #include "gatt-service.h"
 #include "gattrib.h"
 #include "gatt.h"
@@ -39,6 +42,16 @@
 #include "profile.h"
 
 #define PHONE_ALERT_STATUS_SVC_UUID		0x180E
+#define RINGER_CP_CHR_UUID		0x2A40
+
+static uint8_t ringer_cp_write(struct attribute *a,
+						struct btd_device *device,
+						gpointer user_data)
+{
+	DBG("a = %p", a);
+
+	return 0;
+}
 
 static void register_phone_alert_service(struct btd_adapter *adapter)
 {
@@ -48,6 +61,11 @@ static void register_phone_alert_service(struct btd_adapter *adapter)
 
 	/* Phone Alert Status Service */
 	gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid,
+			/* Ringer Control Point characteristic */
+			GATT_OPT_CHR_UUID, RINGER_CP_CHR_UUID,
+			GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_WRITE_WITHOUT_RESP,
+			GATT_OPT_CHR_VALUE_CB, ATTRIB_WRITE,
+			ringer_cp_write, NULL,
 			GATT_OPT_INVALID);
 }
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ 04/25] alert: Add Phone Alert Status Service
From: Anderson Lizardo @ 2012-09-24 18:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Bruna Moreira
In-Reply-To: <1348509661-15967-1-git-send-email-anderson.lizardo@openbossa.org>

From: Bruna Moreira <bruna.moreira@openbossa.org>

Add Phone Alert Status service for PASP.
---
 profiles/alert/server.c |   21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/profiles/alert/server.c b/profiles/alert/server.c
index cc6ff19..a35da99 100644
--- a/profiles/alert/server.c
+++ b/profiles/alert/server.c
@@ -27,13 +27,34 @@
 #endif
 
 #include <stdbool.h>
+#include <glib.h>
+#include <bluetooth/uuid.h>
 
+#include "att.h"
 #include "adapter.h"
+#include "gatt-service.h"
+#include "gattrib.h"
+#include "gatt.h"
 #include "server.h"
 #include "profile.h"
 
+#define PHONE_ALERT_STATUS_SVC_UUID		0x180E
+
+static void register_phone_alert_service(struct btd_adapter *adapter)
+{
+	bt_uuid_t uuid;
+
+	bt_uuid16_create(&uuid, PHONE_ALERT_STATUS_SVC_UUID);
+
+	/* Phone Alert Status Service */
+	gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid,
+			GATT_OPT_INVALID);
+}
+
 static int alert_server_probe(struct btd_adapter *adapter)
 {
+	register_phone_alert_service(adapter);
+
 	return 0;
 }
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ 03/25] alert: Initial profile registration
From: Anderson Lizardo @ 2012-09-24 18:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1348509661-15967-1-git-send-email-anderson.lizardo@openbossa.org>

---
 profiles/alert/server.c |   22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/profiles/alert/server.c b/profiles/alert/server.c
index d91b156..cc6ff19 100644
--- a/profiles/alert/server.c
+++ b/profiles/alert/server.c
@@ -26,13 +26,35 @@
 #include <config.h>
 #endif
 
+#include <stdbool.h>
+
+#include "adapter.h"
 #include "server.h"
+#include "profile.h"
+
+static int alert_server_probe(struct btd_adapter *adapter)
+{
+	return 0;
+}
+
+static void alert_server_remove(struct btd_adapter *adapter)
+{
+}
+
+static struct btd_profile alert_profile = {
+	.name = "gatt-alert-server",
+	.adapter_probe = alert_server_probe,
+	.adapter_remove = alert_server_remove,
+};
 
 int alert_server_init(void)
 {
+	btd_profile_register(&alert_profile);
+
 	return 0;
 }
 
 void alert_server_exit(void)
 {
+	btd_profile_unregister(&alert_profile);
 }
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ 02/25] alert: Introduce manager abstraction layer
From: Anderson Lizardo @ 2012-09-24 18:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1348509661-15967-1-git-send-email-anderson.lizardo@openbossa.org>

This abstraction layer makes the GATT Phone Alert Status and Alert
Notification implementation consistent with other GATT profiles.
---
 Makefile.am              |    3 ++-
 profiles/alert/main.c    |    6 +++---
 profiles/alert/manager.c |   40 ++++++++++++++++++++++++++++++++++++++++
 profiles/alert/manager.h |   26 ++++++++++++++++++++++++++
 4 files changed, 71 insertions(+), 4 deletions(-)
 create mode 100644 profiles/alert/manager.c
 create mode 100644 profiles/alert/manager.h

diff --git a/Makefile.am b/Makefile.am
index 372111a..c982110 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -218,7 +218,8 @@ builtin_sources += profiles/thermometer/main.c \
 			profiles/thermometer/thermometer.h \
 			profiles/thermometer/thermometer.c \
 			profiles/alert/main.c profiles/alert/server.h \
-			profiles/alert/server.c \
+			profiles/alert/server.c profiles/alert/manager.h \
+			profiles/alert/manager.c \
 			profiles/time/main.c profiles/time/server.h \
 			profiles/time/server.c profiles/time/manager.c \
 			profiles/time/manager.h \
diff --git a/profiles/alert/main.c b/profiles/alert/main.c
index ec4ab6d..5e6910a 100644
--- a/profiles/alert/main.c
+++ b/profiles/alert/main.c
@@ -33,7 +33,7 @@
 #include "plugin.h"
 #include "hcid.h"
 #include "log.h"
-#include "server.h"
+#include "manager.h"
 
 static int alert_init(void)
 {
@@ -42,7 +42,7 @@ static int alert_init(void)
 		return -ENOTSUP;
 	}
 
-	return alert_server_init();
+	return alert_manager_init();
 }
 
 static void alert_exit(void)
@@ -50,7 +50,7 @@ static void alert_exit(void)
 	if (!main_opts.gatt_enabled)
 		return;
 
-	alert_server_exit();
+	alert_manager_exit();
 }
 
 BLUETOOTH_PLUGIN_DEFINE(alert, VERSION,
diff --git a/profiles/alert/manager.c b/profiles/alert/manager.c
new file mode 100644
index 0000000..eb2d627
--- /dev/null
+++ b/profiles/alert/manager.c
@@ -0,0 +1,40 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Nokia Corporation
+ *  Copyright (C) 2012  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "manager.h"
+#include "server.h"
+
+int alert_manager_init(void)
+{
+	return alert_server_init();
+}
+
+void alert_manager_exit(void)
+{
+	alert_server_exit();
+}
diff --git a/profiles/alert/manager.h b/profiles/alert/manager.h
new file mode 100644
index 0000000..e4c6bd0
--- /dev/null
+++ b/profiles/alert/manager.h
@@ -0,0 +1,26 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Nokia Corporation
+ *  Copyright (C) 2012  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int alert_manager_init(void);
+void alert_manager_exit(void);
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ 01/25] doc: Introduce Alert API
From: Anderson Lizardo @ 2012-09-24 18:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1348509661-15967-1-git-send-email-anderson.lizardo@openbossa.org>

This API will be implemented and initially used by Phone Alert Status
and Alert Notification GATT profiles (server role).
---
 doc/alert-api.txt |  124 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 124 insertions(+)
 create mode 100644 doc/alert-api.txt

diff --git a/doc/alert-api.txt b/doc/alert-api.txt
new file mode 100644
index 0000000..79d65b8
--- /dev/null
+++ b/doc/alert-api.txt
@@ -0,0 +1,124 @@
+BlueZ D-Bus Alert API description
+*********************************
+
+Copyright (C) 2012  Instituto Nokia de Tecnologia - INdT
+
+Introduction
+------------
+
+Currently, there are two different GATT server profiles that depend on
+receiving alerts or notifications from the platform: Phone Alert Status (PASP)
+and Alert Notification (ANP). PASP is very specific to mobile phones, and also
+allows limited control to alerts (i.e. mute once or switch to a silent mode).
+
+This document presents a unified API that allows to register and notify alerts,
+and to control some alerts (using the provided agent object).
+
+
+Alert hierarchy
+===============
+
+Service		org.bluez
+Interface	org.bluez.Alert
+Object path	/org/bluez
+
+Methods		void RegisterAlert(string category, object agent)
+
+			Register a new alert category and an agent for it. This
+			means the application will be responsible for notifying
+			BlueZ of any alerts of that category, using the
+			NewAlert() method.
+
+			Supported ANP categories: simple, email, news, call,
+				missed_call, sms_mms, voice_mail, schedule,
+				high_priority, instant_message
+			Supported PASP categories: ringer, vibrate, display
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+
+		void NewAlert(string category, uint16 count, string description)
+
+			Notify BlueZ of new alert(s) for the given category. The
+			description is relative to the last received alert and
+			can be sender name, caller ID, title, or other
+			information specific to the category.
+
+			For ringer, vibrate and display categories, valid
+			descriptions are "active" and "not active". Alerts from
+			ringer category also accept "enabled" and "disabled",
+			depending on whether ringer is in silent mode or not.
+
+			Description must not exceed 18 bytes when encoded in
+			UTF-8 format, otherwise an error is returned. If there
+			is no description, an empty string should be used.
+
+			The count argument contains the number of alerts not
+			yet acknowledged by the user on the UI. To save D-Bus
+			traffic, events that may generate multiple alerts at
+			the same time (like email, sms, news) should trigger a
+			single NewAlert().
+
+			If there are more than 254 new alerts, count must be
+			set to 255. PASP alerts should always set count to 1.
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+
+		void UnreadAlert(string category, uint16 count)
+
+			Some services (like SMS and e-mail) keep track of
+			number of unread items. This method allows to update
+			this counter, so peer devices can be notified using
+			Alert Notification Profile.
+
+			If there are more than 254 unread alerts, count must be
+			set to 255.
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+
+Alert Agent hierarchy
+=====================
+
+Service		org.bluez
+Interface	org.bluez.AlertAgent
+Object path	freely definable
+
+Methods		void MuteOnce()
+
+			This method is only called if "ringer" alert category
+			is specified when registering the agent.
+
+			Mute the ringer once (e.g. during a incoming call). If
+			ringer is not active, does nothing.
+
+		void SetRinger(string mode)
+
+			This method is only called if "ringer" alert category
+			is specified when registering the agent.
+
+			Set ringer to the specified mode. If mode is "enabled",
+			ringer is set to the default mode, as defined by the
+			current active profile. If mode is "disabled", ringer
+			will not activate on incoming calls, until it is set
+			back to "enabled" mode.
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+
+		void Suspend(string category)
+
+			Suspend alerts for this category, which means that
+			new/unread alerts should not be reported to save D-Bus
+			traffic. This means that no client has enabled this
+			alert yet.
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+
+		void Resume(string category)
+
+			Resume alerts for this category.
+
+			Possible Errors: org.bluez.Error.InvalidArguments
+
+		void Release()
+
+			Release this agent. At this point, it will be not used
+			by BlueZ anymore and can be destroyed by the owner.
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH BlueZ 00/25] Add support for PASP and ANP server profiles
From: Anderson Lizardo @ 2012-09-24 18:00 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo

Hi,

This series implement most of mandatory features for Phone Alert Status (PASP)
and Alert Notification (ANP) profiles. The only major mandatory feature
currently missing is support for ANP control point (which will be added on a
future series).

Note: for those planning to use ANP/PASP in BlueZ using these patches, it is
necessary to implement an "agent" that forwards platform events (SMS, calls,
e-mail, and ringer/display/vibra status) to BlueZ. See doc/alert-api.txt and
test/test-alert for more details. Alternatively, the components that generate
these events can register themselves and report alerts directly to BlueZ.

This implementation was tested against PTS and all tests passed (except for the
features not yet implemented). The D-Bus API was implemented accordingly to the
previously proposed Alert API (documented on the first patch).

Comments/suggestions are welcome.


Anderson Lizardo (11):
  doc: Introduce Alert API
  alert: Introduce manager abstraction layer
  alert: Initial profile registration
  alert: Initial Alert Notification
  alert: Add initial support for UnreadAlert D-Bus method
  alert: Add per adapter attribute handle information
  alert: Update Supported New/Unread Category characteristic values
  alert: Update new alert characteristic value
  alert: Update unread alert characteristic value
  alert: Implement MuteOnce command
  alert: Update Alert Status and Ringer Setting characteristic values

Bruna Moreira (4):
  alert: Add Phone Alert Status Service
  alert: Add Ringer Control Point characteristic
  alert: Add Ringer Setting characteristic
  alert: Add Alert Status characteristic

Eder Ruiz Maria (10):
  alert: Implement category registration in RegisterAlert()
  alert: Add initial support for NewAlert D-Bus method
  alert: Automatically unregister alert when agent leaves D-Bus
  alert: Add support for calling MuteOnce()
  alert: Add support for calling SetRinger()
  alert: Add test-alert script
  alert: Add support for ringer setting notification
  alert: Add support for alert status notification
  alert: Add support for new alert notification
  alert: Add support for unread alert notification

 Makefile.am              |    3 +-
 doc/alert-api.txt        |  124 ++++++
 profiles/alert/main.c    |    6 +-
 profiles/alert/manager.c |   40 ++
 profiles/alert/manager.h |   26 ++
 profiles/alert/server.c  |  944 ++++++++++++++++++++++++++++++++++++++++++++++
 test/test-alert          |  173 +++++++++
 7 files changed, 1312 insertions(+), 4 deletions(-)
 create mode 100644 doc/alert-api.txt
 create mode 100644 profiles/alert/manager.c
 create mode 100644 profiles/alert/manager.h
 create mode 100755 test/test-alert

-- 
1.7.9.5


^ permalink raw reply

* Re: LE thermometer on Ubuntu 12.10
From: Anderson Lizardo @ 2012-09-24 16:49 UTC (permalink / raw)
  To: jonsmirl@gmail.com; +Cc: linux-bluetooth
In-Reply-To: <CAKON4OzNeFMb=8Sm5_Mzb8g8CFT50umTvEc+cRNbJvQzq9UHnQ@mail.gmail.com>

Hi Jon,

On Mon, Sep 24, 2012 at 12:27 PM, jonsmirl@gmail.com <jonsmirl@gmail.com> wrote:
> On Mon, Sep 24, 2012 at 11:11 AM, Anderson Lizardo
> <anderson.lizardo@openbossa.org> wrote:
>> Hi Jon,
>>
>> On Mon, Sep 24, 2012 at 8:55 AM, jonsmirl@gmail.com <jonsmirl@gmail.com> wrote:
>>> Ubuntu 12.10 has 4.101 and kernel 3.5. I'm trying to get the sample
>>> CC2540 thermometer application from TI working.  The 4.101 package
>>> build has --enable-thermometer set.
>>
>> There is no "--enable-thermometer" since 4.100. Please enable GATT
>> with "--enable-gatt". This will enable all supported GATT profiles at
>> once.
>
> Ubuntu is building this wrong for the 12.10 release then.  I'm filing
> a bug about this, what should the configure option be?
>
> I rebuilt their bluez-4.101 package and it complains about...
>
> configure: WARNING: unrecognized options: --enable-proximity,
> --enable-time, --enable-alert, --enable-gatt-example, --enable-tracer,
> --enable-thermometer, --enable-capng

You should check bootstrap-configure for the available options. For
GATT, you now need only --enable-gatt.

Best Regards,
-- 
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil

^ permalink raw reply

* Re: LE thermometer on Ubuntu 12.10
From: jonsmirl @ 2012-09-24 16:27 UTC (permalink / raw)
  To: Anderson Lizardo; +Cc: linux-bluetooth
In-Reply-To: <CAJdJm_N3E+J4rtaT6g=K-Hmd1tXpWwuZP8PxZGy-x=HqtHMHqw@mail.gmail.com>

On Mon, Sep 24, 2012 at 11:11 AM, Anderson Lizardo
<anderson.lizardo@openbossa.org> wrote:
> Hi Jon,
>
> On Mon, Sep 24, 2012 at 8:55 AM, jonsmirl@gmail.com <jonsmirl@gmail.com> wrote:
>> Ubuntu 12.10 has 4.101 and kernel 3.5. I'm trying to get the sample
>> CC2540 thermometer application from TI working.  The 4.101 package
>> build has --enable-thermometer set.
>
> There is no "--enable-thermometer" since 4.100. Please enable GATT
> with "--enable-gatt". This will enable all supported GATT profiles at
> once.

Ubuntu is building this wrong for the 12.10 release then.  I'm filing
a bug about this, what should the configure option be?

I rebuilt their bluez-4.101 package and it complains about...

configure: WARNING: unrecognized options: --enable-proximity,
--enable-time, --enable-alert, --enable-gatt-example, --enable-tracer,
--enable-thermometer, --enable-capng

configure input from debian/rules...

DEB_CONFIGURE_EXTRA_FLAGS := LDFLAGS=-Wl,--as-needed \
                             --libdir=\$${prefix}/lib/$(DEB_HOST_MULTIARCH) \
                             --enable-static \
                             --disable-hal \
                             --enable-sap \
                             --enable-proximity \
                             --enable-time \
                             --enable-alert \
                             --enable-health \
                             --enable-pnat \
                             --enable-gatt-example \
                             --enable-gstreamer \
                             --enable-alsa \
                             --enable-usb \
                             --enable-tracer \
                             --enable-tools \
                             --enable-bccmd \
                             --enable-pcmcia \
                             --enable-hid2hci \
                             --enable-dfutool \
                             --enable-hidd \
                             --enable-pand \
                             --enable-dund \
                             --enable-cups \
                             --enable-test \
                             --enable-datafiles \
                             --enable-debug \
                             --enable-dbusoob \
                             --enable-wiimote \
                             --enable-thermometer \
                             --enable-capng \
                             --with-systemdunitdir=/lib/systemd/system

>
> Regards,
> --
> Anderson Lizardo
> Instituto Nokia de Tecnologia - INdT
> Manaus - Brazil



-- 
Jon Smirl
jonsmirl@gmail.com

^ permalink raw reply

* [PATCH v1 4/4] audio: Drop audio-specific authorization mechanism
From: Mikel Astiz @ 2012-09-24 15:42 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz
In-Reply-To: <1348501338-29639-1-git-send-email-mikel.astiz.oss@gmail.com>

From: Mikel Astiz <mikel.astiz@bmw-carit.de>

Remove the audio-specific service authorization mechanism in favor of
using the conventional one.

The main difference is that audio profiles will be authorized
independently. Therefore a single connection might result in several
profile authorization requests to the agent (i.e. HFP, A2DP and AVRCP).

This removes any internal policy that would skip the authorization
procedure, making it simpler and more convenient for IVI use-cases.

Agents interested in simulating the old behavior are encouraged to
either set the device as trusted or just reply to the additional
authorization requests automatically without user intervention.
---
 audio/avctp.c   |   29 ++++------
 audio/avdtp.c   |   25 ++++++---
 audio/device.c  |  150 -------------------------------------------------------
 audio/device.h  |   12 +----
 audio/manager.c |   18 ++++---
 5 files changed, 40 insertions(+), 194 deletions(-)

diff --git a/audio/avctp.c b/audio/avctp.c
index 4e0e8dc..40e85ed 100644
--- a/audio/avctp.c
+++ b/audio/avctp.c
@@ -139,6 +139,7 @@ struct avctp {
 
 	GIOChannel *io;
 	guint io_id;
+	int service_auth_id;
 
 	uint16_t mtu;
 
@@ -337,13 +338,9 @@ static void avctp_disconnected(struct avctp *session)
 		g_source_remove(session->io_id);
 		session->io_id = 0;
 
-		if (session->state == AVCTP_STATE_CONNECTING) {
-			struct audio_device *dev;
-
-			dev = manager_get_device(&session->server->src,
-							&session->dst, FALSE);
-			audio_device_cancel_authorization(dev, auth_cb,
-								session);
+		if (session->service_auth_id > 0) {
+			btd_cancel_authorization(session->service_auth_id);
+			session->service_auth_id = 0;
 		}
 	}
 
@@ -386,15 +383,7 @@ static void avctp_set_state(struct avctp *session, avctp_state_t new_state)
 	switch (new_state) {
 	case AVCTP_STATE_DISCONNECTED:
 		DBG("AVCTP Disconnected");
-
 		avctp_disconnected(session);
-
-		if (old_state != AVCTP_STATE_CONNECTED)
-			break;
-
-		if (!audio_device_is_active(dev, NULL))
-			audio_device_set_authorized(dev, FALSE);
-
 		break;
 	case AVCTP_STATE_CONNECTING:
 		DBG("AVCTP Connecting");
@@ -657,6 +646,8 @@ static void auth_cb(DBusError *derr, void *user_data)
 	struct avctp *session = user_data;
 	GError *err = NULL;
 
+	session->service_auth_id = 0;
+
 	if (session->io_id) {
 		g_source_remove(session->io_id);
 		session->io_id = 0;
@@ -736,6 +727,7 @@ static void avctp_confirm_cb(GIOChannel *chan, gpointer data)
 	struct audio_device *dev;
 	char address[18];
 	bdaddr_t src, dst;
+	int auth_id;
 	GError *err = NULL;
 
 	bt_io_get(chan, &err,
@@ -780,12 +772,15 @@ static void avctp_confirm_cb(GIOChannel *chan, gpointer data)
 	avctp_set_state(session, AVCTP_STATE_CONNECTING);
 	session->io = g_io_channel_ref(chan);
 
-	if (audio_device_request_authorization(dev, AVRCP_TARGET_UUID,
-						auth_cb, session) < 0)
+	auth_id = btd_request_authorization(&dev->src, &dev->dst,
+							AVRCP_TARGET_UUID,
+							auth_cb, session);
+	if (auth_id < 0)
 		goto drop;
 
 	session->io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
 							session_cb, session);
+	session->service_auth_id = auth_id;
 	return;
 
 drop:
diff --git a/audio/avdtp.c b/audio/avdtp.c
index d44c504..3137094 100644
--- a/audio/avdtp.c
+++ b/audio/avdtp.c
@@ -400,6 +400,8 @@ struct avdtp {
 	/* True if the entire device is being disconnected */
 	gboolean device_disconnect;
 
+	int service_auth_id;
+
 	GIOChannel *io;
 	guint io_id;
 
@@ -1129,16 +1131,21 @@ static void release_stream(struct avdtp_stream *stream, struct avdtp *session)
 
 static int avdtp_cancel_authorization(struct avdtp *session)
 {
-	struct audio_device *dev;
+	int err;
 
 	if (session->state != AVDTP_SESSION_STATE_CONNECTING)
 		return 0;
 
-	dev = manager_get_device(&session->server->src, &session->dst, FALSE);
-	if (dev == NULL)
-		return -ENODEV;
+	if (!session->service_auth_id)
+		return 0;
 
-	return audio_device_cancel_authorization(dev, auth_cb, session);
+	err = btd_cancel_authorization(session->service_auth_id);
+	if (err < 0)
+		return err;
+
+	session->service_auth_id = 0;
+
+	return 0;
 }
 
 static void connection_lost(struct avdtp *session, int err)
@@ -2507,7 +2514,7 @@ static void avdtp_confirm_cb(GIOChannel *chan, gpointer data)
 	struct audio_device *dev;
 	char address[18];
 	bdaddr_t src, dst;
-	int perr;
+	int auth_id;
 	GError *err = NULL;
 
 	bt_io_get(chan, &err,
@@ -2566,15 +2573,17 @@ static void avdtp_confirm_cb(GIOChannel *chan, gpointer data)
 	session->io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
 					(GIOFunc) session_cb, session);
 
-	perr = audio_device_request_authorization(dev, ADVANCED_AUDIO_UUID,
+	auth_id = btd_request_authorization(&dev->src, &dev->dst,
+							ADVANCED_AUDIO_UUID,
 							auth_cb, session);
-	if (perr < 0) {
+	if (auth_id < 0) {
 		avdtp_set_state(session, AVDTP_SESSION_STATE_DISCONNECTED);
 		avdtp_unref(session);
 		goto drop;
 	}
 
 	dev->auto_connect = auto_connect;
+	session->service_auth_id = auth_id;
 
 	return;
 
diff --git a/audio/device.c b/audio/device.c
index 454bbb9..175e3c0 100644
--- a/audio/device.c
+++ b/audio/device.c
@@ -71,19 +71,12 @@ typedef enum {
 	AUDIO_STATE_CONNECTED,
 } audio_state_t;
 
-struct service_auth {
-	service_auth_cb cb;
-	void *user_data;
-};
-
 struct dev_priv {
 	audio_state_t state;
 
 	headset_state_t hs_state;
 	sink_state_t sink_state;
 	avctp_state_t avctp_state;
-	GSList *auths;
-	int auth_id;
 
 	DBusMessage *conn_req;
 	DBusMessage *dc_req;
@@ -94,8 +87,6 @@ struct dev_priv {
 	guint dc_id;
 
 	gboolean disconnecting;
-	gboolean authorized;
-	guint auth_idle_id;
 };
 
 static unsigned int sink_callback_id = 0;
@@ -110,8 +101,6 @@ static void device_free(struct audio_device *dev)
 	btd_device_unref(dev->btd_dev);
 
 	if (priv) {
-		if (priv->auths)
-			audio_device_cancel_authorization(dev, NULL, NULL);
 		if (priv->control_timer)
 			g_source_remove(priv->control_timer);
 		if (priv->avdtp_timer)
@@ -238,8 +227,6 @@ static void device_set_state(struct audio_device *dev, audio_state_t new_state)
 		return;
 
 	if (new_state == AUDIO_STATE_DISCONNECTED) {
-		priv->authorized = FALSE;
-
 		if (priv->dc_id) {
 			device_remove_disconnect_watch(dev->btd_dev,
 							priv->dc_id);
@@ -732,140 +719,3 @@ void audio_device_unregister(struct audio_device *device)
 
 	device_free(device);
 }
-
-static void auth_cb(DBusError *derr, void *user_data)
-{
-	struct audio_device *dev = user_data;
-	struct dev_priv *priv = dev->priv;
-
-	priv->auth_id = 0;
-
-	if (derr == NULL)
-		priv->authorized = TRUE;
-
-	while (priv->auths) {
-		struct service_auth *auth = priv->auths->data;
-
-		auth->cb(derr, auth->user_data);
-		priv->auths = g_slist_remove(priv->auths, auth);
-		g_free(auth);
-	}
-}
-
-static gboolean auth_idle_cb(gpointer user_data)
-{
-	struct audio_device *dev = user_data;
-	struct dev_priv *priv = dev->priv;
-
-	priv->auth_idle_id = 0;
-
-	auth_cb(NULL, dev);
-
-	return FALSE;
-}
-
-static gboolean audio_device_is_connected(struct audio_device *dev)
-{
-	if (dev->headset) {
-		headset_state_t state = headset_get_state(dev);
-
-		if (state == HEADSET_STATE_CONNECTED ||
-				state == HEADSET_STATE_PLAY_IN_PROGRESS ||
-				state == HEADSET_STATE_PLAYING)
-			return TRUE;
-	}
-
-	if (dev->sink) {
-		sink_state_t state = sink_get_state(dev);
-
-		if (state == SINK_STATE_CONNECTED ||
-				state == SINK_STATE_PLAYING)
-			return TRUE;
-	}
-
-	if (dev->source) {
-		source_state_t state = source_get_state(dev);
-
-		if (state == SOURCE_STATE_CONNECTED ||
-				state == SOURCE_STATE_PLAYING)
-			return TRUE;
-	}
-
-	return FALSE;
-}
-
-int audio_device_request_authorization(struct audio_device *dev,
-					const char *uuid, service_auth_cb cb,
-					void *user_data)
-{
-	struct dev_priv *priv = dev->priv;
-	struct service_auth *auth;
-	int err;
-
-	auth = g_try_new0(struct service_auth, 1);
-	if (!auth)
-		return -ENOMEM;
-
-	auth->cb = cb;
-	auth->user_data = user_data;
-
-	priv->auths = g_slist_append(priv->auths, auth);
-	if (g_slist_length(priv->auths) > 1)
-		return 0;
-
-	if (priv->authorized || audio_device_is_connected(dev)) {
-		priv->auth_idle_id = g_idle_add(auth_idle_cb, dev);
-		return 0;
-	}
-
-	err = btd_request_authorization(&dev->src, &dev->dst, uuid, auth_cb,
-					dev);
-	if (err < 0) {
-		priv->auths = g_slist_remove(priv->auths, auth);
-		g_free(auth);
-	} else
-		priv->auth_id = err;
-
-	return err;
-}
-
-int audio_device_cancel_authorization(struct audio_device *dev,
-					authorization_cb cb, void *user_data)
-{
-	struct dev_priv *priv = dev->priv;
-	GSList *l, *next;
-
-	for (l = priv->auths; l != NULL; l = next) {
-		struct service_auth *auth = l->data;
-
-		next = g_slist_next(l);
-
-		if (cb && auth->cb != cb)
-			continue;
-
-		if (user_data && auth->user_data != user_data)
-			continue;
-
-		priv->auths = g_slist_remove(priv->auths, auth);
-		g_free(auth);
-	}
-
-	if (g_slist_length(priv->auths) == 0) {
-		if (priv->auth_idle_id > 0) {
-			g_source_remove(priv->auth_idle_id);
-			priv->auth_idle_id = 0;
-		} else {
-			btd_cancel_authorization(priv->auth_id);
-			priv->auth_id = 0;
-		}
-	}
-
-	return 0;
-}
-
-void audio_device_set_authorized(struct audio_device *dev, gboolean auth)
-{
-	struct dev_priv *priv = dev->priv;
-
-	priv->authorized = auth;
-}
diff --git a/audio/device.h b/audio/device.h
index f9b868f..548462b 100644
--- a/audio/device.h
+++ b/audio/device.h
@@ -47,6 +47,7 @@ struct audio_device {
 	struct target *target;
 
 	guint hs_preauth_id;
+	int hs_service_auth_id;
 
 	struct dev_priv *priv;
 };
@@ -59,14 +60,3 @@ void audio_device_unregister(struct audio_device *device);
 
 gboolean audio_device_is_active(struct audio_device *dev,
 						const char *interface);
-
-typedef void (*authorization_cb) (DBusError *derr, void *user_data);
-
-int audio_device_cancel_authorization(struct audio_device *dev,
-					authorization_cb cb, void *user_data);
-
-int audio_device_request_authorization(struct audio_device *dev,
-					const char *uuid, authorization_cb cb,
-					void *user_data);
-
-void audio_device_set_authorized(struct audio_device *dev, gboolean auth);
diff --git a/audio/manager.c b/audio/manager.c
index fbfe00f..06a71e3 100644
--- a/audio/manager.c
+++ b/audio/manager.c
@@ -328,7 +328,7 @@ static gboolean hs_preauth_cb(GIOChannel *chan, GIOCondition cond,
 
 	DBG("Headset disconnected during authorization");
 
-	audio_device_cancel_authorization(device, headset_auth_cb, device);
+	btd_cancel_authorization(device->hs_service_auth_id);
 
 	headset_set_state(device, HEADSET_STATE_DISCONNECTED);
 
@@ -343,7 +343,7 @@ static void ag_confirm(GIOChannel *chan, gpointer data)
 	struct audio_device *device;
 	gboolean hfp_active;
 	bdaddr_t src, dst;
-	int perr;
+	int auth_id;
 	GError *err = NULL;
 	uint8_t ch;
 
@@ -398,10 +398,11 @@ static void ag_confirm(GIOChannel *chan, gpointer data)
 
 	headset_set_state(device, HEADSET_STATE_CONNECTING);
 
-	perr = audio_device_request_authorization(device, server_uuid,
-						headset_auth_cb, device);
-	if (perr < 0) {
-		DBG("Authorization denied: %s", strerror(-perr));
+	auth_id = btd_request_authorization(&device->src, &device->dst,
+						server_uuid, headset_auth_cb,
+						device);
+	if (auth_id < 0) {
+		DBG("Authorization denied: %s", strerror(-auth_id));
 		headset_set_state(device, HEADSET_STATE_DISCONNECTED);
 		return;
 	}
@@ -480,8 +481,9 @@ static void hf_io_cb(GIOChannel *chan, gpointer data)
 		goto drop;
 	}
 
-	perr = audio_device_request_authorization(device, server_uuid,
-						gateway_auth_cb, device);
+	perr = btd_request_authorization(&device->src, &device->dst,
+						server_uuid, gateway_auth_cb,
+						device);
 	if (perr < 0) {
 		DBG("Authorization denied: %s", strerror(-perr));
 		gateway_set_state(device, GATEWAY_STATE_DISCONNECTED);
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH v1 3/4] adapter: Queue parallel authorization requests
From: Mikel Astiz @ 2012-09-24 15:42 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz
In-Reply-To: <1348501338-29639-1-git-send-email-mikel.astiz.oss@gmail.com>

From: Mikel Astiz <mikel.astiz@bmw-carit.de>

Remote device could try to connect several profiles in parallel, or
several devices could be trying to connect services. Instead of
returning EBUSY, this patch adds a queue to each adapter such that the
authorization requests will be queued and processed sequentially.
---
 src/adapter.c |  182 ++++++++++++++++++++++++++++++++------------------------
 1 files changed, 104 insertions(+), 78 deletions(-)

diff --git a/src/adapter.c b/src/adapter.c
index dcf58f2..3d14d9e 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -101,8 +101,10 @@ struct service_auth {
 	int id;
 	service_auth_cb cb;
 	void *user_data;
+	const char *uuid;
 	struct btd_device *device;
 	struct btd_adapter *adapter;
+	struct agent *agent;		/* NULL for queued auths */
 };
 
 struct btd_adapter {
@@ -129,8 +131,8 @@ struct btd_adapter {
 	GSList *found_devices;
 	GSList *oor_devices;		/* out of range device list */
 	struct agent *agent;		/* For the new API */
-	guint auth_idle_id;		/* Ongoing authorization (trusted) */
-	struct service_auth *auth;	/* Ongoing authorization */
+	guint auth_idle_id;		/* Pending authorization dequeue */
+	GQueue *auths;			/* Ongoing and pending auths */
 	GSList *connections;		/* Connected devices */
 	GSList *devices;		/* Devices structure pointers */
 	GSList *mode_sessions;		/* Request Mode sessions */
@@ -158,6 +160,8 @@ struct btd_adapter {
 	GSList *profiles;
 };
 
+static gboolean process_auth_queue(gpointer user_data);
+
 static void dev_info_free(void *data)
 {
 	struct remote_dev_info *dev = data;
@@ -951,16 +955,49 @@ static struct btd_device *adapter_create_device(struct btd_adapter *adapter,
 	return device;
 }
 
+static void service_auth_cancel(struct service_auth *auth)
+{
+	DBusError derr;
+
+	dbus_error_init(&derr);
+	dbus_set_error_const(&derr, "org.bluez.Error.Canceled", NULL);
+
+	auth->cb(&derr, auth->user_data);
+
+	dbus_error_free(&derr);
+
+	if (auth->agent != NULL)
+		agent_cancel(auth->agent);
+
+	g_free(auth);
+}
+
 void adapter_remove_device(struct btd_adapter *adapter,
 						struct btd_device *device,
 						gboolean remove_storage)
 {
 	const gchar *dev_path = device_get_path(device);
-	struct agent *agent;
+	GList *l;
 
 	adapter->devices = g_slist_remove(adapter->devices, device);
 	adapter->connections = g_slist_remove(adapter->connections, device);
 
+	l = adapter->auths->head;
+	while (l != NULL) {
+		struct service_auth *auth = l->data;
+		GList *next = g_list_next(l);
+
+		if (auth->device != device) {
+			l = next;
+			continue;
+		}
+
+		g_queue_delete_link(adapter->auths, l);
+		l = next;
+
+		service_auth_cancel(auth);
+	}
+
 	adapter_update_devices(adapter);
 
 	g_dbus_emit_signal(btd_get_dbus_connection(), adapter->path,
@@ -968,14 +1005,6 @@ void adapter_remove_device(struct btd_adapter *adapter,
 			DBUS_TYPE_OBJECT_PATH, &dev_path,
 			DBUS_TYPE_INVALID);
 
-	agent = device_get_agent(device);
-
-	if (agent && adapter->auth && adapter->auth->device == device) {
-		g_free(adapter->auth);
-		adapter->auth = NULL;
-		agent_cancel(agent);
-	}
-
 	device_remove(device, remove_storage);
 }
 
@@ -2414,8 +2443,8 @@ static void adapter_free(gpointer user_data)
 	if (adapter->auth_idle_id)
 		g_source_remove(adapter->auth_idle_id);
 
-	if (adapter->auth)
-		g_free(adapter->auth);
+	g_queue_foreach(adapter->auths, (GFunc) g_free, NULL);
+	g_queue_free(adapter->auths);
 
 	if (adapter->off_timer)
 		off_timer_remove(adapter);
@@ -2509,6 +2538,7 @@ struct btd_adapter *adapter_create(int id)
 	}
 
 	adapter->dev_id = id;
+	adapter->auths = g_queue_new();
 
 	snprintf(path, sizeof(path), "%s/hci%d", base_path, id);
 	adapter->path = g_strdup(path);
@@ -3152,26 +3182,60 @@ static void agent_auth_cb(struct agent *agent, DBusError *derr,
 							void *user_data)
 {
 	struct btd_adapter *adapter = user_data;
-	struct service_auth *auth = adapter->auth;
+	struct service_auth *auth = adapter->auths->head->data;
 
-	adapter->auth = NULL;
+	g_queue_pop_head(adapter->auths);
 
 	auth->cb(derr, auth->user_data);
 
 	g_free(auth);
+
+	adapter->auth_idle_id = g_idle_add(process_auth_queue, adapter);
 }
 
-static gboolean auth_idle_cb(gpointer user_data)
+static gboolean process_auth_queue(gpointer user_data)
 {
 	struct btd_adapter *adapter = user_data;
-	struct service_auth *auth = adapter->auth;
+	DBusError err;
 
-	adapter->auth = NULL;
 	adapter->auth_idle_id = 0;
 
-	auth->cb(NULL, auth->user_data);
+	dbus_error_init(&err);
+	dbus_set_error_const(&err, "org.bluez.Error.Rejected", NULL);
 
-	g_free(auth);
+	while (!g_queue_is_empty(adapter->auths)) {
+		struct service_auth *auth = adapter->auths->head->data;
+		struct btd_device *device = auth->device;
+		const gchar *dev_path;
+
+		if (device_is_trusted(device) == TRUE) {
+			auth->cb(NULL, auth->user_data);
+			goto next;
+		}
+
+		auth->agent = device_get_agent(device);
+		if (auth->agent == NULL) {
+			warn("Can't find device agent");
+			auth->cb(&err, auth->user_data);
+			goto next;
+		}
+
+		dev_path = device_get_path(device);
+
+		if (agent_authorize(auth->agent, dev_path, auth->uuid,
+					agent_auth_cb, adapter, NULL) < 0) {
+			auth->cb(&err, auth->user_data);
+			goto next;
+		}
+
+		break;
+
+next:
+		g_free(auth);
+		g_queue_pop_head(adapter->auths);
+	}
+
+	dbus_error_free(&err);
 
 	return FALSE;
 }
@@ -3182,10 +3246,7 @@ static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
 {
 	struct service_auth *auth;
 	struct btd_device *device;
-	struct agent *agent;
 	char address[18];
-	const gchar *dev_path;
-	int err;
 
 	ba2str(dst, address);
 	device = adapter_find_device(adapter, address);
@@ -3196,42 +3257,27 @@ static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
 	if (!g_slist_find(adapter->connections, device))
 		error("Authorization request for non-connected device!?");
 
-	if (adapter->auth != NULL)
-		return -EBUSY;
-
 	auth = g_try_new0(struct service_auth, 1);
 	if (!auth)
 		return -ENOMEM;
 
 	auth->cb = cb;
 	auth->user_data = user_data;
+	auth->uuid = uuid;
 	auth->device = device;
 	auth->adapter = adapter;
 	auth->id = service_auth_id++;
 
-	if (device_is_trusted(device) == TRUE) {
-		adapter->auth_idle_id = g_idle_add(auth_idle_cb, adapter);
-		goto done;
-	}
+	g_queue_push_tail(adapter->auths, auth);
 
-	agent = device_get_agent(device);
-	if (!agent) {
-		warn("Can't find device agent");
-		g_free(auth);
-		return -EPERM;
-	}
+	if (adapter->auths->length != 1)
+		return auth->id;
 
-	dev_path = device_get_path(device);
+	if (adapter->auth_idle_id != 0)
+		return auth->id;
 
-	err = agent_authorize(agent, dev_path, uuid, agent_auth_cb, adapter,
-									NULL);
-	if (err < 0) {
-		g_free(auth);
-		return err;
-	}
+	adapter->auth_idle_id = g_idle_add(process_auth_queue, adapter);
 
-done:
-	adapter->auth = auth;
 	return auth->id;
 }
 
@@ -3263,18 +3309,20 @@ int btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
 	return -EPERM;
 }
 
-static struct btd_adapter *find_authorization(int auth_id)
+static struct service_auth *find_authorization(int auth_id)
 {
 	GSList *l;
+	GList *l2;
 
 	for (l = manager_get_adapters(); l != NULL; l = g_slist_next(l)) {
 		struct btd_adapter *adapter = l->data;
 
-		if (adapter->auth == NULL)
-			continue;
+		for (l2 = adapter->auths->head; l2 != NULL; l2 = l2->next) {
+			struct service_auth *auth = l2->data;
 
-		if (adapter->auth->id == auth_id)
-			return adapter;
+			if (auth->id == auth_id)
+				return auth;
+		}
 	}
 
 	return NULL;
@@ -3282,39 +3330,17 @@ static struct btd_adapter *find_authorization(int auth_id)
 
 int btd_cancel_authorization(int auth_id)
 {
-	struct btd_adapter *adapter;
-	struct agent *agent;
-	int err;
-
-	adapter = find_authorization(auth_id);
-	if (adapter == NULL)
-		return -EPERM;
-
-	if (adapter->auth_idle_id) {
-		g_source_remove(adapter->auth_idle_id);
-		adapter->auth_idle_id = 0;
-		g_free(adapter->auth);
-		adapter->auth = NULL;
-		return 0;
-	}
-
-	/*
-	 * FIXME: Cancel fails if authorization is requested to adapter's
-	 * agent and in the meanwhile CreatePairedDevice is called.
-	 */
+	struct service_auth *auth;
 
-	agent = device_get_agent(adapter->auth->device);
-	if (!agent)
+	auth = find_authorization(auth_id);
+	if (auth == NULL)
 		return -EPERM;
 
-	err = agent_cancel(agent);
+	g_queue_remove(auth->adapter->auths, auth);
 
-	if (err == 0) {
-		g_free(adapter->auth);
-		adapter->auth = NULL;
-	}
+	service_auth_cancel(auth);
 
-	return err;
+	return 0;
 }
 
 static gchar *adapter_any_path = NULL;
-- 
1.7.7.6


^ permalink raw reply related

* [PATCH v1 2/4] adapter: Use authorization id for cancelling
From: Mikel Astiz @ 2012-09-24 15:42 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Mikel Astiz
In-Reply-To: <1348501338-29639-1-git-send-email-mikel.astiz.oss@gmail.com>

From: Mikel Astiz <mikel.astiz@bmw-carit.de>

Return a request id in btd_request_authorization() in order to be used
when the request needs to be cancelled. This id alone will be enough to
use btd_cancel_authorization().
---
 audio/device.c          |   12 ++++++++--
 plugins/service.c       |   18 ++++++++++------
 profiles/input/server.c |    2 +-
 src/adapter.c           |   51 +++++++++++++++++++++++++++++-----------------
 src/adapter.h           |    2 +-
 5 files changed, 54 insertions(+), 31 deletions(-)

diff --git a/audio/device.c b/audio/device.c
index 99d6512..454bbb9 100644
--- a/audio/device.c
+++ b/audio/device.c
@@ -83,6 +83,7 @@ struct dev_priv {
 	sink_state_t sink_state;
 	avctp_state_t avctp_state;
 	GSList *auths;
+	int auth_id;
 
 	DBusMessage *conn_req;
 	DBusMessage *dc_req;
@@ -737,6 +738,8 @@ static void auth_cb(DBusError *derr, void *user_data)
 	struct audio_device *dev = user_data;
 	struct dev_priv *priv = dev->priv;
 
+	priv->auth_id = 0;
+
 	if (derr == NULL)
 		priv->authorized = TRUE;
 
@@ -820,7 +823,8 @@ int audio_device_request_authorization(struct audio_device *dev,
 	if (err < 0) {
 		priv->auths = g_slist_remove(priv->auths, auth);
 		g_free(auth);
-	}
+	} else
+		priv->auth_id = err;
 
 	return err;
 }
@@ -850,8 +854,10 @@ int audio_device_cancel_authorization(struct audio_device *dev,
 		if (priv->auth_idle_id > 0) {
 			g_source_remove(priv->auth_idle_id);
 			priv->auth_idle_id = 0;
-		} else
-			btd_cancel_authorization(&dev->src, &dev->dst);
+		} else {
+			btd_cancel_authorization(priv->auth_id);
+			priv->auth_id = 0;
+		}
 	}
 
 	return 0;
diff --git a/plugins/service.c b/plugins/service.c
index e02a673..fca559d 100644
--- a/plugins/service.c
+++ b/plugins/service.c
@@ -65,6 +65,7 @@ struct pending_auth {
 	char *sender;
 	bdaddr_t dst;
 	char uuid[MAX_LEN_UUID_STR];
+	int id;
 };
 
 struct service_adapter {
@@ -557,8 +558,9 @@ done:
 	else
 		bacpy(&src, BDADDR_ANY);
 
-	btd_request_authorization(&src, &auth->dst,
-					auth->uuid, auth_cb, serv_adapter);
+	auth->id = btd_request_authorization(&src, &auth->dst,
+							auth->uuid, auth_cb,
+							serv_adapter);
 }
 
 static DBusMessage *request_authorization(DBusConnection *conn,
@@ -633,8 +635,9 @@ static DBusMessage *request_authorization(DBusConnection *conn,
 	else
 		bacpy(&src, BDADDR_ANY);
 
-	if (btd_request_authorization(&src, &auth->dst, auth->uuid, auth_cb,
-							serv_adapter) < 0) {
+	auth->id = btd_request_authorization(&src, &auth->dst, auth->uuid,
+							auth_cb, serv_adapter);
+	if (auth->id < 0) {
 		serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list,
 									auth);
 		g_free(auth);
@@ -664,7 +667,7 @@ static DBusMessage *cancel_authorization(DBusConnection *conn,
 	else
 		bacpy(&src, BDADDR_ANY);
 
-	btd_cancel_authorization(&src, &auth->dst);
+	btd_cancel_authorization(auth->id);
 
 	reply = btd_error_not_authorized(auth->msg);
 	dbus_message_unref(auth->msg);
@@ -683,8 +686,9 @@ static DBusMessage *cancel_authorization(DBusConnection *conn,
 	else
 		bacpy(&src, BDADDR_ANY);
 
-	btd_request_authorization(&src, &auth->dst,
-					auth->uuid, auth_cb, serv_adapter);
+	auth->id = btd_request_authorization(&src, &auth->dst,
+							auth->uuid, auth_cb,
+							serv_adapter);
 
 done:
 	return dbus_message_new_method_return(msg);
diff --git a/profiles/input/server.c b/profiles/input/server.c
index 0464c4a..0385012 100644
--- a/profiles/input/server.c
+++ b/profiles/input/server.c
@@ -175,7 +175,7 @@ static void confirm_event_cb(GIOChannel *chan, gpointer user_data)
 
 	ret = btd_request_authorization(&src, &dst, HID_UUID,
 					auth_callback, server);
-	if (ret == 0)
+	if (ret >= 0)
 		return;
 
 	ba2str(&src, addr);
diff --git a/src/adapter.c b/src/adapter.c
index 366a99f..dcf58f2 100644
--- a/src/adapter.c
+++ b/src/adapter.c
@@ -85,6 +85,7 @@
 #define OFF_TIMER 3
 
 static GSList *adapter_drivers = NULL;
+static int service_auth_id = 0;
 
 struct session_req {
 	struct btd_adapter	*adapter;
@@ -97,6 +98,7 @@ struct session_req {
 };
 
 struct service_auth {
+	int id;
 	service_auth_cb cb;
 	void *user_data;
 	struct btd_device *device;
@@ -3205,6 +3207,7 @@ static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
 	auth->user_data = user_data;
 	auth->device = device;
 	auth->adapter = adapter;
+	auth->id = service_auth_id++;
 
 	if (device_is_trusted(device) == TRUE) {
 		adapter->auth_idle_id = g_idle_add(auth_idle_cb, adapter);
@@ -3229,7 +3232,7 @@ static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
 
 done:
 	adapter->auth = auth;
-	return 0;
+	return auth->id;
 }
 
 int btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
@@ -3248,49 +3251,59 @@ int btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
 	}
 
 	for (l = manager_get_adapters(); l != NULL; l = g_slist_next(l)) {
-		int err;
+		int auth_id;
 
 		adapter = l->data;
 
-		err = adapter_authorize(adapter, dst, uuid, cb, user_data);
-		if (err == 0)
-			return 0;
+		auth_id = adapter_authorize(adapter, dst, uuid, cb, user_data);
+		if (auth_id >= 0)
+			return auth_id;
 	}
 
 	return -EPERM;
 }
 
-int btd_cancel_authorization(const bdaddr_t *src, const bdaddr_t *dst)
+static struct btd_adapter *find_authorization(int auth_id)
 {
-	struct btd_adapter *adapter = manager_find_adapter(src);
-	struct btd_device *device;
+	GSList *l;
+
+	for (l = manager_get_adapters(); l != NULL; l = g_slist_next(l)) {
+		struct btd_adapter *adapter = l->data;
+
+		if (adapter->auth == NULL)
+			continue;
+
+		if (adapter->auth->id == auth_id)
+			return adapter;
+	}
+
+	return NULL;
+}
+
+int btd_cancel_authorization(int auth_id)
+{
+	struct btd_adapter *adapter;
 	struct agent *agent;
-	char address[18];
 	int err;
 
-	if (!adapter)
-		return -EPERM;
-
-	ba2str(dst, address);
-	device = adapter_find_device(adapter, address);
-	if (!device)
+	adapter = find_authorization(auth_id);
+	if (adapter == NULL)
 		return -EPERM;
 
 	if (adapter->auth_idle_id) {
 		g_source_remove(adapter->auth_idle_id);
 		adapter->auth_idle_id = 0;
+		g_free(adapter->auth);
+		adapter->auth = NULL;
 		return 0;
 	}
 
-	if (!adapter->auth || adapter->auth->device != device)
-		return -EPERM;
-
 	/*
 	 * FIXME: Cancel fails if authorization is requested to adapter's
 	 * agent and in the meanwhile CreatePairedDevice is called.
 	 */
 
-	agent = device_get_agent(device);
+	agent = device_get_agent(adapter->auth->device);
 	if (!agent)
 		return -EPERM;
 
diff --git a/src/adapter.h b/src/adapter.h
index eece6f5..2bdd912 100644
--- a/src/adapter.h
+++ b/src/adapter.h
@@ -149,7 +149,7 @@ int btd_register_adapter_driver(struct btd_adapter_driver *driver);
 void btd_unregister_adapter_driver(struct btd_adapter_driver *driver);
 int btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
 		const char *uuid, service_auth_cb cb, void *user_data);
-int btd_cancel_authorization(const bdaddr_t *src, const bdaddr_t *dst);
+int btd_cancel_authorization(int auth_id);
 
 const char *adapter_any_get_path(void);
 
-- 
1.7.7.6


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox