Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH 4/5] Implement server-side ATT handle notification
From: Anderson Lizardo @ 2011-02-21 21:30 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andre Dieb Martins
In-Reply-To: <1298323843-31106-1-git-send-email-anderson.lizardo@openbossa.org>

From: Andre Dieb Martins <andre.dieb@signove.com>

Adds an initial version of ATT handle notification. Notifications are sent to
interested clients (based on the Client Characteristic Configuration) always
when the attribute is updated.

This enables services to call db_attrib_update() and send notifications on their
own terms.
---
 src/attrib-server.c |   29 +++++++++++++++++++++++++++++
 1 files changed, 29 insertions(+), 0 deletions(-)

diff --git a/src/attrib-server.c b/src/attrib-server.c
index 5675a1b..585e1f3 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -961,6 +961,33 @@ static void confirm_event(GIOChannel *io, void *user_data)
 	return;
 }
 
+static void attrib_notify_clients(struct attribute *attr)
+{
+	uint8_t pdu[ATT_MAX_MTU];
+	guint mtu, handle = attr->handle;
+	uint16_t len;
+	GSList *l;
+
+	for (l = clients, mtu = 0, len = 0; l; l = l->next) {
+		struct gatt_channel *channel = l->data;
+
+		mtu = channel->mtu;
+		if (mtu == 0)
+			continue;
+
+		/* Notification */
+		if (g_slist_find_custom(channel->notify,
+					GUINT_TO_POINTER(handle), handle_cmp)) {
+			len = enc_notification(attr, pdu, mtu);
+			if (len == 0)
+				return;
+
+			g_attrib_send(channel->attrib, 0, pdu[0], pdu, len,
+							NULL, NULL, NULL);
+		}
+	}
+}
+
 static gboolean register_core_services(void)
 {
 	uint8_t atval[256];
@@ -1205,6 +1232,8 @@ int attrib_db_update(uint16_t handle, uuid_t *uuid, const uint8_t *value,
 	a->len = len;
 	memcpy(a->data, value, len);
 
+	attrib_notify_clients(a);
+
 	return 0;
 }
 
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 3/5] Check permissions before setting client configs
From: Anderson Lizardo @ 2011-02-21 21:30 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Andre Dieb Martins
In-Reply-To: <1298323843-31106-1-git-send-email-anderson.lizardo@openbossa.org>

From: Andre Dieb Martins <andre.dieb@signove.com>

Only enable notification/indication if the descriptor allows it.
---
 src/attrib-server.c |   11 ++++++++---
 1 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/src/attrib-server.c b/src/attrib-server.c
