* [PATCH BlueZ 02/11] attrib: Add missing g_error_free()
From: Anderson Lizardo @ 2014-01-11 4:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1389415647-25831-1-git-send-email-anderson.lizardo@openbossa.org>
Also print error message.
---
src/attrib-server.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/attrib-server.c b/src/attrib-server.c
index a7ee55d..fcc6601 100644
--- a/src/attrib-server.c
+++ b/src/attrib-server.c
@@ -944,10 +944,12 @@ static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu,
io = g_attrib_get_channel(channel->attrib);
bt_io_get(io, &gerr, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_INVALID);
-
- if (gerr)
- return enc_error_resp(ATT_OP_MTU_REQ, 0,
- ATT_ECODE_UNLIKELY, pdu, len);
+ if (gerr) {
+ error("bt_io_get: %s", gerr->message);
+ g_error_free(gerr);
+ return enc_error_resp(ATT_OP_MTU_REQ, 0, ATT_ECODE_UNLIKELY,
+ pdu, len);
+ }
channel->mtu = MIN(mtu, imtu);
g_attrib_set_mtu(channel->attrib, channel->mtu);
--
1.8.3.2
^ permalink raw reply related
* [PATCH BlueZ 03/11] attrib: Use att_put_u16() instead of htobs() + memcpy()
From: Anderson Lizardo @ 2014-01-11 4:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1389415647-25831-1-git-send-email-anderson.lizardo@openbossa.org>
---
attrib/att.c | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/attrib/att.c b/attrib/att.c
index 753c753..d9ca709 100644
--- a/attrib/att.c
+++ b/attrib/att.c
@@ -723,15 +723,13 @@ uint16_t enc_error_resp(uint8_t opcode, uint16_t handle, uint8_t status,
{
const uint16_t min_len = sizeof(pdu[0]) + sizeof(opcode) +
sizeof(handle) + sizeof(status);
- uint16_t u16;
if (len < min_len)
return 0;
- u16 = htobs(handle);
pdu[0] = ATT_OP_ERROR;
pdu[1] = opcode;
- memcpy(&pdu[2], &u16, sizeof(u16));
+ att_put_u16(handle, &pdu[2]);
pdu[4] = status;
return min_len;
--
1.8.3.2
^ permalink raw reply related
* [PATCH BlueZ 04/11] attrib: Remove unnecessary checks for PDU length on ATT encoding
From: Anderson Lizardo @ 2014-01-11 4:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1389415647-25831-1-git-send-email-anderson.lizardo@openbossa.org>
Both userspace and kernel enforce a minimum ATT MTU of 23 octets, which
is also used as minimum size for buffers passed to ATT encoding
functions. Therefore, it is unnecessary to perform these checks on ATT
requests that are guaranteed to fit into 23 octets.
Also document ATT parameter lengths where a constant is being used for
calculating the PDU length.
---
attrib/att.c | 131 +++++++++++++++++++++--------------------------------------
1 file changed, 46 insertions(+), 85 deletions(-)
diff --git a/attrib/att.c b/attrib/att.c
index d9ca709..a8f641a 100644
--- a/attrib/att.c
+++ b/attrib/att.c
@@ -123,29 +123,28 @@ struct att_data_list *att_data_list_alloc(uint16_t num, uint16_t len)
uint16_t enc_read_by_grp_req(uint16_t start, uint16_t end, bt_uuid_t *uuid,
uint8_t *pdu, size_t len)
{
- uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end);
- uint16_t length;
+ uint16_t uuid_len;
if (!uuid)
return 0;
if (uuid->type == BT_UUID16)
- length = 2;
+ uuid_len = 2;
else if (uuid->type == BT_UUID128)
- length = 16;
+ uuid_len = 16;
else
return 0;
- if (len < min_len + length)
- return 0;
-
+ /* Attribute Opcode (1 octet) */
pdu[0] = ATT_OP_READ_BY_GROUP_REQ;
+ /* Starting Handle (2 octets) */
att_put_u16(start, &pdu[1]);
+ /* Ending Handle (2 octets) */
att_put_u16(end, &pdu[3]);
-
+ /* Attribute Group Type (2 or 16 octet UUID) */
att_put_uuid(*uuid, &pdu[5]);
- return min_len + length;
+ return 5 + uuid_len;
}
uint16_t dec_read_by_grp_req(const uint8_t *pdu, size_t len, uint16_t *start,
@@ -244,9 +243,6 @@ uint16_t enc_find_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid,
if (uuid->type != BT_UUID16)
return 0;
- if (len < min_len)
- return 0;
-
if (vlen > len - min_len)
vlen = len - min_len;
@@ -309,7 +305,7 @@ uint16_t enc_find_by_type_resp(GSList *matches, uint8_t *pdu, size_t len)
GSList *l;
uint16_t offset;
- if (pdu == NULL || len < 5)
+ if (!pdu)
return 0;
pdu[0] = ATT_OP_FIND_BY_TYPE_RESP;
@@ -354,29 +350,28 @@ GSList *dec_find_by_type_resp(const uint8_t *pdu, size_t len)
uint16_t enc_read_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid,
uint8_t *pdu, size_t len)
{
- uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end);
- uint16_t length;
+ uint16_t uuid_len;
if (!uuid)
return 0;
if (uuid->type == BT_UUID16)
- length = 2;
+ uuid_len = 2;
else if (uuid->type == BT_UUID128)
- length = 16;
+ uuid_len = 16;
else
return 0;
- if (len < min_len + length)
- return 0;
-
+ /* Attribute Opcode (1 octet) */
pdu[0] = ATT_OP_READ_BY_TYPE_REQ;
+ /* Starting Handle (2 octets) */
att_put_u16(start, &pdu[1]);
+ /* Ending Handle (2 octets) */
att_put_u16(end, &pdu[3]);
-
+ /* Attribute Type (2 or 16 octet UUID) */
att_put_uuid(*uuid, &pdu[5]);
- return min_len + length;
+ return 5 + uuid_len;
}
uint16_t dec_read_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start,
@@ -468,9 +463,6 @@ uint16_t enc_write_cmd(uint16_t handle, const uint8_t *value, size_t vlen,
if (pdu == NULL)
return 0;
- if (len < min_len)
- return 0;
-
if (vlen > len - min_len)
vlen = len - min_len;
@@ -517,9 +509,6 @@ uint16_t enc_write_req(uint16_t handle, const uint8_t *value, size_t vlen,
if (pdu == NULL)
return 0;
- if (len < min_len)
- return 0;
-
if (vlen > len - min_len)
vlen = len - min_len;
@@ -582,37 +571,31 @@ uint16_t dec_write_resp(const uint8_t *pdu, size_t len)
uint16_t enc_read_req(uint16_t handle, uint8_t *pdu, size_t len)
{
- const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle);
-
if (pdu == NULL)
return 0;
- if (len < min_len)
- return 0;
-
+ /* Attribute Opcode (1 octet) */
pdu[0] = ATT_OP_READ_REQ;
+ /* Attribute Handle (2 octets) */
att_put_u16(handle, &pdu[1]);
- return min_len;
+ return 3;
}
uint16_t enc_read_blob_req(uint16_t handle, uint16_t offset, uint8_t *pdu,
size_t len)
{
- const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle) +
- sizeof(offset);
-
if (pdu == NULL)
return 0;
- if (len < min_len)
- return 0;
-
+ /* Attribute Opcode (1 octet) */
pdu[0] = ATT_OP_READ_BLOB_REQ;
+ /* Attribute Handle (2 octets) */
att_put_u16(handle, &pdu[1]);
+ /* Value Offset (2 octets) */
att_put_u16(offset, &pdu[3]);
- return min_len;
+ return 5;
}
uint16_t dec_read_req(const uint8_t *pdu, size_t len, uint16_t *handle)
@@ -721,36 +704,32 @@ ssize_t dec_read_resp(const uint8_t *pdu, size_t len, uint8_t *value,
uint16_t enc_error_resp(uint8_t opcode, uint16_t handle, uint8_t status,
uint8_t *pdu, size_t len)
{
- const uint16_t min_len = sizeof(pdu[0]) + sizeof(opcode) +
- sizeof(handle) + sizeof(status);
-
- if (len < min_len)
- return 0;
-
+ /* Attribute Opcode (1 octet) */
pdu[0] = ATT_OP_ERROR;
+ /* Request Opcode In Error (1 octet) */
pdu[1] = opcode;
+ /* Attribute Handle In Error (2 octets) */
att_put_u16(handle, &pdu[2]);
+ /* Error Code (1 octet) */
pdu[4] = status;
- return min_len;
+ return 5;
}
uint16_t enc_find_info_req(uint16_t start, uint16_t end, uint8_t *pdu,
size_t len)
{
- const uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end);
-
if (pdu == NULL)
return 0;
- if (len < min_len)
- return 0;
-
+ /* Attribute Opcode (1 octet) */
pdu[0] = ATT_OP_FIND_INFO_REQ;
+ /* Starting Handle (2 octets) */
att_put_u16(start, &pdu[1]);
+ /* Ending Handle (2 octets) */
att_put_u16(end, &pdu[3]);
- return min_len;
+ return 5;
}
uint16_t dec_find_info_req(const uint8_t *pdu, size_t len, uint16_t *start,
@@ -907,33 +886,26 @@ uint16_t dec_indication(const uint8_t *pdu, size_t len, uint16_t *handle,
uint16_t enc_confirmation(uint8_t *pdu, size_t len)
{
- const uint16_t min_len = sizeof(pdu[0]);
-
if (pdu == NULL)
return 0;
- if (len < min_len)
- return 0;
-
+ /* Attribute Opcode (1 octet) */
pdu[0] = ATT_OP_HANDLE_CNF;
- return min_len;
+ return 1;
}
uint16_t enc_mtu_req(uint16_t mtu, uint8_t *pdu, size_t len)
{
- const uint16_t min_len = sizeof(pdu[0]) + sizeof(mtu);
-
if (pdu == NULL)
return 0;
- if (len < min_len)
- return 0;
-
+ /* Attribute Opcode (1 octet) */
pdu[0] = ATT_OP_MTU_REQ;
+ /* Client Rx MTU (2 octets) */
att_put_u16(mtu, &pdu[1]);
- return min_len;
+ return 3;
}
uint16_t dec_mtu_req(const uint8_t *pdu, size_t len, uint16_t *mtu)
@@ -959,18 +931,15 @@ uint16_t dec_mtu_req(const uint8_t *pdu, size_t len, uint16_t *mtu)
uint16_t enc_mtu_resp(uint16_t mtu, uint8_t *pdu, size_t len)
{
- const uint16_t min_len = sizeof(pdu[0]) + sizeof(mtu);
-
if (pdu == NULL)
return 0;
- if (len < min_len)
- return 0;
-
+ /* Attribute Opcode (1 octet) */
pdu[0] = ATT_OP_MTU_RESP;
+ /* Server Rx MTU (2 octets) */
att_put_u16(mtu, &pdu[1]);
- return min_len;
+ return 3;
}
uint16_t dec_mtu_resp(const uint8_t *pdu, size_t len, uint16_t *mtu)
@@ -1004,9 +973,6 @@ uint16_t enc_prep_write_req(uint16_t handle, uint16_t offset,
if (pdu == NULL)
return 0;
- if (len < min_len)
- return 0;
-
if (vlen > len - min_len)
vlen = len - min_len;
@@ -1060,9 +1026,6 @@ uint16_t enc_prep_write_resp(uint16_t handle, uint16_t offset,
if (pdu == NULL)
return 0;
- if (len < min_len)
- return 0;
-
if (vlen > len - min_len)
vlen = len - min_len;
@@ -1107,21 +1070,18 @@ uint16_t dec_prep_write_resp(const uint8_t *pdu, size_t len, uint16_t *handle,
uint16_t enc_exec_write_req(uint8_t flags, uint8_t *pdu, size_t len)
{
- const uint16_t min_len = sizeof(pdu[0]) + sizeof(flags);
-
if (pdu == NULL)
return 0;
- if (len < min_len)
- return 0;
-
if (flags > 1)
return 0;
+ /* Attribute Opcode (1 octet) */
pdu[0] = ATT_OP_EXEC_WRITE_REQ;
+ /* Flags (1 octet) */
pdu[1] = flags;
- return min_len;
+ return 2;
}
uint16_t dec_exec_write_req(const uint8_t *pdu, size_t len, uint8_t *flags)
@@ -1150,9 +1110,10 @@ uint16_t enc_exec_write_resp(uint8_t *pdu)
if (pdu == NULL)
return 0;
+ /* Attribute Opcode (1 octet) */
pdu[0] = ATT_OP_EXEC_WRITE_RESP;
- return sizeof(pdu[0]);
+ return 1;
}
uint16_t dec_exec_write_resp(const uint8_t *pdu, size_t len)
--
1.8.3.2
^ permalink raw reply related
* [PATCH BlueZ 05/11] attrib: Fix PDU length check for Read by Group Type Request
From: Anderson Lizardo @ 2014-01-11 4:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1389415647-25831-1-git-send-email-anderson.lizardo@openbossa.org>
PDU length must be either 7 or 21 octets.
---
attrib/att.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/attrib/att.c b/attrib/att.c
index a8f641a..472c25c 100644
--- a/attrib/att.c
+++ b/attrib/att.c
@@ -161,7 +161,7 @@ uint16_t dec_read_by_grp_req(const uint8_t *pdu, size_t len, uint16_t *start,
if (pdu[0] != ATT_OP_READ_BY_GROUP_REQ)
return 0;
- if (len < min_len + 2)
+ if (len != (min_len + 2) && len != (min_len + 16))
return 0;
*start = att_get_u16(&pdu[1]);
--
1.8.3.2
^ permalink raw reply related
* [PATCH BlueZ 06/11] attrib: Add extra PDU checks when decoding Read by Group Type Response
From: Anderson Lizardo @ 2014-01-11 4:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1389415647-25831-1-git-send-email-anderson.lizardo@openbossa.org>
These checks are needed to avoid invalid memory access on bogus PDUs.
---
attrib/att.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/attrib/att.c b/attrib/att.c
index 472c25c..777ef46 100644
--- a/attrib/att.c
+++ b/attrib/att.c
@@ -211,7 +211,25 @@ struct att_data_list *dec_read_by_grp_resp(const uint8_t *pdu, size_t len)
if (pdu[0] != ATT_OP_READ_BY_GROUP_RESP)
return NULL;
+ /* PDU must contain at least:
+ * - Attribute Opcode (1 octet)
+ * - Length (1 octet)
+ * - Attribute Data List (at least one entry):
+ * - Attribute Handle (2 octets)
+ * - End Group Handle (2 octets)
+ * - Attribute Value (at least 1 octet) */
+ if (len < 7)
+ return NULL;
+
elen = pdu[1];
+ /* Minimum Attribute Data List size */
+ if (elen < 5)
+ return NULL;
+
+ /* Reject incomplete Attribute Data List */
+ if ((len - 2) % elen)
+ return NULL;
+
num = (len - 2) / elen;
list = att_data_list_alloc(num, elen);
if (list == NULL)
--
1.8.3.2
^ permalink raw reply related
* [PATCH BlueZ 07/11] attrib: Remove unnecessary NULL checks on dec_find_by_type_req()
From: Anderson Lizardo @ 2014-01-11 4:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1389415647-25831-1-git-send-email-anderson.lizardo@openbossa.org>
Just assume that the caller will pass non-NULL pointers as arguments
(which is true for the only current caller of this function).
---
attrib/att.c | 24 +++++++++---------------
1 file changed, 9 insertions(+), 15 deletions(-)
diff --git a/attrib/att.c b/attrib/att.c
index 777ef46..435a26d 100644
--- a/attrib/att.c
+++ b/attrib/att.c
@@ -291,30 +291,24 @@ uint16_t dec_find_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start,
if (len < min_len)
return 0;
+ /* Attribute Opcode (1 octet) */
if (pdu[0] != ATT_OP_FIND_BY_TYPE_REQ)
return 0;
- /* First requested handle number */
- if (start)
- *start = att_get_u16(&pdu[1]);
-
- /* Last requested handle number */
- if (end)
- *end = att_get_u16(&pdu[3]);
-
- /* Always UUID16 */
- if (uuid)
- *uuid = att_get_uuid16(&pdu[5]);
+ /* First requested handle number (2 octets) */
+ *start = att_get_u16(&pdu[1]);
+ /* Last requested handle number (2 octets) */
+ *end = att_get_u16(&pdu[3]);
+ /* 16-bit UUID to find (2 octets) */
+ *uuid = att_get_uuid16(&pdu[5]);
valuelen = len - min_len;
+ *vlen = valuelen;
/* Attribute value to find */
- if (valuelen > 0 && value)
+ if (valuelen > 0)
memcpy(value, pdu + min_len, valuelen);
- if (vlen)
- *vlen = valuelen;
-
return len;
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH BlueZ 08/11] attrib: Remove unnecessary local variables from dec_find_by_type_req()
From: Anderson Lizardo @ 2014-01-11 4:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1389415647-25831-1-git-send-email-anderson.lizardo@openbossa.org>
Use number instead of "min_len", which is easier to review (with help of
the documented parameter sizes).
valuelen is redundant as *vlen can be used directly.
---
attrib/att.c | 14 ++++----------
1 file changed, 4 insertions(+), 10 deletions(-)
diff --git a/attrib/att.c b/attrib/att.c
index 435a26d..d367918 100644
--- a/attrib/att.c
+++ b/attrib/att.c
@@ -281,14 +281,10 @@ uint16_t dec_find_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start,
uint16_t *end, bt_uuid_t *uuid,
uint8_t *value, size_t *vlen)
{
- size_t valuelen;
- uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) +
- sizeof(*end) + sizeof(uint16_t);
-
if (pdu == NULL)
return 0;
- if (len < min_len)
+ if (len < 7)
return 0;
/* Attribute Opcode (1 octet) */
@@ -302,12 +298,10 @@ uint16_t dec_find_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start,
/* 16-bit UUID to find (2 octets) */
*uuid = att_get_uuid16(&pdu[5]);
- valuelen = len - min_len;
- *vlen = valuelen;
-
/* Attribute value to find */
- if (valuelen > 0)
- memcpy(value, pdu + min_len, valuelen);
+ *vlen = len - 7;
+ if (*vlen > 0)
+ memcpy(value, pdu + 7, *vlen);
return len;
}
--
1.8.3.2
^ permalink raw reply related
* [PATCH BlueZ 09/11] attrib: Reject incomplete PDU in dec_find_by_type_resp()
From: Anderson Lizardo @ 2014-01-11 4:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1389415647-25831-1-git-send-email-anderson.lizardo@openbossa.org>
Otherwise, an incomplete PDU may be silently accepted (with any
remaining data discarded).
---
attrib/att.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/attrib/att.c b/attrib/att.c
index d367918..c279b2c 100644
--- a/attrib/att.c
+++ b/attrib/att.c
@@ -334,12 +334,21 @@ GSList *dec_find_by_type_resp(const uint8_t *pdu, size_t len)
GSList *matches;
off_t offset;
+ /* PDU should contain at least:
+ * - Attribute Opcode (1 octet)
+ * - Handles Information List (at least one entry):
+ * - Found Attribute Handle (2 octets)
+ * - Group End Handle (2 octets) */
if (pdu == NULL || len < 5)
return NULL;
if (pdu[0] != ATT_OP_FIND_BY_TYPE_RESP)
return NULL;
+ /* Reject incomplete Handles Information List */
+ if ((len - 1) % 4)
+ return NULL;
+
for (offset = 1, matches = NULL;
len >= (offset + sizeof(uint16_t) * 2);
offset += sizeof(uint16_t) * 2) {
--
1.8.3.2
^ permalink raw reply related
* [PATCH BlueZ 10/11] attrib: Fix PDU length check for Read by Type Request
From: Anderson Lizardo @ 2014-01-11 4:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1389415647-25831-1-git-send-email-anderson.lizardo@openbossa.org>
PDU length must be either 7 or 21 octets.
---
attrib/att.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/attrib/att.c b/attrib/att.c
index c279b2c..183390b 100644
--- a/attrib/att.c
+++ b/attrib/att.c
@@ -400,7 +400,7 @@ uint16_t dec_read_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start,
if (start == NULL || end == NULL || uuid == NULL)
return 0;
- if (len < min_len + 2)
+ if (len != (min_len + 2) && len != (min_len + 16))
return 0;
if (pdu[0] != ATT_OP_READ_BY_TYPE_REQ)
--
1.8.3.2
^ permalink raw reply related
* [PATCH BlueZ 11/11] attrib: Add extra PDU checks when decoding Read by Type Response
From: Anderson Lizardo @ 2014-01-11 4:47 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anderson Lizardo
In-Reply-To: <1389415647-25831-1-git-send-email-anderson.lizardo@openbossa.org>
These checks are needed to avoid invalid memory access on bogus PDUs.
---
attrib/att.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/attrib/att.c b/attrib/att.c
index 183390b..e28be25 100644
--- a/attrib/att.c
+++ b/attrib/att.c
@@ -454,7 +454,24 @@ struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, size_t len)
if (pdu[0] != ATT_OP_READ_BY_TYPE_RESP)
return NULL;
+ /* PDU must contain at least:
+ * - Attribute Opcode (1 octet)
+ * - Length (1 octet)
+ * - Attribute Data List (at least one entry):
+ * - Attribute Handle (2 octets)
+ * - Attribute Value (at least 1 octet) */
+ if (len < 5)
+ return NULL;
+
elen = pdu[1];
+ /* Minimum Attribute Data List size */
+ if (elen < 3)
+ return NULL;
+
+ /* Reject incomplete Attribute Data List */
+ if ((len - 2) % elen)
+ return NULL;
+
num = (len - 2) / elen;
list = att_data_list_alloc(num, elen);
if (list == NULL)
--
1.8.3.2
^ permalink raw reply related
* [PATCH BlueZ 1/6] audio/A2DP: Add implemention of audio Open command
From: Luiz Augusto von Dentz @ 2014-01-11 10:13 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
android/a2dp.c | 159 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 158 insertions(+), 1 deletion(-)
diff --git a/android/a2dp.c b/android/a2dp.c
index b59c53d..28b7406 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -52,9 +52,23 @@
static GIOChannel *server = NULL;
static GSList *devices = NULL;
+static GSList *endpoints = NULL;
static bdaddr_t adapter_addr;
static uint32_t record_id = 0;
+struct a2dp_preset {
+ void *data;
+ int8_t len;
+};
+
+struct a2dp_endpoint {
+ uint8_t id;
+ uint8_t codec;
+ struct avdtp_local_sep *sep;
+ struct a2dp_preset *caps;
+ GSList *presets;
+};
+
struct a2dp_device {
bdaddr_t dst;
uint8_t state;
@@ -70,6 +84,29 @@ static int device_cmp(gconstpointer s, gconstpointer user_data)
return bacmp(&dev->dst, dst);
}
+static void preset_free(void *data)
+{
+ struct a2dp_preset *preset = data;
+
+ g_free(preset->data);
+ g_free(preset);
+}
+
+static void unregister_endpoint(void *data)
+{
+ struct a2dp_endpoint *endpoint = data;
+
+ if (endpoint->sep)
+ avdtp_unregister_sep(endpoint->sep);
+
+ if (endpoint->caps)
+ preset_free(endpoint->caps);
+
+ g_slist_free_full(endpoint->presets, preset_free);
+
+ g_free(endpoint);
+}
+
static void a2dp_device_free(struct a2dp_device *dev)
{
if (dev->session)
@@ -354,10 +391,127 @@ static sdp_record_t *a2dp_record(void)
return record;
}
+static gboolean sep_getcap_ind(struct avdtp *session,
+ struct avdtp_local_sep *sep,
+ GSList **caps, uint8_t *err,
+ void *user_data)
+{
+ struct a2dp_endpoint *endpoint = user_data;
+ struct a2dp_preset *cap = endpoint->presets->data;
+ struct avdtp_service_capability *media_transport, *media_codec;
+ struct avdtp_media_codec_capability *codec_caps;
+
+ *caps = NULL;
+
+ media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
+ NULL, 0);
+
+ *caps = g_slist_append(*caps, media_transport);
+
+ codec_caps = g_malloc0(sizeof(*codec_caps) + sizeof(cap));
+ codec_caps->media_type = AVDTP_MEDIA_TYPE_AUDIO;
+ codec_caps->media_codec_type = endpoint->codec;
+ memcpy(codec_caps->data, cap->data, cap->len);
+
+ media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, codec_caps,
+ sizeof(*codec_caps) + sizeof(cap));
+
+ *caps = g_slist_append(*caps, media_codec);
+ g_free(codec_caps);
+
+ return TRUE;
+}
+
+static struct avdtp_sep_ind sep_ind = {
+ .get_capability = sep_getcap_ind,
+};
+
+static uint8_t register_endpoint(const uint8_t *uuid, uint8_t codec,
+ GSList *presets)
+{
+ struct a2dp_endpoint *endpoint;
+
+ /* FIXME: Add proper check for uuid */
+
+ endpoint = g_new0(struct a2dp_endpoint, 1);
+ endpoint->id = g_slist_length(endpoints) + 1;
+ endpoint->codec = codec;
+ endpoint->sep = avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE,
+ AVDTP_MEDIA_TYPE_AUDIO,
+ codec, FALSE, &sep_ind, NULL,
+ endpoint);
+ endpoint->caps = g_slist_nth_data(presets->data, 0);
+ endpoint->presets = g_slist_copy(g_slist_nth(presets, 1));
+
+ endpoints = g_slist_append(endpoints, endpoint);
+
+ return endpoint->id;
+}
+
+static GSList *parse_presets(const struct audio_preset *p, uint8_t count,
+ uint16_t len)
+{
+ GSList *l = NULL;
+ uint8_t i;
+
+ for (i = 0; count > i; i++) {
+ struct a2dp_preset *preset;
+
+ if (len < sizeof(struct audio_preset)) {
+ DBG("Invalid preset index %u", i);
+ break;
+ }
+
+ len -= sizeof(struct audio_preset);
+ if (len == 0 || len < p->len) {
+ DBG("Invalid preset size of %u for index %u", len, i);
+ break;
+ }
+
+ preset = g_new0(struct a2dp_preset, 1);
+ preset->len = p->len;
+ preset->data = g_memdup(p->data, preset->len);
+ l = g_slist_append(l, preset);
+
+ len -= preset->len;
+ p += sizeof(struct audio_preset) + preset->len;
+ }
+
+ return l;
+}
+
static void bt_audio_open(const void *buf, uint16_t len)
{
- DBG("Not Implemented");
+ const struct audio_cmd_open *cmd = buf;
+ struct audio_rsp_open rsp;
+ GSList *presets;
+
+ DBG("");
+ if (cmd->presets == 0) {
+ error("No audio presets found");
+ goto failed;
+ }
+
+ presets = parse_presets(cmd->preset, cmd->presets, len - sizeof(*cmd));
+ if (!presets) {
+ error("No audio presets found");
+ goto failed;
+ }
+
+ rsp.id = register_endpoint(cmd->uuid, cmd->codec, presets);
+ g_slist_free(presets);
+
+ if (rsp.id == 0) {
+ error("Unable to register endpoint");
+ goto failed;
+ }
+
+ audio_ipc_send_rsp_full(AUDIO_OP_OPEN, sizeof(rsp), &rsp, -1);
+
+ return;
+
+failed:
audio_ipc_send_rsp(AUDIO_OP_OPEN, AUDIO_STATUS_FAILED);
}
@@ -471,6 +625,9 @@ void bt_a2dp_unregister(void)
{
DBG("");
+ g_slist_free_full(endpoints, unregister_endpoint);
+ endpoints = NULL;
+
g_slist_foreach(devices, a2dp_device_disconnected, NULL);
devices = NULL;
--
1.8.4.2
^ permalink raw reply related
* [PATCH BlueZ 2/6] audio/A2DP: Add implemention of audio Close command
From: Luiz Augusto von Dentz @ 2014-01-11 10:13 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1389435216-29040-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
android/a2dp.c | 30 ++++++++++++++++++++++++++++--
1 file changed, 28 insertions(+), 2 deletions(-)
diff --git a/android/a2dp.c b/android/a2dp.c
index 28b7406..8649cf3 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -515,11 +515,37 @@ failed:
audio_ipc_send_rsp(AUDIO_OP_OPEN, AUDIO_STATUS_FAILED);
}
+static struct a2dp_endpoint *find_endpoint(uint8_t id)
+{
+ GSList *l;
+
+ for (l = endpoints; l; l = g_slist_next(l)) {
+ struct a2dp_endpoint *endpoint = l->data;
+
+ if (endpoint->id == id)
+ return endpoint;
+ }
+
+ return NULL;
+}
+
static void bt_audio_close(const void *buf, uint16_t len)
{
- DBG("Not Implemented");
+ const struct audio_cmd_close *cmd = buf;
+ struct a2dp_endpoint *endpoint;
+
+ DBG("");
+
+ endpoint = find_endpoint(cmd->id);
+ if (!endpoint) {
+ error("Unable to find endpoint %u", cmd->id);
+ audio_ipc_send_rsp(AUDIO_OP_CLOSE, HAL_STATUS_FAILED);
+ return;
+ }
+
+ unregister_endpoint(endpoint);
- audio_ipc_send_rsp(AUDIO_OP_CLOSE, HAL_STATUS_FAILED);
+ audio_ipc_send_rsp(AUDIO_OP_CLOSE, HAL_STATUS_SUCCESS);
}
static void bt_stream_open(const void *buf, uint16_t len)
--
1.8.4.2
^ permalink raw reply related
* [PATCH BlueZ 3/6] audio/A2DP: Add implemention of audio Open Stream command
From: Luiz Augusto von Dentz @ 2014-01-11 10:13 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1389435216-29040-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
android/a2dp.c | 199 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 197 insertions(+), 2 deletions(-)
diff --git a/android/a2dp.c b/android/a2dp.c
index 8649cf3..479cb71 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -37,6 +37,7 @@
#include "lib/bluetooth.h"
#include "lib/sdp.h"
#include "lib/sdp_lib.h"
+#include "profiles/audio/a2dp-codecs.h"
#include "log.h"
#include "a2dp.h"
#include "hal-msg.h"
@@ -53,6 +54,7 @@
static GIOChannel *server = NULL;
static GSList *devices = NULL;
static GSList *endpoints = NULL;
+static GSList *setups = NULL;
static bdaddr_t adapter_addr;
static uint32_t record_id = 0;
@@ -67,6 +69,7 @@ struct a2dp_endpoint {
struct avdtp_local_sep *sep;
struct a2dp_preset *caps;
GSList *presets;
+ struct a2dp_config *config;
};
struct a2dp_device {
@@ -76,6 +79,13 @@ struct a2dp_device {
struct avdtp *session;
};
+struct a2dp_setup {
+ struct a2dp_device *dev;
+ struct a2dp_endpoint *endpoint;
+ struct a2dp_preset *preset;
+ struct avdtp_stream *stream;
+};
+
static int device_cmp(gconstpointer s, gconstpointer user_data)
{
const struct a2dp_device *dev = s;
@@ -422,8 +432,160 @@ static gboolean sep_getcap_ind(struct avdtp *session,
return TRUE;
}
+static int sbc_check_config(struct a2dp_endpoint *endpoint,
+ struct a2dp_preset *conf)
+{
+ a2dp_sbc_t *caps, *config;
+
+ if (conf->len != sizeof(a2dp_sbc_t)) {
+ error("SBC: Invalid configuration size (%u)", conf->len);
+ return -EINVAL;
+ }
+
+ caps = endpoint->caps->data;
+ config = conf->data;
+
+ if (!(caps->frequency & config->frequency)) {
+ error("SBC: Unsupported frequency (%u) by endpoint",
+ config->frequency);
+ return -EINVAL;
+ }
+
+ if (!(caps->channel_mode & config->channel_mode)) {
+ error("SBC: Unsupported channel mode (%u) by endpoint",
+ config->channel_mode);
+ return -EINVAL;
+ }
+
+ if (!(caps->block_length & config->block_length)) {
+ error("SBC: Unsupported block length (%u) by endpoint",
+ config->block_length);
+ return -EINVAL;
+ }
+
+ if (!(caps->allocation_method & config->allocation_method)) {
+ error("SBC: Unsupported allocation method (%u) by endpoint",
+ config->block_length);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int check_config(struct a2dp_endpoint *endpoint,
+ struct a2dp_preset *config)
+{
+ GSList *l;
+
+ for (l = endpoint->presets; l; l = g_slist_next(l)) {
+ struct a2dp_preset *preset = l->data;
+
+ if (preset->len != config->len)
+ continue;
+
+ if (memcmp(preset->data, config->data, preset->len) == 0)
+ return 0;
+ }
+
+ /* Codec specific */
+ switch (endpoint->codec) {
+ case A2DP_CODEC_SBC:
+ return sbc_check_config(endpoint, config);
+ default:
+ return -EINVAL;
+ }
+}
+
+static struct a2dp_device *find_device_by_session(struct avdtp *session)
+{
+ GSList *l;
+
+ for (l = devices; l; l = g_slist_next(l)) {
+ struct a2dp_device *dev = l->data;
+
+ if (dev->session == session)
+ return dev;
+ }
+
+ return NULL;
+}
+
+static void setup_free(void *data)
+{
+ struct a2dp_setup *setup = data;
+
+ preset_free(setup->preset);
+ g_free(setup);
+}
+
+static void setup_add(struct a2dp_device *dev, struct a2dp_endpoint *endpoint,
+ struct a2dp_preset *preset, struct avdtp_stream *stream)
+{
+ struct a2dp_setup *setup;
+
+ setup = g_new0(struct a2dp_setup, 1);
+ setup->dev = dev;
+ setup->endpoint = endpoint;
+ setup->preset = preset;
+ setup->stream = stream;
+ setups = g_slist_append(setups, setup);
+}
+
+static gboolean sep_setconf_ind(struct avdtp *session,
+ struct avdtp_local_sep *sep,
+ struct avdtp_stream *stream,
+ GSList *caps,
+ avdtp_set_configuration_cb cb,
+ void *user_data)
+{
+ struct a2dp_endpoint *endpoint = user_data;
+ struct a2dp_device *dev;
+ struct a2dp_preset *preset = NULL;
+
+ DBG("");
+
+ dev = find_device_by_session(session);
+ if (!dev) {
+ error("Unable to find device for session %p", session);
+ return FALSE;
+ }
+
+ for (; caps != NULL; caps = g_slist_next(caps)) {
+ struct avdtp_service_capability *cap = caps->data;
+ struct avdtp_media_codec_capability *codec;
+
+ if (cap->category == AVDTP_DELAY_REPORTING)
+ return FALSE;
+
+ if (cap->category != AVDTP_MEDIA_CODEC)
+ continue;
+
+ codec = (struct avdtp_media_codec_capability *) cap->data;
+
+ if (codec->media_codec_type != endpoint->codec)
+ return FALSE;
+
+ preset = g_new0(struct a2dp_preset, 1);
+ preset->len = cap->length - sizeof(*codec);
+ preset->data = g_memdup(codec->data, preset->len);
+
+ if (check_config(endpoint, preset) < 0) {
+ preset_free(preset);
+ return FALSE;
+ }
+ }
+
+ if (!preset)
+ return FALSE;
+
+ setup_add(dev, endpoint, preset, stream);
+
+ return TRUE;
+}
+
static struct avdtp_sep_ind sep_ind = {
.get_capability = sep_getcap_ind,
+ .set_configuration = sep_setconf_ind,
};
static uint8_t register_endpoint(const uint8_t *uuid, uint8_t codec,
@@ -548,11 +710,41 @@ static void bt_audio_close(const void *buf, uint16_t len)
audio_ipc_send_rsp(AUDIO_OP_CLOSE, HAL_STATUS_SUCCESS);
}
+static struct a2dp_setup *find_setup(uint8_t id)
+{
+ GSList *l;
+
+ for (l = setups; l; l = g_slist_next(l)) {
+ struct a2dp_setup *setup = l->data;
+
+ if (setup->endpoint->id == id)
+ return setup;
+ }
+
+ return NULL;
+}
+
static void bt_stream_open(const void *buf, uint16_t len)
{
- DBG("Not Implemented");
+ const struct audio_cmd_open_stream *cmd = buf;
+ struct audio_rsp_open_stream *rsp;
+ struct a2dp_setup *setup;
+
+ DBG("");
- audio_ipc_send_rsp(AUDIO_OP_OPEN_STREAM, AUDIO_STATUS_FAILED);
+ setup = find_setup(cmd->id);
+ if (!setup) {
+ error("Unable to find stream for endpoint %u", cmd->id);
+ audio_ipc_send_rsp(AUDIO_OP_OPEN_STREAM, HAL_STATUS_FAILED);
+ return;
+ }
+
+ len = sizeof(*rsp) + setup->preset->len;
+ rsp = g_malloc0(sizeof(*rsp) + setup->preset->len);
+ rsp->preset->len = setup->preset->len;
+ memcpy(rsp->preset->data, setup->preset->data, setup->preset->len);
+
+ audio_ipc_send_rsp_full(AUDIO_OP_OPEN_STREAM, len, rsp, -1);
}
static void bt_stream_close(const void *buf, uint16_t len)
@@ -651,6 +843,9 @@ void bt_a2dp_unregister(void)
{
DBG("");
+ g_slist_free_full(setups, setup_free);
+ setups = NULL;
+
g_slist_free_full(endpoints, unregister_endpoint);
endpoints = NULL;
--
1.8.4.2
^ permalink raw reply related
* [PATCH BlueZ 4/6] audio/A2DP: Add implemention of audio Close Stream command
From: Luiz Augusto von Dentz @ 2014-01-11 10:13 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1389435216-29040-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
android/a2dp.c | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/android/a2dp.c b/android/a2dp.c
index 479cb71..4e4f43f 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -749,8 +749,29 @@ static void bt_stream_open(const void *buf, uint16_t len)
static void bt_stream_close(const void *buf, uint16_t len)
{
- DBG("Not Implemented");
+ const struct audio_cmd_close_stream *cmd = buf;
+ struct a2dp_setup *setup;
+ int err;
+ DBG("");
+
+ setup = find_setup(cmd->id);
+ if (!setup) {
+ error("Unable to find stream for endpoint %u", cmd->id);
+ goto failed;
+ }
+
+ err = avdtp_close(setup->dev->session, setup->stream, FALSE);
+ if (err < 0) {
+ error("avdtp_close: %s", strerror(-err));
+ goto failed;
+ }
+
+ audio_ipc_send_rsp(AUDIO_OP_CLOSE_STREAM, AUDIO_STATUS_SUCCESS);
+
+ return;
+
+failed:
audio_ipc_send_rsp(AUDIO_OP_CLOSE_STREAM, AUDIO_STATUS_FAILED);
}
--
1.8.4.2
^ permalink raw reply related
* [PATCH BlueZ 5/6] audio/A2DP: Add implemention of audio Resume Stream command
From: Luiz Augusto von Dentz @ 2014-01-11 10:13 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1389435216-29040-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
android/a2dp.c | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/android/a2dp.c b/android/a2dp.c
index 4e4f43f..2d886e9 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -777,8 +777,29 @@ failed:
static void bt_stream_resume(const void *buf, uint16_t len)
{
- DBG("Not Implemented");
+ const struct audio_cmd_resume_stream *cmd = buf;
+ struct a2dp_setup *setup;
+ int err;
+
+ DBG("");
+ setup = find_setup(cmd->id);
+ if (!setup) {
+ error("Unable to find stream for endpoint %u", cmd->id);
+ goto failed;
+ }
+
+ err = avdtp_start(setup->dev->session, setup->stream);
+ if (err < 0) {
+ error("avdtp_start: %s", strerror(-err));
+ goto failed;
+ }
+
+ audio_ipc_send_rsp(AUDIO_OP_RESUME_STREAM, AUDIO_STATUS_SUCCESS);
+
+ return;
+
+failed:
audio_ipc_send_rsp(AUDIO_OP_RESUME_STREAM, AUDIO_STATUS_FAILED);
}
--
1.8.4.2
^ permalink raw reply related
* [PATCH BlueZ 6/6] audio/A2DP: Add implemention of audio Suspend Stream command
From: Luiz Augusto von Dentz @ 2014-01-11 10:13 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1389435216-29040-1-git-send-email-luiz.dentz@gmail.com>
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
---
android/a2dp.c | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/android/a2dp.c b/android/a2dp.c
index 2d886e9..8d7d554 100644
--- a/android/a2dp.c
+++ b/android/a2dp.c
@@ -805,8 +805,29 @@ failed:
static void bt_stream_suspend(const void *buf, uint16_t len)
{
- DBG("Not Implemented");
+ const struct audio_cmd_suspend_stream *cmd = buf;
+ struct a2dp_setup *setup;
+ int err;
+
+ DBG("");
+
+ setup = find_setup(cmd->id);
+ if (!setup) {
+ error("Unable to find stream for endpoint %u", cmd->id);
+ goto failed;
+ }
+
+ err = avdtp_suspend(setup->dev->session, setup->stream);
+ if (err < 0) {
+ error("avdtp_suspend: %s", strerror(-err));
+ goto failed;
+ }
+ audio_ipc_send_rsp(AUDIO_OP_SUSPEND_STREAM, AUDIO_STATUS_SUCCESS);
+
+ return;
+
+failed:
audio_ipc_send_rsp(AUDIO_OP_SUSPEND_STREAM, AUDIO_STATUS_FAILED);
}
--
1.8.4.2
^ permalink raw reply related
* Re: [PATCH BlueZ 01/11] attrib: Modify gatt_cb_t signature
From: Johan Hedberg @ 2014-01-11 16:56 UTC (permalink / raw)
To: Anderson Lizardo; +Cc: linux-bluetooth
In-Reply-To: <1389415647-25831-1-git-send-email-anderson.lizardo@openbossa.org>
Hi Lizardo,
On Sat, Jan 11, 2014, Anderson Lizardo wrote:
> Use standard C types instead of GLib ones (which are unnecessary here)
> and move the "status" parameter to the first position, so it is
> consistent with other callbacks.
> ---
> attrib/gatt.c | 10 +++++-----
> attrib/gatt.h | 2 +-
> attrib/gatttool.c | 9 ++++-----
> attrib/interactive.c | 9 ++++-----
> profiles/cyclingspeed/cyclingspeed.c | 2 +-
> profiles/deviceinfo/deviceinfo.c | 4 ++--
> profiles/gatt/gas.c | 4 ++--
> profiles/heartrate/heartrate.c | 2 +-
> profiles/input/hog.c | 6 +++---
> profiles/proximity/monitor.c | 12 ++++++------
> profiles/scanparam/scan.c | 7 +++----
> profiles/thermometer/thermometer.c | 4 ++--
> src/device.c | 5 ++---
> 13 files changed, 36 insertions(+), 40 deletions(-)
All patches in this set have been applied. Thanks.
Johan
^ permalink raw reply
* Re: [PATCH BlueZ 1/6] audio/A2DP: Add implemention of audio Open command
From: Szymon Janc @ 2014-01-11 19:14 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: linux-bluetooth
In-Reply-To: <1389435216-29040-1-git-send-email-luiz.dentz@gmail.com>
Hi Luiz,
On Saturday 11 January 2014 12:13:31 Luiz Augusto von Dentz wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> ---
> android/a2dp.c | 159
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed,
> 158 insertions(+), 1 deletion(-)
>
> diff --git a/android/a2dp.c b/android/a2dp.c
> index b59c53d..28b7406 100644
> --- a/android/a2dp.c
> +++ b/android/a2dp.c
> @@ -52,9 +52,23 @@
>
> static GIOChannel *server = NULL;
> static GSList *devices = NULL;
> +static GSList *endpoints = NULL;
> static bdaddr_t adapter_addr;
> static uint32_t record_id = 0;
>
> +struct a2dp_preset {
> + void *data;
> + int8_t len;
> +};
> +
> +struct a2dp_endpoint {
> + uint8_t id;
> + uint8_t codec;
> + struct avdtp_local_sep *sep;
> + struct a2dp_preset *caps;
> + GSList *presets;
> +};
> +
> struct a2dp_device {
> bdaddr_t dst;
> uint8_t state;
> @@ -70,6 +84,29 @@ static int device_cmp(gconstpointer s, gconstpointer
> user_data) return bacmp(&dev->dst, dst);
> }
>
> +static void preset_free(void *data)
> +{
> + struct a2dp_preset *preset = data;
> +
> + g_free(preset->data);
> + g_free(preset);
> +}
> +
> +static void unregister_endpoint(void *data)
> +{
> + struct a2dp_endpoint *endpoint = data;
> +
> + if (endpoint->sep)
> + avdtp_unregister_sep(endpoint->sep);
> +
> + if (endpoint->caps)
> + preset_free(endpoint->caps);
> +
> + g_slist_free_full(endpoint->presets, preset_free);
> +
> + g_free(endpoint);
> +}
> +
> static void a2dp_device_free(struct a2dp_device *dev)
> {
> if (dev->session)
> @@ -354,10 +391,127 @@ static sdp_record_t *a2dp_record(void)
> return record;
> }
>
> +static gboolean sep_getcap_ind(struct avdtp *session,
> + struct avdtp_local_sep *sep,
> + GSList **caps, uint8_t *err,
> + void *user_data)
> +{
> + struct a2dp_endpoint *endpoint = user_data;
> + struct a2dp_preset *cap = endpoint->presets->data;
> + struct avdtp_service_capability *media_transport, *media_codec;
> + struct avdtp_media_codec_capability *codec_caps;
> +
> + *caps = NULL;
> +
> + media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
> + NULL, 0);
> +
> + *caps = g_slist_append(*caps, media_transport);
> +
> + codec_caps = g_malloc0(sizeof(*codec_caps) + sizeof(cap));
Shouldn't this be cap->len instead of sizeof(cap) ?
> + codec_caps->media_type = AVDTP_MEDIA_TYPE_AUDIO;
> + codec_caps->media_codec_type = endpoint->codec;
> + memcpy(codec_caps->data, cap->data, cap->len);
> +
> + media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, codec_caps,
> + sizeof(*codec_caps) + sizeof(cap));
> +
> + *caps = g_slist_append(*caps, media_codec);
> + g_free(codec_caps);
> +
> + return TRUE;
> +}
> +
> +static struct avdtp_sep_ind sep_ind = {
> + .get_capability = sep_getcap_ind,
> +};
> +
> +static uint8_t register_endpoint(const uint8_t *uuid, uint8_t codec,
> + GSList *presets)
> +{
> + struct a2dp_endpoint *endpoint;
> +
> + /* FIXME: Add proper check for uuid */
> +
> + endpoint = g_new0(struct a2dp_endpoint, 1);
> + endpoint->id = g_slist_length(endpoints) + 1;
> + endpoint->codec = codec;
> + endpoint->sep = avdtp_register_sep(AVDTP_SEP_TYPE_SOURCE,
> + AVDTP_MEDIA_TYPE_AUDIO,
> + codec, FALSE, &sep_ind, NULL,
> + endpoint);
> + endpoint->caps = g_slist_nth_data(presets->data, 0);
> + endpoint->presets = g_slist_copy(g_slist_nth(presets, 1));
> +
> + endpoints = g_slist_append(endpoints, endpoint);
> +
> + return endpoint->id;
> +}
> +
> +static GSList *parse_presets(const struct audio_preset *p, uint8_t count,
> + uint16_t len)
> +{
> + GSList *l = NULL;
> + uint8_t i;
> +
> + for (i = 0; count > i; i++) {
> + struct a2dp_preset *preset;
> +
> + if (len < sizeof(struct audio_preset)) {
If Audio IPC command is malformed we should discard it, free list and return
NULL.
(I'm still not sure how daemon should behave if there is Audio IPC error,
possibly closing IPC socket and reset a2dp service state?)
> + DBG("Invalid preset index %u", i);
> + break;
> + }
> +
> + len -= sizeof(struct audio_preset);
> + if (len == 0 || len < p->len) {
> + DBG("Invalid preset size of %u for index %u", len, i);
> + break;
> + }
> +
> + preset = g_new0(struct a2dp_preset, 1);
> + preset->len = p->len;
> + preset->data = g_memdup(p->data, preset->len);
> + l = g_slist_append(l, preset);
> +
> + len -= preset->len;
> + p += sizeof(struct audio_preset) + preset->len;
> + }
> +
> + return l;
> +}
> +
> static void bt_audio_open(const void *buf, uint16_t len)
> {
> - DBG("Not Implemented");
> + const struct audio_cmd_open *cmd = buf;
> + struct audio_rsp_open rsp;
> + GSList *presets;
> +
> + DBG("");
>
> + if (cmd->presets == 0) {
> + error("No audio presets found");
> + goto failed;
> + }
> +
> + presets = parse_presets(cmd->preset, cmd->presets, len - sizeof(*cmd));
> + if (!presets) {
> + error("No audio presets found");
> + goto failed;
> + }
> +
> + rsp.id = register_endpoint(cmd->uuid, cmd->codec, presets);
> + g_slist_free(presets);
> +
> + if (rsp.id == 0) {
> + error("Unable to register endpoint");
> + goto failed;
> + }
> +
> + audio_ipc_send_rsp_full(AUDIO_OP_OPEN, sizeof(rsp), &rsp, -1);
> +
> + return;
> +
> +failed:
> audio_ipc_send_rsp(AUDIO_OP_OPEN, AUDIO_STATUS_FAILED);
> }
>
> @@ -471,6 +625,9 @@ void bt_a2dp_unregister(void)
> {
> DBG("");
>
> + g_slist_free_full(endpoints, unregister_endpoint);
> + endpoints = NULL;
> +
> g_slist_foreach(devices, a2dp_device_disconnected, NULL);
> devices = NULL;
--
Szymon K. Janc
szymon.janc@gmail.com
^ permalink raw reply
* [PATCH] Bluetooth: Track Secure Connections support of remote devices
From: Marcel Holtmann @ 2014-01-11 20:39 UTC (permalink / raw)
To: linux-bluetooth
It is important to know if Secure Connections support has been enabled
for a given remote device. The information is provided in the remote
host features page. So track this information and provide a simple
helper function to extract the status.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
include/net/bluetooth/hci_core.h | 8 ++++++++
net/bluetooth/hci_event.c | 3 +++
2 files changed, 11 insertions(+)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 66e96ebffe97..8d225e4ea2ce 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -448,6 +448,7 @@ enum {
HCI_CONN_LE_SMP_PEND,
HCI_CONN_MGMT_CONNECTED,
HCI_CONN_SSP_ENABLED,
+ HCI_CONN_SC_ENABLED,
HCI_CONN_POWER_SAVE,
HCI_CONN_REMOTE_OOB,
HCI_CONN_6LOWPAN,
@@ -460,6 +461,13 @@ static inline bool hci_conn_ssp_enabled(struct hci_conn *conn)
test_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
}
+static inline bool hci_conn_sc_enabled(struct hci_conn *conn)
+{
+ struct hci_dev *hdev = conn->hdev;
+ return test_bit(HCI_SC_ENABLED, &hdev->dev_flags) &&
+ test_bit(HCI_CONN_SC_ENABLED, &conn->flags);
+}
+
static inline void hci_conn_hash_add(struct hci_dev *hdev, struct hci_conn *c)
{
struct hci_conn_hash *h = &hdev->conn_hash;
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index da1eca1c43db..8c44bbe19add 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2898,6 +2898,9 @@ static void hci_remote_ext_features_evt(struct hci_dev *hdev,
* features do not indicate SSP support */
clear_bit(HCI_CONN_SSP_ENABLED, &conn->flags);
}
+
+ if (ev->features[0] & LMP_HOST_SC)
+ set_bit(HCI_CONN_SC_ENABLED, &conn->flags);
}
if (conn->state != BT_CONFIG)
--
1.8.4.2
^ permalink raw reply related
* [PATCH] Bluetooth: Introduce requirements for security level 4
From: Marcel Holtmann @ 2014-01-11 21:03 UTC (permalink / raw)
To: linux-bluetooth
The security level 4 is a new strong security requirement that is based
around 128-bit equivalent strength for link and encryption keys required
using FIPS approved algorithms. Which means that E0, SAFER+ and P-192
are not allowed. Only connections created with P-256 resulting from
using Secure Connections support are allowed.
This security level needs to be enforced when Secure Connection Only
mode is enabled for a controller or a service requires FIPS compliant
strong security. Currently it is not possible to enable either of
these two cases. This patch just puts in the foundation for being
able to handle security level 4 in the future.
It should be noted that devices or services with security level 4
requirement can only communicate using Bluetooth 4.1 controllers
with support for Secure Connections. There is no backward compatibilty
if used with older hardware.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
include/net/bluetooth/bluetooth.h | 1 +
net/bluetooth/hci_conn.c | 18 +++++++++++++-----
2 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h
index f4f9ee466791..904777c1cd24 100644
--- a/include/net/bluetooth/bluetooth.h
+++ b/include/net/bluetooth/bluetooth.h
@@ -65,6 +65,7 @@ struct bt_security {
#define BT_SECURITY_LOW 1
#define BT_SECURITY_MEDIUM 2
#define BT_SECURITY_HIGH 3
+#define BT_SECURITY_FIPS 4
#define BT_DEFER_SETUP 7
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index cf96b3438a91..0266bd8e4913 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -800,10 +800,17 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
if (!(conn->link_mode & HCI_LM_AUTH))
goto auth;
- /* An authenticated combination key has sufficient security for any
- security level. */
- if (conn->key_type == HCI_LK_AUTH_COMBINATION_P192 ||
- conn->key_type == HCI_LK_AUTH_COMBINATION_P256)
+ /* An authenticated FIPS approved combination key has sufficient
+ * security for security level 4. */
+ if (conn->key_type == HCI_LK_AUTH_COMBINATION_P256 &&
+ sec_level == BT_SECURITY_FIPS)
+ goto encrypt;
+
+ /* An authenticated combination key has sufficient security for
+ security level 3. */
+ if ((conn->key_type == HCI_LK_AUTH_COMBINATION_P192 ||
+ conn->key_type == HCI_LK_AUTH_COMBINATION_P256) &&
+ sec_level == BT_SECURITY_HIGH)
goto encrypt;
/* An unauthenticated combination key has sufficient security for
@@ -818,7 +825,8 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
is generated using maximum PIN code length (16).
For pre 2.1 units. */
if (conn->key_type == HCI_LK_COMBINATION &&
- (sec_level != BT_SECURITY_HIGH || conn->pin_length == 16))
+ (sec_level == BT_SECURITY_MEDIUM || sec_level == BT_SECURITY_LOW ||
+ conn->pin_length == 16))
goto encrypt;
auth:
--
1.8.4.2
^ permalink raw reply related
* [PATCH 1/2] Bluetooth: Handle security level 4 for L2CAP connections
From: Marcel Holtmann @ 2014-01-11 21:44 UTC (permalink / raw)
To: linux-bluetooth
With the introduction of security level 4, the L2CAP sockets need to
be made aware of this new level. This change ensures that the pairing
requirements are set correctly for these connections.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
include/net/bluetooth/l2cap.h | 1 +
net/bluetooth/l2cap_core.c | 11 ++++++++---
net/bluetooth/l2cap_sock.c | 10 ++++++++++
3 files changed, 19 insertions(+), 3 deletions(-)
diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
index dbc4a89984ca..c695083eee2b 100644
--- a/include/net/bluetooth/l2cap.h
+++ b/include/net/bluetooth/l2cap.h
@@ -91,6 +91,7 @@ struct l2cap_conninfo {
#define L2CAP_LM_TRUSTED 0x0008
#define L2CAP_LM_RELIABLE 0x0010
#define L2CAP_LM_SECURE 0x0020
+#define L2CAP_LM_FIPS 0x0040
/* L2CAP command codes */
#define L2CAP_COMMAND_REJ 0x01
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index b0ad2c752d73..3f0dd552cb2b 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -737,6 +737,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
case L2CAP_CHAN_RAW:
switch (chan->sec_level) {
case BT_SECURITY_HIGH:
+ case BT_SECURITY_FIPS:
return HCI_AT_DEDICATED_BONDING_MITM;
case BT_SECURITY_MEDIUM:
return HCI_AT_DEDICATED_BONDING;
@@ -749,7 +750,8 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
if (chan->sec_level == BT_SECURITY_LOW)
chan->sec_level = BT_SECURITY_SDP;
}
- if (chan->sec_level == BT_SECURITY_HIGH)
+ if (chan->sec_level == BT_SECURITY_HIGH ||
+ chan->sec_level == BT_SECURITY_FIPS)
return HCI_AT_NO_BONDING_MITM;
else
return HCI_AT_NO_BONDING;
@@ -759,7 +761,8 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
if (chan->sec_level == BT_SECURITY_LOW)
chan->sec_level = BT_SECURITY_SDP;
- if (chan->sec_level == BT_SECURITY_HIGH)
+ if (chan->sec_level == BT_SECURITY_HIGH ||
+ chan->sec_level == BT_SECURITY_FIPS)
return HCI_AT_NO_BONDING_MITM;
else
return HCI_AT_NO_BONDING;
@@ -768,6 +771,7 @@ static inline u8 l2cap_get_auth_type(struct l2cap_chan *chan)
default:
switch (chan->sec_level) {
case BT_SECURITY_HIGH:
+ case BT_SECURITY_FIPS:
return HCI_AT_GENERAL_BONDING_MITM;
case BT_SECURITY_MEDIUM:
return HCI_AT_GENERAL_BONDING;
@@ -7206,7 +7210,8 @@ static inline void l2cap_check_encryption(struct l2cap_chan *chan, u8 encrypt)
if (encrypt == 0x00) {
if (chan->sec_level == BT_SECURITY_MEDIUM) {
__set_chan_timer(chan, L2CAP_ENC_TIMEOUT);
- } else if (chan->sec_level == BT_SECURITY_HIGH)
+ } else if (chan->sec_level == BT_SECURITY_HIGH ||
+ chan->sec_level == BT_SECURITY_FIPS)
l2cap_chan_close(chan, ECONNREFUSED);
} else {
if (chan->sec_level == BT_SECURITY_MEDIUM)
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 20ef748b2906..4aa6704f0b33 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -432,6 +432,10 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
L2CAP_LM_SECURE;
break;
+ case BT_SECURITY_FIPS:
+ opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
+ L2CAP_LM_SECURE | L2CAP_LM_FIPS;
+ break;
default:
opt = 0;
break;
@@ -445,6 +449,7 @@ static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
if (put_user(opt, (u32 __user *) optval))
err = -EFAULT;
+
break;
case L2CAP_CONNINFO:
@@ -699,6 +704,11 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
break;
}
+ if (opt & L2CAP_LM_FIPS) {
+ err = -EINVAL;
+ break;
+ }
+
if (opt & L2CAP_LM_AUTH)
chan->sec_level = BT_SECURITY_LOW;
if (opt & L2CAP_LM_ENCRYPT)
--
1.8.4.2
^ permalink raw reply related
* [PATCH 2/2] Bluetooth: Handle security level 4 for RFCOMM connections
From: Marcel Holtmann @ 2014-01-11 21:44 UTC (permalink / raw)
To: linux-bluetooth
With the introduction of security level 4, the RFCOMM sockets need to
be made aware of this new level. This change ensures that the pairing
requirements are set correctly for these connections.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
include/net/bluetooth/rfcomm.h | 1 +
net/bluetooth/rfcomm/core.c | 4 +++-
net/bluetooth/rfcomm/sock.c | 12 +++++++++++-
3 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
index 486213a1aed8..c312cfc4e922 100644
--- a/include/net/bluetooth/rfcomm.h
+++ b/include/net/bluetooth/rfcomm.h
@@ -295,6 +295,7 @@ struct rfcomm_conninfo {
#define RFCOMM_LM_TRUSTED 0x0008
#define RFCOMM_LM_RELIABLE 0x0010
#define RFCOMM_LM_SECURE 0x0020
+#define RFCOMM_LM_FIPS 0x0040
#define rfcomm_pi(sk) ((struct rfcomm_pinfo *) sk)
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index facd8a79c038..ba115d472f7b 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -216,6 +216,7 @@ static int rfcomm_check_security(struct rfcomm_dlc *d)
switch (d->sec_level) {
case BT_SECURITY_HIGH:
+ case BT_SECURITY_FIPS:
auth_type = HCI_AT_GENERAL_BONDING_MITM;
break;
case BT_SECURITY_MEDIUM:
@@ -2085,7 +2086,8 @@ static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
set_bit(RFCOMM_SEC_PENDING, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
continue;
- } else if (d->sec_level == BT_SECURITY_HIGH) {
+ } else if (d->sec_level == BT_SECURITY_HIGH ||
+ d->sec_level == BT_SECURITY_FIPS) {
set_bit(RFCOMM_ENC_DROP, &d->flags);
continue;
}
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index 3c2d3e4aa2f5..fb8158af1f39 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -648,6 +648,11 @@ static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __u
break;
}
+ if (opt & RFCOMM_LM_FIPS) {
+ err = -EINVAL;
+ break;
+ }
+
if (opt & RFCOMM_LM_AUTH)
rfcomm_pi(sk)->sec_level = BT_SECURITY_LOW;
if (opt & RFCOMM_LM_ENCRYPT)
@@ -762,7 +767,11 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
break;
case BT_SECURITY_HIGH:
opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
- RFCOMM_LM_SECURE;
+ RFCOMM_LM_SECURE;
+ break;
+ case BT_SECURITY_FIPS:
+ opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
+ RFCOMM_LM_SECURE | RFCOMM_LM_FIPS;
break;
default:
opt = 0;
@@ -774,6 +783,7 @@ static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __u
if (put_user(opt, (u32 __user *) optval))
err = -EFAULT;
+
break;
case RFCOMM_CONNINFO:
--
1.8.4.2
^ permalink raw reply related
* [PATCH] Bluetooth: Add management command for Secure Connection Only mode
From: Marcel Holtmann @ 2014-01-11 22:05 UTC (permalink / raw)
To: linux-bluetooth
With support for Secure Connections it is possible to switch the
controller into a mode that is called Secure Connections Only. In
this mode only security level 4 connections are allowed (with the
exception of security level 0 approved services).
This patch just introduces the management command and setting of the
right internal flags to enable this mode. It does not yet enforce it.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
include/net/bluetooth/hci.h | 1 +
net/bluetooth/mgmt.c | 36 +++++++++++++++++++++++++-----------
2 files changed, 26 insertions(+), 11 deletions(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index 2bc19881e250..aed74d1bd206 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -124,6 +124,7 @@ enum {
HCI_LE_SCAN,
HCI_SSP_ENABLED,
HCI_SC_ENABLED,
+ HCI_SC_ONLY,
HCI_HS_ENABLED,
HCI_LE_ENABLED,
HCI_ADVERTISING,
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 4b6034fcc902..a1d42ae6f8fd 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -4040,7 +4040,7 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
{
struct mgmt_mode *cp = data;
struct pending_cmd *cmd;
- u8 status;
+ u8 val, status;
int err;
BT_DBG("request for %s", hdev->name);
@@ -4055,7 +4055,7 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
MGMT_STATUS_NOT_SUPPORTED);
- if (cp->val != 0x00 && cp->val != 0x01)
+ if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN,
MGMT_STATUS_INVALID_PARAMS);
@@ -4064,12 +4064,16 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
if (!hdev_is_powered(hdev)) {
bool changed;
- if (cp->val)
+ if (cp->val) {
changed = !test_and_set_bit(HCI_SC_ENABLED,
&hdev->dev_flags);
- else
+ if (cp->val == 0x02)
+ set_bit(HCI_SC_ONLY, &hdev->dev_flags);
+ } else {
changed = test_and_clear_bit(HCI_SC_ENABLED,
&hdev->dev_flags);
+ clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
+ }
err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
if (err < 0)
@@ -4087,7 +4091,9 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
goto failed;
}
- if (!!cp->val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) {
+ val = !!cp->val;
+
+ if (val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) {
err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev);
goto failed;
}
@@ -4098,12 +4104,15 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev,
goto failed;
}
- err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &cp->val);
+ err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &val);
if (err < 0) {
mgmt_pending_remove(cmd);
goto failed;
}
+ if (cp->val == 0x02)
+ set_bit(HCI_SC_ONLY, &hdev->dev_flags);
+
failed:
hci_dev_unlock(hdev);
return err;
@@ -5029,19 +5038,24 @@ void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
if (status) {
u8 mgmt_err = mgmt_status(status);
- if (enable && test_and_clear_bit(HCI_SC_ENABLED,
- &hdev->dev_flags))
- new_settings(hdev, NULL);
+ if (enable) {
+ if (test_and_clear_bit(HCI_SC_ENABLED,
+ &hdev->dev_flags))
+ new_settings(hdev, NULL);
+ clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
+ }
mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
cmd_status_rsp, &mgmt_err);
return;
}
- if (enable)
+ if (enable) {
changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags);
- else
+ } else {
changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags);
+ clear_bit(HCI_SC_ONLY, &hdev->dev_flags);
+ }
mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev,
settings_rsp, &match);
--
1.8.4.2
^ permalink raw reply related
* [PATCH] Bluetooth: Add debugfs entry to show Secure Connections Only mode
From: Marcel Holtmann @ 2014-01-11 22:20 UTC (permalink / raw)
To: linux-bluetooth
For debugging purposes of Secure Connection Only support a simple
debugfs entry is used to indicate if this mode is active or not.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
net/bluetooth/hci_core.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 499ec1b1095d..369d30750417 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -461,6 +461,24 @@ static const struct file_operations force_sc_support_fops = {
.llseek = default_llseek,
};
+static ssize_t sc_only_mode_read(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct hci_dev *hdev = file->private_data;
+ char buf[3];
+
+ buf[0] = test_bit(HCI_SC_ONLY, &hdev->dev_flags) ? 'Y': 'N';
+ buf[1] = '\n';
+ buf[2] = '\0';
+ return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static const struct file_operations sc_only_mode_fops = {
+ .open = simple_open,
+ .read = sc_only_mode_read,
+ .llseek = default_llseek,
+};
+
static int idle_timeout_set(void *data, u64 val)
{
struct hci_dev *hdev = data;
@@ -1491,6 +1509,8 @@ static int __hci_init(struct hci_dev *hdev)
hdev, &ssp_debug_mode_fops);
debugfs_create_file("force_sc_support", 0644, hdev->debugfs,
hdev, &force_sc_support_fops);
+ debugfs_create_file("sc_only_mode", 0444, hdev->debugfs,
+ hdev, &sc_only_mode_fops);
}
if (lmp_sniff_capable(hdev)) {
--
1.8.4.2
^ permalink raw reply related
* [PATCH] Bluetooth: Avoid use of session socket after the session gets freed
From: Dean_Jenkins @ 2014-01-12 13:20 UTC (permalink / raw)
To: linux-bluetooth, marcel, gustavo; +Cc: Dean_Jenkins, vitaly_kuzmichev
From: Vitaly Kuzmichev <vitaly_kuzmichev@mentor.com>
The commits 08c30aca9e698faddebd34f81e1196295f9dc063 "Bluetooth: Remove
RFCOMM session refcnt" and 8ff52f7d04d9cc31f1e81dcf9a2ba6335ed34905
"Bluetooth: Return RFCOMM session ptrs to avoid freed session"
allow rfcomm_recv_ua and rfcomm_session_close to delete the session
(and free the corresponding socket) and propagate NULL session pointer
to the upper callers.
Additional fix is required to terminate the loop in rfcomm_process_rx
function to avoid use of freed 'sk' memory.
The issue is only reproducible with kernel option CONFIG_PAGE_POISONING
enabled making freed memory being changed and filled up with fixed char
value used to unmask use-after-free issues.
Signed-off-by: Vitaly Kuzmichev <Vitaly_Kuzmichev@mentor.com>
Acked-by: Dean Jenkins <Dean_Jenkins@mentor.com>
---
net/bluetooth/rfcomm/core.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index facd8a7..5632146 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -1857,7 +1857,7 @@ static struct rfcomm_session *rfcomm_process_rx(struct rfcomm_session *s)
BT_DBG("session %p state %ld qlen %d", s, s->state, skb_queue_len(&sk->sk_receive_queue));
/* Get data directly from socket receive queue without copying it. */
- while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
+ while (s && (skb = skb_dequeue(&sk->sk_receive_queue))) {
skb_orphan(skb);
if (!skb_linearize(skb))
s = rfcomm_recv_frame(s, skb);
--
1.8.1.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox