From: Luiz Augusto von Dentz <luiz.von.dentz@xxxxxxxxx> 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(-) diff --git a/btio/btio.c b/btio/btio.c index db37b99da..e7b4db16b 100644 --- a/btio/btio.c +++ b/btio/btio.c @@ -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, diff --git a/btio/btio.h b/btio/btio.h index 41a017acb..5ebfb85c6 100644 --- a/btio/btio.h +++ b/btio/btio.h @@ -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); -- 2.21.1