index be71621..5675a1b 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -197,19 +197,21 @@ static uint8_t client_set_notifications(struct attribute *attr,
 	struct gatt_channel *channel = user_data;
 	struct attribute *a, *last_chr_val = NULL;
 	uint16_t handle, cfg_val;
+	uint8_t perm;
 	uuid_t uuid;
 	GSList *l;
 
 	cfg_val = att_get_u16(attr->data);
 
 	sdp_uuid16_create(&uuid, GATT_CHARAC_UUID);
-	for (l = database, handle = 0; l != NULL; l = l->next) {
+	for (l = database, handle = 0, perm = 0; l != NULL; l = l->next) {
 		a = l->data;
 
 		if (a->handle >= attr->handle)
 			break;
 
 		if (sdp_uuid_cmp(&a->uuid, &uuid) == 0) {
+			perm = att_get_u8(&a->data[0]);
 			handle = att_get_u16(&a->data[1]);
 			continue;
 		}
@@ -221,8 +223,11 @@ static uint8_t client_set_notifications(struct attribute *attr,
 	if (last_chr_val == NULL)
 		return 0;
 
-	/* FIXME: Characteristic properties shall be checked for
-	 * Notification/Indication permissions. */
+	if ((cfg_val & 0x0001) && !(perm & ATT_CHAR_PROPER_NOTIFY))
+		return ATT_ECODE_WRITE_NOT_PERM;
+
+	if ((cfg_val & 0x0002) && !(perm & ATT_CHAR_PROPER_INDICATE))
+		return ATT_ECODE_WRITE_NOT_PERM;
 
 	if (cfg_val & 0x0001)
 		channel->notify = g_slist_append(channel->notify, last_chr_val);
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 2/5] Initial Client Characteristic Configuration implementation
From: Anderson Lizardo @ 2011-02-21 21:30 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1298323843-31106-1-git-send-email-anderson.lizardo@openbossa.org>

This initial version creates a private copy of the Client Configuration
attribute for each client on the first write to that attribute. Further
reads/writes should use the client's private copy.

Two list of attributes are created: one for values to be indicated and
another for values to be notified. The actual notification/indication
sending is implemented in a separate commit.

This initial version also does not check for the characteristic
properties, which is implemented in a separate commit as well.
---
 src/attrib-server.c |  177 ++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 146 insertions(+), 31 deletions(-)

diff --git a/src/attrib-server.c b/src/attrib-server.c
index 28649f1..be71621 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -54,6 +54,7 @@ static GSList *database = NULL;
 struct gatt_channel {
 	bdaddr_t src;
 	bdaddr_t dst;
+	GSList *configs, *notify, *indicate;
 	GAttrib *attrib;
 	guint mtu;
 	guint id;
@@ -143,6 +144,22 @@ static sdp_record_t *server_record_new(uuid_t *uuid, uint16_t start, uint16_t en
 	return record;
 }
 
+static int handle_cmp(gconstpointer a, gconstpointer b)
+{
+	const struct attribute *attrib = a;
+	uint16_t handle = GPOINTER_TO_UINT(b);
+
+	return attrib->handle - handle;
+}
+
+static int attribute_cmp(gconstpointer a1, gconstpointer a2)
+{
+	const struct attribute *attrib1 = a1;
+	const struct attribute *attrib2 = a2;
+
+	return attrib1->handle - attrib2->handle;
+}
+
 static uint8_t att_check_reqs(struct gatt_channel *channel, uint8_t opcode,
 								int reqs)
 {
@@ -174,6 +191,91 @@ static uint8_t att_check_reqs(struct gatt_channel *channel, uint8_t opcode,
 	return 0;
 }
 
+static uint8_t client_set_notifications(struct attribute *attr,
+							gpointer user_data)
+{
+	struct gatt_channel *channel = user_data;
+	struct attribute *a, *last_chr_val = NULL;
+	uint16_t handle, cfg_val;
+	uuid_t uuid;
+	GSList *l;
+
+	cfg_val = att_get_u16(attr->data);
+
+	sdp_uuid16_create(&uuid, GATT_CHARAC_UUID);
+	for (l = database, handle = 0; l != NULL; l = l->next) {
+		a = l->data;
+
+		if (a->handle >= attr->handle)
+			break;
+
+		if (sdp_uuid_cmp(&a->uuid, &uuid) == 0) {
+			handle = att_get_u16(&a->data[1]);
+			continue;
+		}
+
+		if (handle && a->handle == handle)
+			last_chr_val = a;
+	}
+
+	if (last_chr_val == NULL)
+		return 0;
+
+	/* FIXME: Characteristic properties shall be checked for
+	 * Notification/Indication permissions. */
+
+	if (cfg_val & 0x0001)
+		channel->notify = g_slist_append(channel->notify, last_chr_val);
+	else
+		channel->notify = g_slist_remove(channel->notify, last_chr_val);
+
+	if (cfg_val & 0x0002)
+		channel->indicate = g_slist_append(channel->indicate,
+								last_chr_val);
+	else
+		channel->indicate = g_slist_remove(channel->indicate,
+								last_chr_val);
+
+	return 0;
+}
+
+static struct attribute *client_cfg_attribute(struct gatt_channel *channel,
+		struct attribute *orig_attr, const uint8_t *value, int vlen)
+{
+	uuid_t uuid;
+	GSList *l;
+	guint handle = orig_attr->handle;
+
+	sdp_uuid16_create(&uuid, GATT_CLIENT_CHARAC_CFG_UUID);
+	if (sdp_uuid_cmp(&orig_attr->uuid, &uuid) != 0)
+		return NULL;
+
+	/* Value is unchanged, not need to create a private copy yet */
+	if (vlen == orig_attr->len && memcmp(orig_attr->data, value, vlen) == 0)
+		return orig_attr;
+
+	l = g_slist_find_custom(channel->configs, GUINT_TO_POINTER(handle),
+								handle_cmp);
+	if (!l) {
+		struct attribute *a;
+
+		/* Create a private copy of the Client Characteristic
+		 * Configuration attribute */
+		a = g_malloc0(sizeof(struct attribute) + vlen);
+		memcpy(a, orig_attr, sizeof(struct attribute));
+		memcpy(a->data, value, vlen);
+		a->write_cb = client_set_notifications;
+		a->cb_user_data = channel;
+
+		channel->configs = g_slist_insert_sorted(channel->configs, a,
+								attribute_cmp);
+
+		return a;
+	}
+
+	return l->data;
+}
+
 static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
 						uint16_t end, uuid_t *uuid,
 						uint8_t *pdu, int len)
@@ -202,6 +304,8 @@ static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
 
 	last_handle = end;
 	for (l = database, groups = NULL; l; l = l->next) {
+		struct attribute *client_attr;
+
 		a = l->data;
 
 		if (a->handle < start)
@@ -230,6 +334,10 @@ static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
 		status = att_check_reqs(channel, ATT_OP_READ_BY_GROUP_REQ,
 								a->read_reqs);
 
+		client_attr = client_cfg_attribute(channel, a, a->data, a->len);
+		if (client_attr)
+			a = client_attr;
+
 		if (status == 0x00 && a->read_cb)
 			status = a->read_cb(a, a->cb_user_data);
 
@@ -308,6 +416,8 @@ static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start,
 					ATT_ECODE_INVALID_HANDLE, pdu, len);
 
 	for (l = database, length = 0, types = NULL; l; l = l->next) {
+		struct attribute *client_attr;
+
 		a = l->data;
 
 		if (a->handle < start)
@@ -322,6 +432,10 @@ static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start,
 		status = att_check_reqs(channel, ATT_OP_READ_BY_TYPE_REQ,
 								a->read_reqs);
 
+		client_attr = client_cfg_attribute(channel, a, a->data, a->len);
+		if (client_attr)
+			a = client_attr;
+
 		if (status == 0x00 && a->read_cb)
 			status = a->read_cb(a, a->cb_user_data);
 
@@ -506,22 +620,6 @@ static int find_by_type(uint16_t start, uint16_t end, uuid_t *uuid,
 	return len;
 }
 
-static int handle_cmp(gconstpointer a, gconstpointer b)
-{
-	const struct attribute *attrib = a;
-	uint16_t handle = GPOINTER_TO_UINT(b);
-
-	return attrib->handle - handle;
-}
-
-static int attribute_cmp(gconstpointer a1, gconstpointer a2)
-{
-	const struct attribute *attrib1 = a1;
-	const struct attribute *attrib2 = a2;
-
-	return attrib1->handle - attrib2->handle;
-}
-
 static struct attribute *find_primary_range(uint16_t start, uint16_t *end)
 {
 	struct attribute *attrib;
@@ -559,7 +657,7 @@ static struct attribute *find_primary_range(uint16_t start, uint16_t *end)
 static uint16_t read_value(struct gatt_channel *channel, uint16_t handle,
 							uint8_t *pdu, int len)
 {
-	struct attribute *a;
+	struct attribute *a, *client_attr;
 	uint8_t status;
 	GSList *l;
 	guint h = handle;
@@ -573,6 +671,10 @@ static uint16_t read_value(struct gatt_channel *channel, uint16_t handle,
 
 	status = att_check_reqs(channel, ATT_OP_READ_REQ, a->read_reqs);
 
+	client_attr = client_cfg_attribute(channel, a, a->data, a->len);
+	if (client_attr)
+		a = client_attr;
+
 	if (status == 0x00 && a->read_cb)
 		status = a->read_cb(a, a->cb_user_data);
 
@@ -586,7 +688,7 @@ static uint16_t read_value(struct gatt_channel *channel, uint16_t handle,
 static uint16_t read_blob(struct gatt_channel *channel, uint16_t handle,
 					uint16_t offset, uint8_t *pdu, int len)
 {
-	struct attribute *a;
+	struct attribute *a, *client_attr;
 	uint8_t status;
 	GSList *l;
 	guint h = handle;
@@ -604,6 +706,10 @@ static uint16_t read_blob(struct gatt_channel *channel, uint16_t handle,
 
 	status = att_check_reqs(channel, ATT_OP_READ_BLOB_REQ, a->read_reqs);
 
+	client_attr = client_cfg_attribute(channel, a, a->data, a->len);
+	if (client_attr)
+		a = client_attr;
+
 	if (status == 0x00 && a->read_cb)
 		status = a->read_cb(a, a->cb_user_data);
 
@@ -618,11 +724,10 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
 						const uint8_t *value, int vlen,
 						uint8_t *pdu, int len)
 {
-	struct attribute *a;
+	struct attribute *a, *client_attr;
 	uint8_t status;
 	GSList *l;
 	guint h = handle;
-	uuid_t uuid;
 
 	l = g_slist_find_custom(database, GUINT_TO_POINTER(h), handle_cmp);
 	if (!l)
@@ -636,8 +741,11 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
 		return enc_error_resp(ATT_OP_WRITE_REQ, handle, status, pdu,
 									len);
 
-	memcpy(&uuid, &a->uuid, sizeof(uuid_t));
-	attrib_db_update(handle, &uuid, value, vlen);
+	client_attr = client_cfg_attribute(channel, a, value, vlen);
+	if (client_attr)
+		a = client_attr;
+	else
+		attrib_db_update(a->handle, &a->uuid, value, vlen);
 
 	if (a->write_cb) {
 		status = a->write_cb(a, a->cb_user_data);
@@ -646,6 +754,10 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
 								pdu, len);
 	}
 
+	DBG("Notifications: %d, indications: %d",
+					g_slist_length(channel->notify),
+					g_slist_length(channel->indicate));
+
 	return enc_write_resp(pdu, len);
 }
 
@@ -664,6 +776,11 @@ static void channel_disconnect(void *user_data)
 	g_attrib_unref(channel->attrib);
 	clients = g_slist_remove(clients, channel);
 
+	g_slist_free(channel->notify);
+	g_slist_free(channel->indicate);
+	g_slist_foreach(channel->configs, (GFunc) g_free, NULL);
+	g_slist_free(channel->configs);
+
 	g_free(channel);
 }
 
@@ -976,6 +1093,11 @@ void attrib_server_exit(void)
 	for (l = clients; l; l = l->next) {
 		struct gatt_channel *channel = l->data;
 
+		g_slist_free(channel->notify);
+		g_slist_free(channel->indicate);
+		g_slist_foreach(channel->configs, (GFunc) g_free, NULL);
+		g_slist_free(channel->configs);
+
 		g_attrib_unref(channel->attrib);
 		g_free(channel);
 	}
@@ -1073,18 +1195,11 @@ int attrib_db_update(uint16_t handle, uuid_t *uuid, const uint8_t *value,
 
 	l->data = a;
 	a->handle = handle;
-	memcpy(&a->uuid, uuid, sizeof(uuid_t));
+	if (uuid != &a->uuid)
+		memcpy(&a->uuid, uuid, sizeof(uuid_t));
 	a->len = len;
 	memcpy(a->data, value, len);
 
-	/*
-	 * <<Client/Server Characteristic Configuration>> descriptors are
-	 * not supported yet. If a given attribute changes, the attribute
-	 * server shall report the new values using the mechanism selected
-	 * by the client. Notification/Indication shall not be automatically
-	 * sent if the client didn't request them.
-	 */
-
 	return 0;
 }
 
-- 
1.7.0.4


^ permalink raw reply related

* [PATCH 1/5] Add read/write callbacks to attribute server
From: Anderson Lizardo @ 2011-02-21 21:30 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Lizardo

These callbacks will allow profiles to act before an attribute is read
and after it is written, to e.g. update the attribute value to/from an
external source.

Note that by the time the callback is called, the necessary security
checks (attribute permissions, authentication and encryption) were
already performed by the core attribute server.

The callback can optionally return an ATT status code, which will be
sent to the client using an Error Response PDU.
---
 attrib/att.h        |    7 +++++++
 src/attrib-server.c |   29 ++++++++++++++++++++++++++---
 src/attrib-server.h |    4 ++--
 3 files changed, 35 insertions(+), 5 deletions(-)

diff --git a/attrib/att.h b/attrib/att.h
index 7d9afeb..05ae606 100644
--- a/attrib/att.h
+++ b/attrib/att.h
@@ -118,11 +118,18 @@ enum {
 	ATT_NOT_PERMITTED,	/* Operation not permitted */
 };
 
+struct attribute;
+
+typedef uint8_t (*att_cb_t)(struct attribute *, gpointer);
+
 struct attribute {
 	uint16_t handle;
 	uuid_t uuid;
 	int read_reqs;
 	int write_reqs;
+	att_cb_t read_cb;
+	att_cb_t write_cb;
+	gpointer cb_user_data;
 	int len;
 	uint8_t data[0];
 };
diff --git a/src/attrib-server.c b/src/attrib-server.c
index 7ec0f56..28649f1 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -229,6 +229,10 @@ static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
 
 		status = att_check_reqs(channel, ATT_OP_READ_BY_GROUP_REQ,
 								a->read_reqs);
+
+		if (status == 0x00 && a->read_cb)
+			status = a->read_cb(a, a->cb_user_data);
+
 		if (status) {
 			g_slist_foreach(groups, (GFunc) g_free, NULL);
 			g_slist_free(groups);
@@ -317,6 +321,10 @@ static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start,
 
 		status = att_check_reqs(channel, ATT_OP_READ_BY_TYPE_REQ,
 								a->read_reqs);
+
+		if (status == 0x00 && a->read_cb)
+			status = a->read_cb(a, a->cb_user_data);
+
 		if (status) {
 			g_slist_free(types);
 			return enc_error_resp(ATT_OP_READ_BY_TYPE_REQ,
@@ -564,6 +572,10 @@ static uint16_t read_value(struct gatt_channel *channel, uint16_t handle,
 	a = l->data;
 
 	status = att_check_reqs(channel, ATT_OP_READ_REQ, a->read_reqs);
+
+	if (status == 0x00 && a->read_cb)
+		status = a->read_cb(a, a->cb_user_data);
+
 	if (status)
 		return enc_error_resp(ATT_OP_READ_REQ, handle, status, pdu,
 									len);
@@ -591,6 +603,10 @@ static uint16_t read_blob(struct gatt_channel *channel, uint16_t handle,
 					ATT_ECODE_INVALID_OFFSET, pdu, len);
 
 	status = att_check_reqs(channel, ATT_OP_READ_BLOB_REQ, a->read_reqs);
+
+	if (status == 0x00 && a->read_cb)
+		status = a->read_cb(a, a->cb_user_data);
+
 	if (status)
 		return enc_error_resp(ATT_OP_READ_BLOB_REQ, handle, status,
 								pdu, len);
@@ -623,6 +639,13 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
 	memcpy(&uuid, &a->uuid, sizeof(uuid_t));
 	attrib_db_update(handle, &uuid, value, vlen);
 
+	if (a->write_cb) {
+		status = a->write_cb(a, a->cb_user_data);
+		if (status)
+			return enc_error_resp(ATT_OP_WRITE_REQ, handle, status,
+								pdu, len);
+	}
+
 	return enc_write_resp(pdu, len);
 }
 
@@ -1013,8 +1036,8 @@ void attrib_free_sdp(uint32_t sdp_handle)
 	remove_record_from_server(sdp_handle);
 }
 
-int attrib_db_add(uint16_t handle, uuid_t *uuid, int read_reqs, int write_reqs,
-						const uint8_t *value, int len)
+struct attribute *attrib_db_add(uint16_t handle, uuid_t *uuid, int read_reqs,
+				int write_reqs, const uint8_t *value, int len)
 {
 	struct attribute *a;
 
@@ -1030,7 +1053,7 @@ int attrib_db_add(uint16_t handle, uuid_t *uuid, int read_reqs, int write_reqs,
 
 	database = g_slist_insert_sorted(database, a, attribute_cmp);
 
-	return 0;
+	return a;
 }
 
 int attrib_db_update(uint16_t handle, uuid_t *uuid, const uint8_t *value,
diff --git a/src/attrib-server.h b/src/attrib-server.h
index ecd695c..85f3bdb 100644
--- a/src/attrib-server.h
+++ b/src/attrib-server.h
@@ -25,8 +25,8 @@
 int attrib_server_init(void);
 void attrib_server_exit(void);
 
-int attrib_db_add(uint16_t handle, uuid_t *uuid, int read_reqs, int write_reqs,
-						const uint8_t *value, int len);
+struct attribute *attrib_db_add(uint16_t handle, uuid_t *uuid, int read_reqs,
+				int write_reqs, const uint8_t *value, int len);
 int attrib_db_update(uint16_t handle, uuid_t *uuid, const uint8_t *value,
 								int len);
 int attrib_db_del(uint16_t handle);
-- 
1.7.0.4


^ permalink raw reply related

* Re: [PATCH 2/3] Add generic descriptor support to Attribute API document
From: Elvis Pfützenreuter @ 2011-02-21 21:24 UTC (permalink / raw)
  To: Claudio Takahasi; +Cc: linux-bluetooth
In-Reply-To: <AANLkTimDdtdSUFqoVyGUy-UC_r3y_pu9N5dO9CBD9dfi@mail.gmail.com>


On 21 Feb 2011, at 18:14 , Claudio Takahasi wrote:

> Hi Elvis,
> 
> On Mon, Feb 21, 2011 at 7:39 PM, Elvis Pfützenreuter <epx@signove.com> wrote:
>> 
>> On 21 Feb 2011, at 16:14 , Claudio Takahasi wrote:
>> 
>>> Hi,
>>> 
>>> 
>>> On Wed, Feb 16, 2011 at 6:13 PM, Elvis Pfützenreuter <epx@signove.com> wrote:
>>>> This patch proposes extensions to Attribute API, giving access to all
>>>> characteristic descriptors (beyond 'Description' and 'Format').
>>>> ---
>>>>  doc/attribute-api.txt |   28 ++++++++++++++++++++++++++++
>>>>  1 files changed, 28 insertions(+), 0 deletions(-)
>>>> 
>>>> diff --git a/doc/attribute-api.txt b/doc/attribute-api.txt
>>>> index 23808e6..5ee189e 100644
>>>> --- a/doc/attribute-api.txt
>>>> +++ b/doc/attribute-api.txt
>>>> @@ -104,6 +104,14 @@ Methods            dict GetProperties()
>>>> 
>>>>                        Possible Errors: org.bluez.Error.InvalidArguments
>>>> 
>>>> +               void SetDescriptorValue(object descriptor, array{byte} value)
>>>> +
>>>> +                       Sets descriptor value, provided that it is writable.
>>>> +
>>>> +                       Possible Errors: org.bluez.Error.InvalidArguments
>>>> +                                       org.bluez.Error.NotAuthorized
>>>> +
>>>> +
>>>>  Properties     string UUID [readonly]
>>>> 
>>>>                        UUID128 of this characteristic.
>>>> @@ -143,6 +151,26 @@ Properties         string UUID [readonly]
>>>>                        Friendly representation of the Characteristic Value
>>>>                        based on the format attribute.
>>>> 
>>>> +               dict Descriptors [readonly]
>>>> +
>>>> +                       List of descriptors for this characteristic.
>>>> +
>>>> +                       This list contains only the descriptors not already
>>>> +                       covered by other properties (v.g. Description, Format).
>>>> +
>>>> +                       Each descriptor is mapped to an unique object path,
>>>> +                       which is the key for the dict.
>>>> +
>>>> +                       Each dict value is, in turn, a dict with at least
>>>> +                       the following keys:
>>>> +
>>>> +                       {
>>>> +                               "UUID": string (descriptor UUID - mandatory),
>>>> +                               "Value": array of bytes (raw descriptor value -
>>>> +                                        optional, shows up when value can be
>>>> +                                        fetched)
>>>> +                       }
>>>> +
>>>> 
>>>>  Characteristic Watcher hierarchy
>>>>  ===============================
>>>> --
>>>> 1.7.1
>>>> 
>>>> --
>>>> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
>>>> the body of a message to majordomo@vger.kernel.org
>>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>>> 
>>> 
>>> In my opinion is not a good approach to allow applications(D-Bus
>>> clients) to change a behavior/value of the same characteristic
>>> descriptor. bluetoothd could manage automatically writing the client
>>> characteristic configuration and server characteristic configuration
>>> based on the registered watchers and supported client profiles.
>> 
>> I'm not sure I follow, but let's break it down:
>> 
>> 1) Note that this API is not just for client (and server) characteristic configuration descriptors. It is good for any kind of descriptor (like Valid Range, that client is supposed to be able to read, and set the related characteristic within its limits).
> 
> The API already has SetProperty and GetProperties that could expose
> the descriptors that you need.

Yes, but note that biggest part of proposal is exactly to add one more
item to be returned by GetProperties() :)

If you mean that a separate method to update descriptors is not ok, and
using SetProperty() to do that is the way, I understand.

> 
>> 
>> 2) Updating automatically CCC/SCC descriptors based on Watchers sounds nice. We just need to add some kind of flag to agent registering in order to tell if we want notification or indication.
> 
> This is our initial ideia, but it is not written in the stone yet. We
> need to investigate a little bit more and see which/how the Profiles
> are using these characteristics descriptors.

Ok, but I think it is near perfect.

>> 
>> 3) In terms of client profiles, the GATT API looks generic to me, not profile-specific. As there is a way to access characteristic values in a generic way, so there is a need to do the same for descriptors.
> 
> For some descriptors I agree that we need to expose through the D-Bus
> API. However for others such as CCC and SCC I don't think that we need
> to allow the apps to change it. If necessary we will also have a
> plugin or a service specific interface, one example is Proximity
> Profile. Do you have a good use case/example in health profiles using
> CCC and SCC?

Yes, I will send you the details.

^ permalink raw reply

* Re: [PATCH 2/3] Add generic descriptor support to Attribute API document
From: Claudio Takahasi @ 2011-02-21 21:14 UTC (permalink / raw)
  To: Elvis Pfützenreuter; +Cc: linux-bluetooth
In-Reply-To: <F8CC68A2-1854-466D-AC84-37B50D05F847@signove.com>

Hi Elvis,

On Mon, Feb 21, 2011 at 7:39 PM, Elvis Pfützenreuter <epx@signove.com> wrote:
>
> On 21 Feb 2011, at 16:14 , Claudio Takahasi wrote:
>
>> Hi,
>>
>>
>> On Wed, Feb 16, 2011 at 6:13 PM, Elvis Pfützenreuter <epx@signove.com> wrote:
>>> This patch proposes extensions to Attribute API, giving access to all
>>> characteristic descriptors (beyond 'Description' and 'Format').
>>> ---
>>>  doc/attribute-api.txt |   28 ++++++++++++++++++++++++++++
>>>  1 files changed, 28 insertions(+), 0 deletions(-)
>>>
>>> diff --git a/doc/attribute-api.txt b/doc/attribute-api.txt
>>> index 23808e6..5ee189e 100644
>>> --- a/doc/attribute-api.txt
>>> +++ b/doc/attribute-api.txt
>>> @@ -104,6 +104,14 @@ Methods            dict GetProperties()
>>>
>>>                        Possible Errors: org.bluez.Error.InvalidArguments
>>>
>>> +               void SetDescriptorValue(object descriptor, array{byte} value)
>>> +
>>> +                       Sets descriptor value, provided that it is writable.
>>> +
>>> +                       Possible Errors: org.bluez.Error.InvalidArguments
>>> +                                       org.bluez.Error.NotAuthorized
>>> +
>>> +
>>>  Properties     string UUID [readonly]
>>>
>>>                        UUID128 of this characteristic.
>>> @@ -143,6 +151,26 @@ Properties         string UUID [readonly]
>>>                        Friendly representation of the Characteristic Value
>>>                        based on the format attribute.
>>>
>>> +               dict Descriptors [readonly]
>>> +
>>> +                       List of descriptors for this characteristic.
>>> +
>>> +                       This list contains only the descriptors not already
>>> +                       covered by other properties (v.g. Description, Format).
>>> +
>>> +                       Each descriptor is mapped to an unique object path,
>>> +                       which is the key for the dict.
>>> +
>>> +                       Each dict value is, in turn, a dict with at least
>>> +                       the following keys:
>>> +
>>> +                       {
>>> +                               "UUID": string (descriptor UUID - mandatory),
>>> +                               "Value": array of bytes (raw descriptor value -
>>> +                                        optional, shows up when value can be
>>> +                                        fetched)
>>> +                       }
>>> +
>>>
>>>  Characteristic Watcher hierarchy
>>>  ===============================
>>> --
>>> 1.7.1
>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
>>> the body of a message to majordomo@vger.kernel.org
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>>
>>
>> In my opinion is not a good approach to allow applications(D-Bus
>> clients) to change a behavior/value of the same characteristic
>> descriptor. bluetoothd could manage automatically writing the client
>> characteristic configuration and server characteristic configuration
>> based on the registered watchers and supported client profiles.
>
> I'm not sure I follow, but let's break it down:
>
> 1) Note that this API is not just for client (and server) characteristic configuration descriptors. It is good for any kind of descriptor (like Valid Range, that client is supposed to be able to read, and set the related characteristic within its limits).

The API already has SetProperty and GetProperties that could expose
the descriptors that you need.

>
> 2) Updating automatically CCC/SCC descriptors based on Watchers sounds nice. We just need to add some kind of flag to agent registering in order to tell if we want notification or indication.

This is our initial ideia, but it is not written in the stone yet. We
need to investigate a little bit more and see which/how the Profiles
are using these characteristics descriptors.

>
> 3) In terms of client profiles, the GATT API looks generic to me, not profile-specific. As there is a way to access characteristic values in a generic way, so there is a need to do the same for descriptors.

For some descriptors I agree that we need to expose through the D-Bus
API. However for others such as CCC and SCC I don't think that we need
to allow the apps to change it. If necessary we will also have a
plugin or a service specific interface, one example is Proximity
Profile. Do you have a good use case/example in health profiles using
CCC and SCC?

BR,
Claudio.

^ permalink raw reply

* Re: [PATCH 2/2] bt hidp: send Output reports using SET_REPORT on the Control channel
From: Gustavo F. Padovan @ 2011-02-21 21:09 UTC (permalink / raw)
  To: Jiri Kosina
  Cc: Alan Ott, Antonio Ospite, linux-input, linux-bluetooth,
	Marcel Holtmann, Bastien Nocera, Jim Paris, pascal@pabr.org
In-Reply-To: <alpine.LNX.2.00.1102211349550.2160@pobox.suse.cz>

Hi Jiri,

* Jiri Kosina <jkosina@suse.cz> [2011-02-21 13:50:40 +0100]:

> On Sun, 20 Feb 2011, Alan Ott wrote:
> 
> > On 02/20/2011 12:26 PM, Antonio Ospite wrote:
> > > The current implementation of hidp_output_raw_report() relies only on
> > > the Control channel even for Output reports, and the BT HID
> > > specification [1] does not mention using the DATA message for Output
> > > reports on the Control channel (see section 7.9.1 and also Figure 11:
> > > SET_ Flow Chart), so let us just use SET_REPORT.
> > > 
> > > This also fixes sending Output reports to some devices (like Sony
> > > Sixaxis) which are not able to handle DATA messages on the Control
> > > channel.
> > > 
> > > Ideally hidp_output_raw_report() could be improved to use this scheme:
> > >    Feature Report -- SET_REPORT on the Control channel
> > >    Output Report  -- DATA on the Interrupt channel
> > > for more efficiency, but as said above, right now only the Control
> > > channel is used.
> > > 
> > > [1] http://www.bluetooth.com/Specification%20Documents/HID_SPEC_V10.pdf
> > > 
> > >   	case HID_OUTPUT_REPORT:
> > > -		report_type = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
> > > +		report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_OUPUT;
> > >    
> > 
> > I think this is right. Section 7.4[.0] says that SET_ and GET_ requests return
> > with HANDSHAKE. Section 7.4.9 says that DATA does _not_ return a HANDSHAKE. My
> > patch to hidp_output_raw_report() relies on getting a HANDSHAKE back, so it
> > wouldn't have worked with BT devices that take output reports. Since I don't
> > have any that do, I couldn't test it. (And it was like that when I got here :)
> > )
> > 
> > For the whole set:
> > Acked-by: Alan Ott <alan@signal11.us>
> 
> Agreed.
> 
> As an author of the original code, I agree with the change. But as it is 
> in net/bluetooth, I'd at least have Acked-by from some of the Bluetooth 
> folks before I take it through my tree.
> 
> Marcel? Gustavo?

Acked-by: Gustavo F. Padovan <padovan@profusion.mobi>

-- 
Gustavo F. Padovan
http://profusion.mobi

^ permalink raw reply

* Re: [PATCH 2/2] Bluetooth: Use ERR_PTR as return error from hci_connect
From: Gustavo F. Padovan @ 2011-02-21 21:04 UTC (permalink / raw)
  To: anderson.briglia; +Cc: linux-bluetooth, Ville Tervo
In-Reply-To: <4d62aa7a.47f3d80a.5ea1.ffffd992@mx.google.com>

* anderson.briglia@openbossa.org <anderson.briglia@openbossa.org> [2011-02-21 15:09:24 -0300]:

> From: Ville Tervo <ville.tervo@nokia.com>
> 
> Use ERR_PRT mechanism to return error from hci_connect.

Btw, Johan added a new call to hci_connect, so be sure to add the ERR_PTR
stuff there too.

-- 
Gustavo F. Padovan
http://profusion.mobi

^ permalink raw reply

* Re: [PATCH 1/2] Bluetooth: Fix LE conn creation
From: Gustavo F. Padovan @ 2011-02-21 21:00 UTC (permalink / raw)
  To: anderson.briglia; +Cc: linux-bluetooth, Ville Tervo
In-Reply-To: <4d62aa6e.47f3d80a.5ea1.ffffd98d@mx.google.com>

Hi Briglia,

* anderson.briglia@openbossa.org <anderson.briglia@openbossa.org> [2011-02-21 15:09:23 -0300]:

> From: Anderson Briglia <anderson.briglia@openbossa.org>
> 
> This patch prevents a crash when remote host tries to create a LE
> link which already exists. i.e.: call l2test twice passing the
> same parameters.
> 
> Signed-off-by: Anderson Briglia <anderson.briglia@openbossa.org>
> Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
> ---
>  net/bluetooth/hci_conn.c |    5 +++--
>  1 files changed, 3 insertions(+), 2 deletions(-)

Applied, thanks.

-- 
Gustavo F. Padovan
http://profusion.mobi

^ permalink raw reply

* Re: [PATCH 2/2] Bluetooth: Use ERR_PTR as return error from hci_connect
From: Gustavo F. Padovan @ 2011-02-21 20:59 UTC (permalink / raw)
  To: anderson.briglia; +Cc: linux-bluetooth, Ville Tervo
In-Reply-To: <4d62aa7a.47f3d80a.5ea1.ffffd992@mx.google.com>

Hi,

* anderson.briglia@openbossa.org <anderson.briglia@openbossa.org> [2011-02-21 15:09:24 -0300]:

> From: Ville Tervo <ville.tervo@nokia.com>
> 
> Use ERR_PRT mechanism to return error from hci_connect.
> 
> Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
> Signed-off-by: Anderson Briglia <anderson.briglia@openbossa.org>
> ---
>  net/bluetooth/hci_conn.c   |    8 ++++----
>  net/bluetooth/l2cap_core.c |   10 ++++------
>  net/bluetooth/sco.c        |    6 +++---
>  3 files changed, 11 insertions(+), 13 deletions(-)
> 
> diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
> index d401775..06af539 100644
> --- a/net/bluetooth/hci_conn.c
> +++ b/net/bluetooth/hci_conn.c
> @@ -430,10 +430,10 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
>  	if (type == LE_LINK) {
>  		le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
>  		if (le)
> -			return NULL;
> +			return ERR_PTR(-EBUSY);
>  		le = hci_conn_add(hdev, LE_LINK, dst);
>  		if (!le)
> -			return NULL;
> +			return ERR_PTR(-ENOMEM);
>  		if (le->state == BT_OPEN)
>  			hci_le_connect(le);
>  
> @@ -445,8 +445,8 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
>  	acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
>  	if (!acl) {
>  		acl = hci_conn_add(hdev, ACL_LINK, dst);
> -		if (!acl)
> -			return NULL;
> +		if (IS_ERR(acl))
> +			return acl;

hci_conn_add() doesn't use the ERR_PTR magic.


-- 
Gustavo F. Padovan
http://profusion.mobi

^ permalink raw reply

* Re: [PATCH 0/8] More Management interface patches
From: Gustavo F. Padovan @ 2011-02-21 20:53 UTC (permalink / raw)
  To: johan.hedberg; +Cc: linux-bluetooth
In-Reply-To: <1298127962-18576-1-git-send-email-johan.hedberg@gmail.com>

Hi Johan,

* johan.hedberg@gmail.com <johan.hedberg@gmail.com> [2011-02-19 12:05:54 -0300]:

> Hi,
> 
> Here's a new set of patches for the Management interface. Combined with
> the latest user space git these patches enable both legacy and Secure
> Simple Pairing procedures. After these the only big missing feature in
> the management interface is device discovery which I'm just about to
> start working on.

All 8 patches are in my tree now, Thanks.

-- 
Gustavo F. Padovan
http://profusion.mobi

^ permalink raw reply

* Re: pull request: bluetooth-next-2.6 2011-02-17
From: John W. Linville @ 2011-02-21 20:48 UTC (permalink / raw)
  To: linux-wireless, linux-bluetooth
In-Reply-To: <20110221201645.GC2965@joana>

On Mon, Feb 21, 2011 at 05:16:45PM -0300, Gustavo F. Padovan wrote:
> Hi John,
> 
> * Gustavo F. Padovan <padovan@profusion.mobi> [2011-02-18 10:59:56 -0300]:
> 
> > Hi John,
> > 
> > Busy times at the Bluetooth subsystem. Here is another big set of patches
> > intended to 2.6.39. ;)
> > 
> > One of the changes is the end of the L2CAP and SCO kernel modules. We just
> > merged them into the main bluetooth.ko module. It really never made sense to
> > have them separated. 
> > 
> > Then we have firmware support to a new Atheros device by Bala Shanmugam.
> > The First set of patches for Bluetooth Low Energy(LE) support, by Ville Tervo.
> > Low Energy is a new Bluetooth radio that will bring many new use cases to the
> > Bluetooth technology. Finally, LE connection update command support by Claudio
> > Takahasi. The rest is just bugs fixes and cleanups. 
> > 
> > Please pull, or let me know any doubts you have. Thanks.
> 
> I saw you had a merge conflict between bluetooth-2.6 and bluetooth-next-2.6
> and I want to apologize for the extra work I caused to you. It was all my
> fault by not testing the merge of the my own trees. It won't happen again. ;)

Cool, thanks!  It wasn't a big deal, but better if I can avoid it! :-)

John
-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* Re: pull request: bluetooth-next-2.6 2011-02-17
From: Gustavo F. Padovan @ 2011-02-21 20:16 UTC (permalink / raw)
  To: linville; +Cc: linux-wireless, linux-bluetooth
In-Reply-To: <20110218135956.GA2256@joana>

Hi John,

* Gustavo F. Padovan <padovan@profusion.mobi> [2011-02-18 10:59:56 -0300]:

> Hi John,
> 
> Busy times at the Bluetooth subsystem. Here is another big set of patches
> intended to 2.6.39. ;)
> 
> One of the changes is the end of the L2CAP and SCO kernel modules. We just
> merged them into the main bluetooth.ko module. It really never made sense to
> have them separated. 
> 
> Then we have firmware support to a new Atheros device by Bala Shanmugam.
> The First set of patches for Bluetooth Low Energy(LE) support, by Ville Tervo.
> Low Energy is a new Bluetooth radio that will bring many new use cases to the
> Bluetooth technology. Finally, LE connection update command support by Claudio
> Takahasi. The rest is just bugs fixes and cleanups. 
> 
> Please pull, or let me know any doubts you have. Thanks.

I saw you had a merge conflict between bluetooth-2.6 and bluetooth-next-2.6
and I want to apologize for the extra work I caused to you. It was all my
fault by not testing the merge of the my own trees. It won't happen again. ;)

Regards,

-- 
Gustavo F. Padovan
http://profusion.mobi

^ permalink raw reply

* Re: [PATCH 2/3] Add generic descriptor support to Attribute API document
From: Elvis Pfützenreuter @ 2011-02-21 19:39 UTC (permalink / raw)
  To: Claudio Takahasi; +Cc: linux-bluetooth
In-Reply-To: <AANLkTi=X=E_VA7p0J6aj+kcJYPA7mUJiqjs+xySKJ6EE@mail.gmail.com>


On 21 Feb 2011, at 16:14 , Claudio Takahasi wrote:

> Hi,
> 
> 
> On Wed, Feb 16, 2011 at 6:13 PM, Elvis Pfützenreuter <epx@signove.com> wrote:
>> This patch proposes extensions to Attribute API, giving access to all
>> characteristic descriptors (beyond 'Description' and 'Format').
>> ---
>>  doc/attribute-api.txt |   28 ++++++++++++++++++++++++++++
>>  1 files changed, 28 insertions(+), 0 deletions(-)
>> 
>> diff --git a/doc/attribute-api.txt b/doc/attribute-api.txt
>> index 23808e6..5ee189e 100644
>> --- a/doc/attribute-api.txt
>> +++ b/doc/attribute-api.txt
>> @@ -104,6 +104,14 @@ Methods            dict GetProperties()
>> 
>>                        Possible Errors: org.bluez.Error.InvalidArguments
>> 
>> +               void SetDescriptorValue(object descriptor, array{byte} value)
>> +
>> +                       Sets descriptor value, provided that it is writable.
>> +
>> +                       Possible Errors: org.bluez.Error.InvalidArguments
>> +                                       org.bluez.Error.NotAuthorized
>> +
>> +
>>  Properties     string UUID [readonly]
>> 
>>                        UUID128 of this characteristic.
>> @@ -143,6 +151,26 @@ Properties         string UUID [readonly]
>>                        Friendly representation of the Characteristic Value
>>                        based on the format attribute.
>> 
>> +               dict Descriptors [readonly]
>> +
>> +                       List of descriptors for this characteristic.
>> +
>> +                       This list contains only the descriptors not already
>> +                       covered by other properties (v.g. Description, Format).
>> +
>> +                       Each descriptor is mapped to an unique object path,
>> +                       which is the key for the dict.
>> +
>> +                       Each dict value is, in turn, a dict with at least
>> +                       the following keys:
>> +
>> +                       {
>> +                               "UUID": string (descriptor UUID - mandatory),
>> +                               "Value": array of bytes (raw descriptor value -
>> +                                        optional, shows up when value can be
>> +                                        fetched)
>> +                       }
>> +
>> 
>>  Characteristic Watcher hierarchy
>>  ===============================
>> --
>> 1.7.1
>> 
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>> 
> 
> In my opinion is not a good approach to allow applications(D-Bus
> clients) to change a behavior/value of the same characteristic
> descriptor. bluetoothd could manage automatically writing the client
> characteristic configuration and server characteristic configuration
> based on the registered watchers and supported client profiles.

I'm not sure I follow, but let's break it down:

1) Note that this API is not just for client (and server) characteristic configuration descriptors. It is good for any kind of descriptor (like Valid Range, that client is supposed to be able to read, and set the related characteristic within its limits).

2) Updating automatically CCC/SCC descriptors based on Watchers sounds nice. We just need to add some kind of flag to agent registering in order to tell if we want notification or indication.

3) In terms of client profiles, the GATT API looks generic to me, not profile-specific. As there is a way to access characteristic values in a generic way, so there is a need to do the same for descriptors.

^ permalink raw reply

* Re: [PATCH 2/3] Add generic descriptor support to Attribute API document
From: Claudio Takahasi @ 2011-02-21 19:14 UTC (permalink / raw)
  To: Elvis Pfützenreuter; +Cc: linux-bluetooth
In-Reply-To: <1297880021-31728-2-git-send-email-epx@signove.com>

SGksCgoKT24gV2VkLCBGZWIgMTYsIDIwMTEgYXQgNjoxMyBQTSwgRWx2aXMgUGbDvHR6ZW5yZXV0
ZXIgPGVweEBzaWdub3ZlLmNvbT4gd3JvdGU6Cj4gVGhpcyBwYXRjaCBwcm9wb3NlcyBleHRlbnNp
b25zIHRvIEF0dHJpYnV0ZSBBUEksIGdpdmluZyBhY2Nlc3MgdG8gYWxsCj4gY2hhcmFjdGVyaXN0
aWMgZGVzY3JpcHRvcnMgKGJleW9uZCAnRGVzY3JpcHRpb24nIGFuZCAnRm9ybWF0JykuCj4gLS0t
Cj4gwqBkb2MvYXR0cmlidXRlLWFwaS50eHQgfCDCoCAyOCArKysrKysrKysrKysrKysrKysrKysr
KysrKysrCj4gwqAxIGZpbGVzIGNoYW5nZWQsIDI4IGluc2VydGlvbnMoKyksIDAgZGVsZXRpb25z
KC0pCj4KPiBkaWZmIC0tZ2l0IGEvZG9jL2F0dHJpYnV0ZS1hcGkudHh0IGIvZG9jL2F0dHJpYnV0
ZS1hcGkudHh0Cj4gaW5kZXggMjM4MDhlNi4uNWVlMTg5ZSAxMDA2NDQKPiAtLS0gYS9kb2MvYXR0
cmlidXRlLWFwaS50eHQKPiArKysgYi9kb2MvYXR0cmlidXRlLWFwaS50eHQKPiBAQCAtMTA0LDYg
KzEwNCwxNCBAQCBNZXRob2RzIMKgIMKgIMKgIMKgIMKgIMKgZGljdCBHZXRQcm9wZXJ0aWVzKCkK
Pgo+IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgUG9zc2libGUgRXJyb3JzOiBv
cmcuYmx1ZXouRXJyb3IuSW52YWxpZEFyZ3VtZW50cwo+Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDC
oCB2b2lkIFNldERlc2NyaXB0b3JWYWx1ZShvYmplY3QgZGVzY3JpcHRvciwgYXJyYXl7Ynl0ZX0g
dmFsdWUpCj4gKwo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgU2V0cyBkZXNj
cmlwdG9yIHZhbHVlLCBwcm92aWRlZCB0aGF0IGl0IGlzIHdyaXRhYmxlLgo+ICsKPiArIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIFBvc3NpYmxlIEVycm9yczogb3JnLmJsdWV6LkVy
cm9yLkludmFsaWRBcmd1bWVudHMKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIG9yZy5ibHVlei5FcnJvci5Ob3RBdXRob3JpemVkCj4g
Kwo+ICsKPiDCoFByb3BlcnRpZXMgwqAgwqAgc3RyaW5nIFVVSUQgW3JlYWRvbmx5XQo+Cj4gwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBVVUlEMTI4IG9mIHRoaXMgY2hhcmFjdGVy
aXN0aWMuCj4gQEAgLTE0Myw2ICsxNTEsMjYgQEAgUHJvcGVydGllcyDCoCDCoCDCoCDCoCBzdHJp
bmcgVVVJRCBbcmVhZG9ubHldCj4gwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqBG
cmllbmRseSByZXByZXNlbnRhdGlvbiBvZiB0aGUgQ2hhcmFjdGVyaXN0aWMgVmFsdWUKPiDCoCDC
oCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoGJhc2VkIG9uIHRoZSBmb3JtYXQgYXR0cmli
dXRlLgo+Cj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCBkaWN0IERlc2NyaXB0b3JzIFtyZWFkb25s
eV0KPiArCj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCBMaXN0IG9mIGRlc2Ny
aXB0b3JzIGZvciB0aGlzIGNoYXJhY3RlcmlzdGljLgo+ICsKPiArIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIFRoaXMgbGlzdCBjb250YWlucyBvbmx5IHRoZSBkZXNjcmlwdG9ycyBu
b3QgYWxyZWFkeQo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgY292ZXJlZCBi
eSBvdGhlciBwcm9wZXJ0aWVzICh2LmcuIERlc2NyaXB0aW9uLCBGb3JtYXQpLgo+ICsKPiArIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIEVhY2ggZGVzY3JpcHRvciBpcyBtYXBwZWQg
dG8gYW4gdW5pcXVlIG9iamVjdCBwYXRoLAo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgd2hpY2ggaXMgdGhlIGtleSBmb3IgdGhlIGRpY3QuCj4gKwo+ICsgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgRWFjaCBkaWN0IHZhbHVlIGlzLCBpbiB0dXJuLCBhIGRpY3Qg
d2l0aCBhdCBsZWFzdAo+ICsgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgdGhlIGZv
bGxvd2luZyBrZXlzOgo+ICsKPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIHsK
PiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgICJVVUlEIjog
c3RyaW5nIChkZXNjcmlwdG9yIFVVSUQgLSBtYW5kYXRvcnkpLAo+ICsgwqAgwqAgwqAgwqAgwqAg
wqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgwqAgIlZhbHVlIjogYXJyYXkgb2YgYnl0ZXMgKHJh
dyBkZXNjcmlwdG9yIHZhbHVlIC0KPiArIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKg
IMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgIMKgb3B0aW9uYWwsIHNob3dzIHVwIHdoZW4gdmFsdWUg
Y2FuIGJlCj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCDCoCDCoCDCoCDCoGZldGNoZWQpCj4gKyDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDCoCDC
oCB9Cj4gKwo+Cj4gwqBDaGFyYWN0ZXJpc3RpYyBXYXRjaGVyIGhpZXJhcmNoeQo+IMKgPT09PT09
PT09PT09PT09PT09PT09PT09PT09PT09PQo+IC0tCj4gMS43LjEKPgo+IC0tCj4gVG8gdW5zdWJz
Y3JpYmUgZnJvbSB0aGlzIGxpc3Q6IHNlbmQgdGhlIGxpbmUgInVuc3Vic2NyaWJlIGxpbnV4LWJs
dWV0b290aCIgaW4KPiB0aGUgYm9keSBvZiBhIG1lc3NhZ2UgdG8gbWFqb3Jkb21vQHZnZXIua2Vy
bmVsLm9yZwo+IE1vcmUgbWFqb3Jkb21vIGluZm8gYXQgwqBodHRwOi8vdmdlci5rZXJuZWwub3Jn
L21ham9yZG9tby1pbmZvLmh0bWwKPgoKSW4gbXkgb3BpbmlvbiBpcyBub3QgYSBnb29kIGFwcHJv
YWNoIHRvIGFsbG93IGFwcGxpY2F0aW9ucyhELUJ1cwpjbGllbnRzKSB0byBjaGFuZ2UgYSBiZWhh
dmlvci92YWx1ZSBvZiB0aGUgc2FtZSBjaGFyYWN0ZXJpc3RpYwpkZXNjcmlwdG9yLiBibHVldG9v
dGhkIGNvdWxkIG1hbmFnZSBhdXRvbWF0aWNhbGx5IHdyaXRpbmcgdGhlIGNsaWVudApjaGFyYWN0
ZXJpc3RpYyBjb25maWd1cmF0aW9uIGFuZCBzZXJ2ZXIgY2hhcmFjdGVyaXN0aWMgY29uZmlndXJh
dGlvbgpiYXNlZCBvbiB0aGUgcmVnaXN0ZXJlZCB3YXRjaGVycyBhbmQgc3VwcG9ydGVkIGNsaWVu
dCBwcm9maWxlcy4KCkJSLApDbGF1ZGlvLgo=

^ permalink raw reply

* Re: [RFC v2 00/14] Store UUID-128 on host order
From: Luiz Augusto von Dentz @ 2011-02-21 18:37 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, Anderson Lizardo, Claudio Takahasi,
	linux-bluetooth, Marcel Holtmann
  Cc: Johan Hedberg
In-Reply-To: <20110221165431.GA9130@jh-x301>

Hi,

On Mon, Feb 21, 2011 at 6:54 PM, Johan Hedberg <johan.hedberg@gmail.com> wr=
ote:
> Hi Luiz,
>
> On Mon, Feb 21, 2011, Luiz Augusto von Dentz wrote:
>> > Just throwing my own bits on this: I think making the internal
>> > representation for uuid_t consistent is important to avoid bugs when
>> > handling the different UUID types.
>> >
>> > currently uuid_t stores 16/32-bit uuids and 128-bit uuid differently.
>>
>> The problem is not the internal representation, but things like this:
>>
>> - =A0 =A0 =A0 sdp_uuid128_create(&svclass_uuid, SYNCMLC_UUID);
>> + =A0 =A0 =A0 ntoh128(SYNCMLC_UUID, &h128);
>> + =A0 =A0 =A0 sdp_uuid128_create(&svclass_uuid, &h128);
>>
>> This means the API has changed, it now takes host order where it used
>> to be network order. We could have a new function e.g.
>> sdp_uuid128h_create to handle such cases and not break existing
>> applications using this API.
>
> In this particular case the prefix sdp_ already implies that this is for
> SDP and shouldn't be used in other code. I think what makes sense (and
> Marcel supported it in IRC) is to a new bt_uuid_t struct and bt_uuid_*
> helper functions which internally store everything in host byte order.
> Then in the first phase we can make the ATT code use the new API and
> later in a second phase start converting existing SDP code to use it.

