Diff between fc9ccf6154a0c090e641569a9567a40eb1c721f5 and 05bdde05b2176b42f6334c4f478395cfc6943abf

Changed Files

File Additions Deletions Status
src/shared/att-types.h +4 -0 modified
src/shared/att.c +47 -4 modified
src/shared/att.h +1 -0 modified

Full Patch

diff --git a/src/shared/att-types.h b/src/shared/att-types.h
index 4a9b67f..51922d1 100644
--- a/src/shared/att-types.h
+++ b/src/shared/att-types.h
@@ -37,6 +37,10 @@
 #define BT_ATT_MAX_LE_MTU	517
 #define BT_ATT_MAX_VALUE_LEN	512
 
+#define BT_ATT_LINK_BREDR	0x00
+#define BT_ATT_LINK_LE		0x01
+#define BT_ATT_LINK_LOCAL	0xff
+
 /* ATT protocol opcodes */
 #define BT_ATT_OP_ERROR_RSP			0x01
 #define BT_ATT_OP_MTU_REQ			0x02
diff --git a/src/shared/att.c b/src/shared/att.c
index 74a9150..f1e0f59 100644
--- a/src/shared/att.c
+++ b/src/shared/att.c
@@ -34,6 +34,7 @@
 #include "src/shared/util.h"
 #include "src/shared/timeout.h"
 #include "lib/bluetooth.h"
+#include "lib/l2cap.h"
 #include "lib/uuid.h"
 #include "src/shared/att.h"
 #include "src/shared/crypto.h"
@@ -967,6 +968,18 @@ static void bt_att_free(struct bt_att *att)
 	free(att);
 }
 
+static uint16_t get_l2cap_mtu(int fd)
+{
+	socklen_t len;
+	struct l2cap_options l2o;
+
+	len = sizeof(l2o);
+	if (getsockopt(fd, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &len) < 0)
+		return 0;
+
+	return l2o.omtu;
+}
+
 struct bt_att *bt_att_new(int fd, bool ext_signed)
 {
 	struct bt_att *att;
@@ -976,10 +989,6 @@ struct bt_att *bt_att_new(int fd, bool ext_signed)
 
 	att = new0(struct bt_att, 1);
 	att->fd = fd;
-	att->mtu = BT_ATT_DEFAULT_LE_MTU;
-	att->buf = malloc(att->mtu);
-	if (!att->buf)
-		goto fail;
 
 	att->io = io_new(fd);
 	if (!att->io)
@@ -1005,6 +1014,18 @@ struct bt_att *bt_att_new(int fd, bool ext_signed)
 	if (!att->io_on_l2cap)
 		att->io_sec_level = BT_ATT_SECURITY_LOW;
 
+	if (bt_att_get_link_type(att) == BT_ATT_LINK_BREDR)
+		att->mtu = get_l2cap_mtu(att->fd);
+	else
+		att->mtu = BT_ATT_DEFAULT_LE_MTU;
+
+	if (att->mtu < BT_ATT_DEFAULT_LE_MTU)
+		goto fail;
+
+	att->buf = malloc(att->mtu);
+	if (!att->buf)
+		goto fail;
+
 	return bt_att_ref(att);
 
 fail:
@@ -1099,6 +1120,28 @@ bool bt_att_set_mtu(struct bt_att *att, uint16_t mtu)
 	return true;
 }
 
+uint8_t bt_att_get_link_type(struct bt_att *att)
+{
+	struct sockaddr_l2 src;
+	socklen_t len;
+
+	if (!att)
+		return -EINVAL;
+
+	if (!att->io_on_l2cap)
+		return BT_ATT_LINK_LOCAL;
+
+	len = sizeof(src);
+	memset(&src, 0, len);
+	if (getsockname(att->fd, (void *)&src, &len) < 0)
+		return -errno;
+
+	if (src.l2_bdaddr_type == BDADDR_BREDR)
+		return BT_ATT_LINK_BREDR;
+
+	return BT_ATT_LINK_LE;
+}
+
 bool bt_att_set_timeout_cb(struct bt_att *att, bt_att_timeout_func_t callback,
 						void *user_data,
 						bt_att_destroy_func_t destroy)
diff --git a/src/shared/att.h b/src/shared/att.h
index 2a7f87e..7bffee7 100644
--- a/src/shared/att.h
+++ b/src/shared/att.h
@@ -53,6 +53,7 @@ bool bt_att_set_debug(struct bt_att *att, bt_att_debug_func_t callback,
 
 uint16_t bt_att_get_mtu(struct bt_att *att);
 bool bt_att_set_mtu(struct bt_att *att, uint16_t mtu);
+uint8_t bt_att_get_link_type(struct bt_att *att);
 
 bool bt_att_set_timeout_cb(struct bt_att *att, bt_att_timeout_func_t callback,
 						void *user_data,