@@ -630,18 +630,34 @@ static gboolean set_le_imtu(int sock, uint16_t imtu, GError **err)
return TRUE;
}
+static gboolean set_le_mode(int sock, uint8_t mode, GError **err)
+{
+ if (setsockopt(sock, SOL_BLUETOOTH, BT_MODE, &mode,
+ sizeof(mode)) < 0) {
+ ERROR_FAILED(err, "setsockopt(BT_MODE)", errno);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
static gboolean l2cap_set(int sock, uint8_t src_type, int sec_level,
uint16_t imtu, uint16_t omtu, uint8_t mode,
int master, int flushable, uint32_t priority,
GError **err)
{
if (imtu || omtu || mode) {
- gboolean ret;
+ gboolean ret = FALSE;
if (src_type == BDADDR_BREDR)
ret = set_l2opts(sock, imtu, omtu, mode, err);
- else
- ret = set_le_imtu(sock, imtu, err);
+ else {
+ if (imtu)
+ ret = set_le_imtu(sock, imtu, err);
+
+ if (ret && mode)
+ ret = set_le_mode(sock, mode, err);
+ }
if (!ret)
return ret;
@@ -980,6 +996,30 @@ static int get_phy(int sock, uint32_t *phy)
return 0;
}
+static int get_le_imtu(int sock, uint16_t *mtu)
+{
+ socklen_t len;
+
+ len = sizeof(*mtu);
+
+ if (getsockopt(sock, SOL_BLUETOOTH, BT_RCVMTU, mtu, &len) < 0)
+ return -errno;
+
+ return 0;
+}
+
+static int get_le_mode(int sock, uint8_t *mode)
+{
+ socklen_t len;
+
+ len = sizeof(*mode);
+
+ if (getsockopt(sock, SOL_BLUETOOTH, BT_MODE, mode, &len) < 0)
+ return -errno;
+
+ return 0;
+}
+
static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
va_list args)
{
@@ -999,10 +1039,11 @@ static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
memset(&l2o, 0, sizeof(l2o));
if (src.l2_bdaddr_type != BDADDR_BREDR) {
- len = sizeof(l2o.imtu);
- if (getsockopt(sock, SOL_BLUETOOTH, BT_RCVMTU,
- &l2o.imtu, &len) == 0)
+ if (get_le_imtu(sock, &l2o.imtu) == 0) {
+ /* Older kernels may not support BT_MODE */
+ get_le_mode(sock, &l2o.mode);
goto parse_opts;
+ }
/* Non-LE CoC enabled kernels will return one of these
* in which case we need to fall back to L2CAP_OPTIONS.
@@ -1644,6 +1685,12 @@ GIOChannel *bt_io_connect(BtIOConnect connect, gpointer user_data,
sock = g_io_channel_unix_get_fd(io);
+ /* Use DEFER_SETUP when connecting using Ext-Flowctl */
+ if (opts.mode == BT_IO_MODE_EXT_FLOWCTL && opts.defer) {
+ setsockopt(sock, SOL_BLUETOOTH, BT_DEFER_SETUP, &opts.defer,
+ sizeof(opts.defer));
+ }
+
switch (opts.type) {
case BT_IO_L2CAP:
err = l2cap_connect(sock, &opts.dst, opts.dst_type,
@@ -71,7 +71,8 @@ typedef enum {
BT_IO_MODE_RETRANS,
BT_IO_MODE_FLOWCTL,
BT_IO_MODE_ERTM,
- BT_IO_MODE_STREAMING
+ BT_IO_MODE_STREAMING,
+ BT_IO_MODE_EXT_FLOWCTL = 0x81
} BtIOMode;
typedef void (*BtIOConfirm)(GIOChannel *io, gpointer user_data);
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> This adds BT_IO_MODE_EXT_FLOWCTL which directly maps to L2CAP_MODE_EXT_FLOWCTL. --- btio/btio.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++------ btio/btio.h | 3 ++- 2 files changed, 55 insertions(+), 7 deletions(-)