Sound good to me.



--=20
Luiz Augusto von Dentz
Computer Engineer

^ permalink raw reply

* [PATCH 2/2] Bluetooth: Use ERR_PTR as return error from hci_connect
From: anderson.briglia @ 2011-02-21 18:16 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Ville Tervo, Anderson Briglia

From: Ville Tervo <ville.tervo@nokia.com>

Use ERR_PTR mechanism to return error from hci_connect.

Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
Signed-off-by: Anderson Briglia <anderson.briglia@openbossa.org>
---
 net/bluetooth/hci_conn.c   |    8 ++++----
 net/bluetooth/l2cap_core.c |   10 ++++------
 net/bluetooth/sco.c        |    6 +++---
 3 files changed, 11 insertions(+), 13 deletions(-)

diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index d401775..06af539 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -430,10 +430,10 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
 	if (type == LE_LINK) {
 		le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
 		if (le)
-			return NULL;
+			return ERR_PTR(-EBUSY);
 		le = hci_conn_add(hdev, LE_LINK, dst);
 		if (!le)
-			return NULL;
+			return ERR_PTR(-ENOMEM);
 		if (le->state == BT_OPEN)
 			hci_le_connect(le);
 
@@ -445,8 +445,8 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
 	acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
 	if (!acl) {
 		acl = hci_conn_add(hdev, ACL_LINK, dst);
-		if (!acl)
-			return NULL;
+		if (IS_ERR(acl))
+			return acl;
 	}
 
 	hci_conn_hold(acl);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index efcef0d..e76e9e5 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -841,7 +841,7 @@ int l2cap_do_connect(struct sock *sk)
 	struct hci_conn *hcon;
 	struct hci_dev *hdev;
 	__u8 auth_type;
-	int err;
+	int err = 0;
 
 	BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
 							l2cap_pi(sk)->psm);
@@ -852,8 +852,6 @@ int l2cap_do_connect(struct sock *sk)
 
 	hci_dev_lock_bh(hdev);
 
-	err = -ENOMEM;
-
 	auth_type = l2cap_get_auth_type(sk);
 
 	if (l2cap_pi(sk)->dcid == L2CAP_CID_LE_DATA)
@@ -863,8 +861,10 @@ int l2cap_do_connect(struct sock *sk)
 		hcon = hci_connect(hdev, ACL_LINK, dst,
 					l2cap_pi(sk)->sec_level, auth_type);
 
-	if (!hcon)
+	if (IS_ERR(hcon)) {
+		err = PTR_ERR(hcon);
 		goto done;
+	}
 
 	conn = l2cap_conn_add(hcon, 0);
 	if (!conn) {
@@ -872,8 +872,6 @@ int l2cap_do_connect(struct sock *sk)
 		goto done;
 	}
 
-	err = 0;
-
 	/* Update source addr of the socket */
 	bacpy(src, conn->src);
 
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index c9348dd..26f2f04 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -190,16 +190,16 @@ static int sco_connect(struct sock *sk)
 
 	hci_dev_lock_bh(hdev);
 
-	err = -ENOMEM;
-
 	if (lmp_esco_capable(hdev) && !disable_esco)
 		type = ESCO_LINK;
 	else
 		type = SCO_LINK;
 
 	hcon = hci_connect(hdev, type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING);
-	if (!hcon)
+	if (IS_ERR(hcon)) {
+		err = PTR_ERR(hcon);
 		goto done;
+	}
 
 	conn = sco_conn_add(hcon, 0);
 	if (!conn) {
-- 
1.7.1


^ permalink raw reply related

* [PATCH 2/2] Bluetooth: Use ERR_PTR as return error from hci_connect
From: anderson.briglia @ 2011-02-21 18:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Ville Tervo, Anderson Briglia

From: Ville Tervo <ville.tervo@nokia.com>

Use ERR_PRT mechanism to return error from hci_connect.

Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
Signed-off-by: Anderson Briglia <anderson.briglia@openbossa.org>
---
 net/bluetooth/hci_conn.c   |    8 ++++----
 net/bluetooth/l2cap_core.c |   10 ++++------
 net/bluetooth/sco.c        |    6 +++---
 3 files changed, 11 insertions(+), 13 deletions(-)

diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index d401775..06af539 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -430,10 +430,10 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
 	if (type == LE_LINK) {
 		le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
 		if (le)
-			return NULL;
+			return ERR_PTR(-EBUSY);
 		le = hci_conn_add(hdev, LE_LINK, dst);
 		if (!le)
-			return NULL;
+			return ERR_PTR(-ENOMEM);
 		if (le->state == BT_OPEN)
 			hci_le_connect(le);
 
@@ -445,8 +445,8 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
 	acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
 	if (!acl) {
 		acl = hci_conn_add(hdev, ACL_LINK, dst);
-		if (!acl)
-			return NULL;
+		if (IS_ERR(acl))
+			return acl;
 	}
 
 	hci_conn_hold(acl);
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index efcef0d..e76e9e5 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -841,7 +841,7 @@ int l2cap_do_connect(struct sock *sk)
 	struct hci_conn *hcon;
 	struct hci_dev *hdev;
 	__u8 auth_type;
-	int err;
+	int err = 0;
 
 	BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
 							l2cap_pi(sk)->psm);
@@ -852,8 +852,6 @@ int l2cap_do_connect(struct sock *sk)
 
 	hci_dev_lock_bh(hdev);
 
-	err = -ENOMEM;
-
 	auth_type = l2cap_get_auth_type(sk);
 
 	if (l2cap_pi(sk)->dcid == L2CAP_CID_LE_DATA)
@@ -863,8 +861,10 @@ int l2cap_do_connect(struct sock *sk)
 		hcon = hci_connect(hdev, ACL_LINK, dst,
 					l2cap_pi(sk)->sec_level, auth_type);
 
-	if (!hcon)
+	if (IS_ERR(hcon)) {
+		err = PTR_ERR(hcon);
 		goto done;
+	}
 
 	conn = l2cap_conn_add(hcon, 0);
 	if (!conn) {
@@ -872,8 +872,6 @@ int l2cap_do_connect(struct sock *sk)
 		goto done;
 	}
 
-	err = 0;
-
 	/* Update source addr of the socket */
 	bacpy(src, conn->src);
 
diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c
index c9348dd..26f2f04 100644
--- a/net/bluetooth/sco.c
+++ b/net/bluetooth/sco.c
@@ -190,16 +190,16 @@ static int sco_connect(struct sock *sk)
 
 	hci_dev_lock_bh(hdev);
 
-	err = -ENOMEM;
-
 	if (lmp_esco_capable(hdev) && !disable_esco)
 		type = ESCO_LINK;
 	else
 		type = SCO_LINK;
 
 	hcon = hci_connect(hdev, type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING);
-	if (!hcon)
+	if (IS_ERR(hcon)) {
+		err = PTR_ERR(hcon);
 		goto done;
+	}
 
 	conn = sco_conn_add(hcon, 0);
 	if (!conn) {
-- 
1.7.1


^ permalink raw reply related

* [PATCH 1/2] Bluetooth: Fix LE conn creation
From: anderson.briglia @ 2011-02-21 18:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anderson Briglia, Ville Tervo

From: Anderson Briglia <anderson.briglia@openbossa.org>

This patch prevents a crash when remote host tries to create a LE
link which already exists. i.e.: call l2test twice passing the
same parameters.

Signed-off-by: Anderson Briglia <anderson.briglia@openbossa.org>
Signed-off-by: Ville Tervo <ville.tervo@nokia.com>
---
 net/bluetooth/hci_conn.c |    5 +++--
 1 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index a050a69..d401775 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -429,8 +429,9 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
 
 	if (type == LE_LINK) {
 		le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
-		if (!le)
-			le = hci_conn_add(hdev, LE_LINK, dst);
+		if (le)
+			return NULL;
+		le = hci_conn_add(hdev, LE_LINK, dst);
 		if (!le)
 			return NULL;
 		if (le->state == BT_OPEN)
-- 
1.7.1


^ permalink raw reply related

* [bluetooth-next 15/15] Bluetooth: Add key size checks for SMP
From: Vinicius Costa Gomes @ 2011-02-21 17:24 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Vinicius Costa Gomes, Anderson Briglia
In-Reply-To: <cover.1298307667.git.vinicius.gomes@openbossa.org>

This patch implements a check in smp cmd pairing request and pairing
response to verify if encryption key maximum size is compatible in both
slave and master when SMP Pairing is requested. Keys are also masked to
the correct negotiated size.

Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@openbossa.org>
Signed-off-by: Anderson Briglia <anderson.briglia@openbossa.org>
---
 include/net/bluetooth/l2cap.h |    1 +
 include/net/bluetooth/smp.h   |    3 ++
 net/bluetooth/smp.c           |   54 +++++++++++++++++++++++++++++++----------
 3 files changed, 45 insertions(+), 13 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index c2d4ff4..577948f 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -312,6 +312,7 @@ struct l2cap_conn {
 	__u8		prnd[16]; /* SMP Pairing Random */
 	__u8		pcnf[16]; /* SMP Pairing Confirm */
 	__u8		tk[16]; /* SMP Temporary Key */
+	__u8		smp_key_size;
 
 	struct timer_list security_timer;
 
diff --git a/include/net/bluetooth/smp.h b/include/net/bluetooth/smp.h
index 111853a..4fb7d19 100644
--- a/include/net/bluetooth/smp.h
+++ b/include/net/bluetooth/smp.h
@@ -112,6 +112,9 @@ struct smp_cmd_security_req {
 #define SMP_UNSPECIFIED		0x08
 #define SMP_REPEATED_ATTEMPTS		0x09
 
+#define SMP_MIN_ENC_KEY_SIZE		7
+#define SMP_MAX_ENC_KEY_SIZE		16
+
 /* SMP Commands */
 int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level);
 int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb);
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 33a2932..f94b480 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -204,35 +204,51 @@ static void build_pairing_cmd(struct l2cap_conn *conn, struct smp_cmd_pairing *c
 {
 	cmd->io_capability = SMP_IO_NO_INPUT_OUTPUT;
 	cmd->oob_flag = SMP_OOB_NOT_PRESENT;
-	cmd->max_key_size = 16;
+	cmd->max_key_size = SMP_MAX_ENC_KEY_SIZE;
 	cmd->init_key_dist = 0x00;
 	cmd->resp_key_dist = 0x00;
 	cmd->auth_req = authreq;
 }
 
+static u8 check_enc_key_size(struct l2cap_conn *conn, __u8 max_key_size)
+{
+	if ((max_key_size > SMP_MAX_ENC_KEY_SIZE) ||
+			(max_key_size < SMP_MIN_ENC_KEY_SIZE))
+		return SMP_ENC_KEY_SIZE;
+
+	conn->smp_key_size = max_key_size;
+
+	return 0;
+}
+
 static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 {
-	struct smp_cmd_pairing *rp = (void *) skb->data;
+	struct smp_cmd_pairing rsp, *req = (void *) skb->data;
+	u8 key_size;
 
 	BT_DBG("conn %p", conn);
 
 	conn->preq[0] = SMP_CMD_PAIRING_REQ;
-	memcpy(&conn->preq[1], rp, sizeof(*rp));
-	skb_pull(skb, sizeof(*rp));
+	memcpy(&conn->preq[1], req, sizeof(*req));
+	skb_pull(skb, sizeof(*req));
 
-	if (rp->oob_flag)
+	if (req->oob_flag)
 		return SMP_OOB_NOT_AVAIL;
 
 	/* We didn't start the pairing, so no requirements */
-	build_pairing_cmd(conn, rp, SMP_AUTH_NONE);
+	build_pairing_cmd(conn, &rsp, SMP_AUTH_NONE);
+
+	key_size = min(req->max_key_size, rsp.max_key_size);
+	if (check_enc_key_size(conn, key_size))
+		return SMP_ENC_KEY_SIZE;
 
 	/* Just works */
 	memset(conn->tk, 0, sizeof(conn->tk));
 
 	conn->prsp[0] = SMP_CMD_PAIRING_RSP;
-	memcpy(&conn->prsp[1], rp, sizeof(*rp));
+	memcpy(&conn->prsp[1], &rsp, sizeof(rsp));
 
-	smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(*rp), rp);
+	smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(rsp), &rsp);
 
 	mod_timer(&conn->security_timer, jiffies +
 					msecs_to_jiffies(SMP_TIMEOUT));
@@ -242,24 +258,30 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 
 static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 {
-	struct smp_cmd_pairing *rp = (void *) skb->data;
+	struct smp_cmd_pairing *req, *rsp = (void *) skb->data;
 	struct smp_cmd_pairing_confirm cp;
 	struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm;
 	int ret;
-	u8 res[16];
+	u8 res[16], key_size;
 
 	BT_DBG("conn %p", conn);
 
-	skb_pull(skb, sizeof(*rp));
+	skb_pull(skb, sizeof(*rsp));
+
+	req = (void *) &conn->preq[1];
 
-	if (rp->oob_flag)
+	key_size = min(req->max_key_size, rsp->max_key_size);
+	if (check_enc_key_size(conn, key_size))
+		return SMP_ENC_KEY_SIZE;
+
+	if (rsp->oob_flag)
 		return SMP_OOB_NOT_AVAIL;
 
 	/* Just works */
 	memset(conn->tk, 0, sizeof(conn->tk));
 
 	conn->prsp[0] = SMP_CMD_PAIRING_RSP;
-	memcpy(&conn->prsp[1], rp, sizeof(*rp));
+	memcpy(&conn->prsp[1], rsp, sizeof(*rsp));
 
 	ret = smp_rand(conn->prnd);
 	if (ret)
@@ -351,6 +373,9 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 		smp_s1(tfm, conn->tk, random, conn->prnd, key);
 		swap128(key, hcon->ltk);
 
+		memset(hcon->ltk + conn->smp_key_size, 0,
+				SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
+
 		hci_le_start_enc(hcon, hcon->ltk);
 
 		hex_dump_to_buffer(key, sizeof(key), 16, 1, buf, sizeof(buf), 0);
@@ -364,6 +389,9 @@ static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 		smp_s1(tfm, conn->tk, conn->prnd, random, key);
 		swap128(key, hcon->ltk);
 
+		memset(hcon->ltk + conn->smp_key_size, 0,
+				SMP_MAX_ENC_KEY_SIZE - conn->smp_key_size);
+
 		hex_dump_to_buffer(key, sizeof(key), 16, 1, buf, sizeof(buf), 0);
 		BT_DBG("key %s", buf);
 	}
-- 
1.7.4.1


^ permalink raw reply related

* [bluetooth-next 14/15] Bluetooth: Add support for SMP timeout
From: Vinicius Costa Gomes @ 2011-02-21 17:24 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Vinicius Costa Gomes
In-Reply-To: <cover.1298307667.git.vinicius.gomes@openbossa.org>

This patch adds support for disconnecting the link when SMP procedure
takes more than 30 seconds.

SMP begins when either the Pairing Request command is sent or the
Pairing Response is received, and it ends when the link is encrypted
(or terminated). Vol 3, Part H Section 3.4.

Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@openbossa.org>
---
 include/net/bluetooth/l2cap.h |    2 +
 net/bluetooth/l2cap_core.c    |   70 ++++++++++++++++++++++++----------------
 net/bluetooth/smp.c           |   14 ++++++++
 3 files changed, 58 insertions(+), 28 deletions(-)

diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index ed65d65..c2d4ff4 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -313,6 +313,8 @@ struct l2cap_conn {
 	__u8		pcnf[16]; /* SMP Pairing Confirm */
 	__u8		tk[16]; /* SMP Temporary Key */
 
+	struct timer_list security_timer;
+
 	struct l2cap_chan_list chan_list;
 };
 
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 991b349..d781703 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -733,6 +733,36 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
 	read_unlock(&l->lock);
 }
 
+static void l2cap_conn_del(struct hci_conn *hcon, int err)
+{
+	struct l2cap_conn *conn = hcon->l2cap_data;
+	struct sock *sk;
+
+	if (!conn)
+		return;
+
+	BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
+
+	kfree_skb(conn->rx_skb);
+
+	/* Kill channels */
+	while ((sk = conn->chan_list.head)) {
+		bh_lock_sock(sk);
+		l2cap_chan_del(sk, err);
+		bh_unlock_sock(sk);
+		l2cap_sock_kill(sk);
+	}
+
+	if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
+		del_timer_sync(&conn->info_timer);
+
+	if (hcon->type == LE_LINK)
+		del_timer(&conn->security_timer);
+
+	hcon->l2cap_data = NULL;
+	kfree(conn);
+}
+
 static void l2cap_info_timeout(unsigned long arg)
 {
 	struct l2cap_conn *conn = (void *) arg;
@@ -743,6 +773,13 @@ static void l2cap_info_timeout(unsigned long arg)
 	l2cap_conn_start(conn);
 }
 
+static void security_timeout(unsigned long arg)
+{
+	struct l2cap_conn *conn = (void *) arg;
+
+	l2cap_conn_del(conn->hcon, ETIMEDOUT);
+}
+
 static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
 {
 	struct l2cap_conn *conn = hcon->l2cap_data;
@@ -772,7 +809,10 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
 	spin_lock_init(&conn->lock);
 	rwlock_init(&conn->chan_list.lock);
 
-	if (hcon->type != LE_LINK)
+	if (hcon->type == LE_LINK)
+		setup_timer(&conn->security_timer, security_timeout,
+						(unsigned long) conn);
+	else
 		setup_timer(&conn->info_timer, l2cap_info_timeout,
 						(unsigned long) conn);
 
@@ -781,33 +821,6 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
 	return conn;
 }
 
-static void l2cap_conn_del(struct hci_conn *hcon, int err)
-{
-	struct l2cap_conn *conn = hcon->l2cap_data;
-	struct sock *sk;
-
-	if (!conn)
-		return;
-
-	BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
-
-	kfree_skb(conn->rx_skb);
-
-	/* Kill channels */
-	while ((sk = conn->chan_list.head)) {
-		bh_lock_sock(sk);
-		l2cap_chan_del(sk, err);
-		bh_unlock_sock(sk);
-		l2cap_sock_kill(sk);
-	}
-
-	if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
-		del_timer_sync(&conn->info_timer);
-
-	hcon->l2cap_data = NULL;
-	kfree(conn);
-}
-
 static inline void l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct sock *parent)
 {
 	struct l2cap_chan_list *l = &conn->chan_list;
@@ -3794,6 +3807,7 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 		if (l2cap_pi(sk)->scid == L2CAP_CID_LE_DATA) {
 			if (!status && encrypt) {
 				l2cap_pi(sk)->sec_level = hcon->sec_level;
+				del_timer(&conn->security_timer);
 				l2cap_chan_ready(sk);
 			}
 
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 496a1ba..33a2932 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -27,6 +27,8 @@
 #include <linux/crypto.h>
 #include <crypto/b128ops.h>
 
+#define SMP_TIMEOUT 30000 /* 30 seconds */
+
 static inline void swap128(u8 src[16], u8 dst[16])
 {
 	int i;
@@ -232,6 +234,9 @@ static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(*rp), rp);
 
+	mod_timer(&conn->security_timer, jiffies +
+					msecs_to_jiffies(SMP_TIMEOUT));
+
 	return 0;
 }
 
@@ -306,6 +311,9 @@ static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
 		smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
 	}
 
+	mod_timer(&conn->security_timer, jiffies +
+					msecs_to_jiffies(SMP_TIMEOUT));
+
 	return 0;
 }
 
@@ -384,6 +392,9 @@ static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
 
+	mod_timer(&conn->security_timer, jiffies +
+					msecs_to_jiffies(SMP_TIMEOUT));
+
 	set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
 
 	return 0;
@@ -417,6 +428,9 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
 		conn->preq[0] = SMP_CMD_PAIRING_REQ;
 		memcpy(&conn->preq[1], &cp, sizeof(cp));
 
+		mod_timer(&conn->security_timer, jiffies +
+					msecs_to_jiffies(SMP_TIMEOUT));
+
 		smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
 	} else {
 		struct smp_cmd_security_req cp;
-- 
1.7.4.1


^ permalink raw reply related

* [bluetooth-next 13/15] Bluetooth: Add support for Pairing features exchange
From: Vinicius Costa Gomes @ 2011-02-21 17:24 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Vinicius Costa Gomes
In-Reply-To: <cover.1298307667.git.vinicius.gomes@openbossa.org>

This patch implements a simple version of the SMP Pairing Features
exchange procedure (Vol. 3 Part H, Section 2.3.5.1).

For now, everything that would cause a Pairing Method different of
Just Works to be chosen is rejected.

Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@openbossa.org>
---
 net/bluetooth/hci_event.c |    1 +
 net/bluetooth/smp.c       |  115 ++++++++++++++++++++++++--------------------
 2 files changed, 64 insertions(+), 52 deletions(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 0637755..890177f 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1510,6 +1510,7 @@ static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *
 				/* Encryption implies authentication */
 				conn->link_mode |= HCI_LM_AUTH;
 				conn->link_mode |= HCI_LM_ENCRYPT;
+				conn->sec_level = conn->pending_sec_level;
 			} else
 				conn->link_mode &= ~HCI_LM_ENCRYPT;
 		}
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 1fd338b..496a1ba 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -186,7 +186,29 @@ static void smp_send_cmd(struct l2cap_conn *conn, u8 code, u16 len, void *data)
 	hci_send_acl(conn->hcon, skb, 0);
 }
 
-static void smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
+static __u8 seclevel_to_authreq(__u8 level)
+{
+	switch (level) {
+	case BT_SECURITY_HIGH:
+		/* Right now we don't support bonding */
+		return SMP_AUTH_MITM;
+
+	default:
+		return SMP_AUTH_NONE;
+	}
+}
+
+static void build_pairing_cmd(struct l2cap_conn *conn, struct smp_cmd_pairing *cmd, __u8 authreq)
+{
+	cmd->io_capability = SMP_IO_NO_INPUT_OUTPUT;
+	cmd->oob_flag = SMP_OOB_NOT_PRESENT;
+	cmd->max_key_size = 16;
+	cmd->init_key_dist = 0x00;
+	cmd->resp_key_dist = 0x00;
+	cmd->auth_req = authreq;
+}
+
+static u8 smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 {
 	struct smp_cmd_pairing *rp = (void *) skb->data;
 
@@ -196,12 +218,11 @@ static void smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 	memcpy(&conn->preq[1], rp, sizeof(*rp));
 	skb_pull(skb, sizeof(*rp));
 
-	rp->io_capability = 0x00;
-	rp->oob_flag = 0x00;
-	rp->max_key_size = 16;
-	rp->init_key_dist = 0x00;
-	rp->resp_key_dist = 0x00;
-	rp->auth_req &= (SMP_AUTH_BONDING | SMP_AUTH_MITM);
+	if (rp->oob_flag)
+		return SMP_OOB_NOT_AVAIL;
+
+	/* We didn't start the pairing, so no requirements */
+	build_pairing_cmd(conn, rp, SMP_AUTH_NONE);
 
 	/* Just works */
 	memset(conn->tk, 0, sizeof(conn->tk));
@@ -210,9 +231,11 @@ static void smp_cmd_pairing_req(struct l2cap_conn *conn, struct sk_buff *skb)
 	memcpy(&conn->prsp[1], rp, sizeof(*rp));
 
 	smp_send_cmd(conn, SMP_CMD_PAIRING_RSP, sizeof(*rp), rp);
+
+	return 0;
 }
 
-static void smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
+static u8 smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 {
 	struct smp_cmd_pairing *rp = (void *) skb->data;
 	struct smp_cmd_pairing_confirm cp;
@@ -222,28 +245,34 @@ static void smp_cmd_pairing_rsp(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	BT_DBG("conn %p", conn);
 
+	skb_pull(skb, sizeof(*rp));
+
+	if (rp->oob_flag)
+		return SMP_OOB_NOT_AVAIL;
+
 	/* Just works */
 	memset(conn->tk, 0, sizeof(conn->tk));
 
 	conn->prsp[0] = SMP_CMD_PAIRING_RSP;
 	memcpy(&conn->prsp[1], rp, sizeof(*rp));
-	skb_pull(skb, sizeof(*rp));
 
 	ret = smp_rand(conn->prnd);
 	if (ret)
-		return;
+		return SMP_UNSPECIFIED;
 
 	ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp, 0,
 			conn->src, 0, conn->dst, res);
 	if (ret)
-		return;
+		return SMP_UNSPECIFIED;
 
 	swap128(res, cp.confirm_val);
 
 	smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
+
+	return 0;
 }
 
-static void smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
+static u8 smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb)
 {
 	struct crypto_blkcipher *tfm = conn->hcon->hdev->tfm;
 
@@ -265,20 +294,22 @@ static void smp_cmd_pairing_confirm(struct l2cap_conn *conn, struct sk_buff *skb
 
 		ret = smp_rand(conn->prnd);
 		if (ret)
-			return;
+			return SMP_UNSPECIFIED;
 
 		ret = smp_c1(tfm, conn->tk, conn->prnd, conn->preq, conn->prsp,
 					0, conn->dst, 0, conn->src, res);
 		if (ret)
-			return;
+			return SMP_CONFIRM_FAILED;
 
 		swap128(res, cp.confirm_val);
 
 		smp_send_cmd(conn, SMP_CMD_PAIRING_CONFIRM, sizeof(cp), &cp);
 	}
+
+	return 0;
 }
 
-static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
+static u8 smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 {
 	struct hci_conn *hcon = conn->hcon;
 	struct crypto_blkcipher *tfm = hcon->hdev->tfm;
@@ -297,19 +328,15 @@ static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 		ret = smp_c1(tfm, conn->tk, random, conn->preq, conn->prsp, 0,
 				conn->dst, 0, conn->src, res);
 	if (ret)
-		return;
+		return SMP_UNSPECIFIED;
 
 	BT_DBG("conn %p %s", conn, conn->hcon->out ? "master" : "slave");
 
 	swap128(res, confirm);
 
 	if (memcmp(conn->pcnf, confirm, sizeof(conn->pcnf)) != 0) {
-		struct smp_cmd_pairing_fail cp;
-
 		BT_ERR("Pairing failed (confirmation values mismatch)");
-		cp.reason = SMP_CONFIRM_FAILED;
-		smp_send_cmd(conn, SMP_CMD_PAIRING_FAIL, sizeof(cp), &cp);
-		return;
+		return SMP_CONFIRM_FAILED;
 	}
 
 	if (conn->hcon->out) {
@@ -332,9 +359,11 @@ static void smp_cmd_pairing_random(struct l2cap_conn *conn, struct sk_buff *skb)
 		hex_dump_to_buffer(key, sizeof(key), 16, 1, buf, sizeof(buf), 0);
 		BT_DBG("key %s", buf);
 	}
+
+	return 0;
 }
 
-static void smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
+static u8 smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
 {
 	struct smp_cmd_security_req *rp = (void *) skb->data;
 	struct smp_cmd_pairing cp;
@@ -343,17 +372,12 @@ static void smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
 	BT_DBG("conn %p", conn);
 
 	if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
-		return;
+		return 0;
 
 	skb_pull(skb, sizeof(*rp));
-	memset(&cp, 0, sizeof(cp));
 
-	cp.io_capability = 0x00;
-	cp.oob_flag = 0x00;
-	cp.max_key_size = 16;
-	cp.init_key_dist = 0x00;
-	cp.resp_key_dist = 0x00;
-	cp.auth_req = rp->auth_req & (SMP_AUTH_BONDING | SMP_AUTH_MITM);
+	memset(&cp, 0, sizeof(cp));
+	build_pairing_cmd(conn, &cp, rp->auth_req);
 
 	conn->preq[0] = SMP_CMD_PAIRING_REQ;
 	memcpy(&conn->preq[1], &cp, sizeof(cp));
@@ -361,18 +385,8 @@ static void smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
 	smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
 
 	set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
-}
 
-static __u8 seclevel_to_authreq(__u8 level)
-{
-	switch (level) {
-	case BT_SECURITY_HIGH:
-		/* For now we don't support bonding */
-		return SMP_AUTH_MITM;
-
-	default:
-		return SMP_AUTH_NONE;
-	}
+	return 0;
 }
 
 int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
@@ -398,13 +412,8 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
 
 	if (hcon->link_mode & HCI_LM_MASTER) {
 		struct smp_cmd_pairing cp;
-		cp.io_capability = 0x00;
-		cp.oob_flag = 0x00;
-		cp.max_key_size = 16;
-		cp.init_key_dist = 0x00;
-		cp.resp_key_dist = 0x00;
-		cp.auth_req = authreq;
 
+		build_pairing_cmd(conn, &cp, authreq);
 		conn->preq[0] = SMP_CMD_PAIRING_REQ;
 		memcpy(&conn->preq[1], &cp, sizeof(cp));
 
@@ -437,26 +446,28 @@ int smp_sig_channel(struct l2cap_conn *conn, struct sk_buff *skb)
 
 	switch (code) {
 	case SMP_CMD_PAIRING_REQ:
-		smp_cmd_pairing_req(conn, skb);
+		reason = smp_cmd_pairing_req(conn, skb);
 		break;
 
 	case SMP_CMD_PAIRING_FAIL:
+		reason = 0;
+		err = -EPERM;
 		break;
 
 	case SMP_CMD_PAIRING_RSP:
-		smp_cmd_pairing_rsp(conn, skb);
+		reason = smp_cmd_pairing_rsp(conn, skb);
 		break;
 
 	case SMP_CMD_SECURITY_REQ:
-		smp_cmd_security_req(conn, skb);
+		reason = smp_cmd_security_req(conn, skb);
 		break;
 
 	case SMP_CMD_PAIRING_CONFIRM:
-		smp_cmd_pairing_confirm(conn, skb);
+		reason = smp_cmd_pairing_confirm(conn, skb);
 		break;
 
 	case SMP_CMD_PAIRING_RANDOM:
-		smp_cmd_pairing_random(conn, skb);
+		reason = smp_cmd_pairing_random(conn, skb);
 		break;
 
 	case SMP_CMD_ENCRYPT_INFO:
-- 
1.7.4.1


^ permalink raw reply related

* [bluetooth-next 12/15] Bluetooth: Update the security level when link is encrypted
From: Vinicius Costa Gomes @ 2011-02-21 17:23 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Vinicius Costa Gomes
In-Reply-To: <cover.1298307667.git.vinicius.gomes@openbossa.org>

If the pending security level is greater than the current security
level and the link is now encrypted, we should update the link
security level.

This is only useful for LE links, when the only event generated
when SMP is sucessful in the Encrypt Change event.
---
 include/net/bluetooth/hci_core.h |    3 +++
 1 files changed, 3 insertions(+), 0 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index aeae4b4..c949073 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -679,6 +679,9 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encr
 	if (conn->sec_level == BT_SECURITY_SDP)
 		conn->sec_level = BT_SECURITY_LOW;
 
+	if (conn->pending_sec_level > conn->sec_level)
+		conn->sec_level = conn->pending_sec_level;
+
 	hci_proto_encrypt_cfm(conn, status, encrypt);
 
 	read_lock_bh(&hci_cb_list_lock);
-- 
1.7.4.1


^ permalink raw reply related

* [bluetooth-next 11/15] Bluetooth: Fix initial security level of LE links
From: Vinicius Costa Gomes @ 2011-02-21 17:23 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Vinicius Costa Gomes
In-Reply-To: <cover.1298307667.git.vinicius.gomes@openbossa.org>

As the default security level (BT_SECURITY_SDP) doesn't make sense for
LE links, initialize LE links with something that makes sense.

Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@openbossa.org>
---
 net/bluetooth/hci_conn.c  |    1 +
 net/bluetooth/hci_event.c |    1 +
 2 files changed, 2 insertions(+), 0 deletions(-)

diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index e75b2a6..160c60c 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -53,6 +53,7 @@ static void hci_le_connect(struct hci_conn *conn)
 	conn->state = BT_CONNECT;
 	conn->out = 1;
 	conn->link_mode |= HCI_LM_MASTER;
+	conn->sec_level = BT_SECURITY_LOW;
 
 	memset(&cp, 0, sizeof(cp));
 	cp.scan_interval = cpu_to_le16(0x0004);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 829ba49..0637755 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2461,6 +2461,7 @@ static inline void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff
 		goto unlock;
 	}
 
+	conn->sec_level = BT_SECURITY_LOW;
 	conn->handle = __le16_to_cpu(ev->handle);
 	conn->state = BT_CONNECTED;
 
-- 
1.7.4.1


^ permalink raw reply related

* [bluetooth-next 10/15] Bluetooth: Add support for resuming socket when SMP is finished
From: Vinicius Costa Gomes @ 2011-02-21 17:23 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Vinicius Costa Gomes
In-Reply-To: <cover.1298307667.git.vinicius.gomes@openbossa.org>

This adds support for resuming the user space traffic when SMP
negotiation is complete.

Signed-off-by: Vinicius Costa Gomes <vinicius.gomes@openbossa.org>
---
 net/bluetooth/l2cap_core.c |   61 ++++++++++++++++++++++---------------------
 net/bluetooth/l2cap_sock.c |   17 ++++++++++++
 net/bluetooth/smp.c        |   40 ++++++++++++++++++++--------
 3 files changed, 76 insertions(+), 42 deletions(-)

diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 66988b8..991b349 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -666,6 +666,22 @@ clean:
 	bh_unlock_sock(parent);
 }
 
+static void l2cap_chan_ready(struct sock *sk)
+{
+	struct sock *parent = bt_sk(sk)->parent;
+
+	BT_DBG("sk %p, parent %p", sk, parent);
+
+	l2cap_pi(sk)->conf_state = 0;
+	l2cap_sock_clear_timer(sk);
+
+	sk->sk_state = BT_CONNECTED;
+	sk->sk_state_change(sk);
+
+	if (parent)
+		parent->sk_data_ready(parent, 0);
+}
+
 static void l2cap_conn_ready(struct l2cap_conn *conn)
 {
 	struct l2cap_chan_list *l = &conn->chan_list;
@@ -681,15 +697,11 @@ static void l2cap_conn_ready(struct l2cap_conn *conn)
 	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
 		bh_lock_sock(sk);
 
-		if (conn->hcon->type == LE_LINK) {
-			l2cap_sock_clear_timer(sk);
-			sk->sk_state = BT_CONNECTED;
-			sk->sk_state_change(sk);
+		if (l2cap_pi(sk)->scid == L2CAP_CID_LE_DATA) {
 			if (smp_conn_security(conn, l2cap_pi(sk)->sec_level))
-				BT_DBG("Insufficient security");
-		}
+				l2cap_chan_ready(sk);
 
-		if (sk->sk_type != SOCK_SEQPACKET &&
+		} else if (sk->sk_type != SOCK_SEQPACKET &&
 				sk->sk_type != SOCK_STREAM) {
 			l2cap_sock_clear_timer(sk);
 			sk->sk_state = BT_CONNECTED;
@@ -1360,29 +1372,6 @@ int l2cap_sar_segment_sdu(struct sock *sk, struct msghdr *msg, size_t len)
 	return size;
 }
 
-static void l2cap_chan_ready(struct sock *sk)
-{
-	struct sock *parent = bt_sk(sk)->parent;
-
-	BT_DBG("sk %p, parent %p", sk, parent);
-
-	l2cap_pi(sk)->conf_state = 0;
-	l2cap_sock_clear_timer(sk);
-
-	if (!parent) {
-		/* Outgoing channel.
-		 * Wake up socket sleeping on connect.
-		 */
-		sk->sk_state = BT_CONNECTED;
-		sk->sk_state_change(sk);
-	} else {
-		/* Incoming channel.
-		 * Wake up socket sleeping on accept.
-		 */
-		parent->sk_data_ready(parent, 0);
-	}
-}
-
 /* Copy frame to all raw sockets on that connection */
 static void l2cap_raw_recv(struct l2cap_conn *conn, struct sk_buff *skb)
 {
@@ -3800,6 +3789,18 @@ static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 	for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
 		bh_lock_sock(sk);
 
+		BT_DBG("sk->scid %d", l2cap_pi(sk)->scid);
+
+		if (l2cap_pi(sk)->scid == L2CAP_CID_LE_DATA) {
+			if (!status && encrypt) {
+				l2cap_pi(sk)->sec_level = hcon->sec_level;
+				l2cap_chan_ready(sk);
+			}
+
+			bh_unlock_sock(sk);
+			continue;
+		}
+
 		if (l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND) {
 			bh_unlock_sock(sk);
 			continue;
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index fc85e7a..3abf678 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -29,6 +29,7 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
+#include <net/bluetooth/smp.h>
 
 /* ---- L2CAP timers ---- */
 static void l2cap_sock_timeout(unsigned long arg)
@@ -614,6 +615,7 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
 {
 	struct sock *sk = sock->sk;
 	struct bt_security sec;
+	struct l2cap_conn *conn;
 	int len, err = 0;
 	u32 opt;
 
@@ -650,6 +652,21 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
 		}
 
 		l2cap_pi(sk)->sec_level = sec.level;
+
+		conn = l2cap_pi(sk)->conn;
+		if (conn && l2cap_pi(sk)->scid == L2CAP_CID_LE_DATA) {
+			if (!conn->hcon->out) {
+				err = -EINVAL;
+				break;
+			}
+
+			if (!smp_conn_security(conn, sec.level)) {
+				err = -EINVAL;
+				break;
+			}
+
+			sk->sk_state = BT_CONFIG;
+		}
 		break;
 
 	case BT_DEFER_SETUP:
diff --git a/net/bluetooth/smp.c b/net/bluetooth/smp.c
index 6d32bcc..1fd338b 100644
--- a/net/bluetooth/smp.c
+++ b/net/bluetooth/smp.c
@@ -338,9 +338,13 @@ static void smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
 {
 	struct smp_cmd_security_req *rp = (void *) skb->data;
 	struct smp_cmd_pairing cp;
+	struct hci_conn *hcon = conn->hcon;
 
 	BT_DBG("conn %p", conn);
 
+	if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
+		return;
+
 	skb_pull(skb, sizeof(*rp));
 	memset(&cp, 0, sizeof(cp));
 
@@ -355,6 +359,20 @@ static void smp_cmd_security_req(struct l2cap_conn *conn, struct sk_buff *skb)
 	memcpy(&conn->preq[1], &cp, sizeof(cp));
 
 	smp_send_cmd(conn, SMP_CMD_PAIRING_REQ, sizeof(cp), &cp);
+
+	set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
+}
+
+static __u8 seclevel_to_authreq(__u8 level)
+{
+	switch (level) {
+	case BT_SECURITY_HIGH:
+		/* For now we don't support bonding */
+		return SMP_AUTH_MITM;
+
+	default:
+		return SMP_AUTH_NONE;
+	}
 }
 
 int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
@@ -367,21 +385,16 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
 	if (IS_ERR(hcon->hdev->tfm))
 		return PTR_ERR(hcon->hdev->tfm);
 
-	switch (sec_level) {
-	case BT_SECURITY_MEDIUM:
-		/* Encrypted, no MITM protection */
-		authreq = HCI_AT_NO_BONDING_MITM;
-		break;
+	if (test_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend))
+		return -EINPROGRESS;
 
-	case BT_SECURITY_HIGH:
-		/* Bonding, MITM protection */
-		authreq = HCI_AT_GENERAL_BONDING_MITM;
-		break;
+	if (sec_level == BT_SECURITY_LOW)
+		return 1;
 
-	case BT_SECURITY_LOW:
-	default:
+	if (hcon->sec_level > sec_level)
 		return 1;
-	}
+
+	authreq = seclevel_to_authreq(sec_level);
 
 	if (hcon->link_mode & HCI_LM_MASTER) {
 		struct smp_cmd_pairing cp;
@@ -402,6 +415,9 @@ int smp_conn_security(struct l2cap_conn *conn, __u8 sec_level)
 		smp_send_cmd(conn, SMP_CMD_SECURITY_REQ, sizeof(cp), &cp);
 	}
 
+	hcon->pending_sec_level = sec_level;
+	set_bit(HCI_CONN_ENCRYPT_PEND, &hcon->pend);
+
 	return 0;
 }
 
-- 
1.7.4.1


^ 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