Skip to content

Commit 3ee7b7c

Browse files
Vudentzholtmann
authored andcommitted
Bluetooth: Add BT_MODE socket option
This adds BT_MODE socket option which can be used to set L2CAP modes, including modes only supported over LE which were not supported using the L2CAP_OPTIONS. Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
1 parent b86b0b1 commit 3ee7b7c

File tree

2 files changed

+120
-1
lines changed

2 files changed

+120
-1
lines changed

include/net/bluetooth/bluetooth.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,14 @@ struct bt_voice {
139139
#define BT_PHY_LE_CODED_TX 0x00002000
140140
#define BT_PHY_LE_CODED_RX 0x00004000
141141

142+
#define BT_MODE 15
143+
144+
#define BT_MODE_BASIC 0x00
145+
#define BT_MODE_ERTM 0x01
146+
#define BT_MODE_STREAMING 0x02
147+
#define BT_MODE_LE_FLOWCTL 0x03
148+
#define BT_MODE_EXT_FLOWCTL 0x04
149+
142150
__printf(1, 2)
143151
void bt_info(const char *fmt, ...);
144152
__printf(1, 2)

net/bluetooth/l2cap_sock.c

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,24 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr,
395395
return sizeof(struct sockaddr_l2);
396396
}
397397

398+
static int l2cap_get_mode(struct l2cap_chan *chan)
399+
{
400+
switch (chan->mode) {
401+
case L2CAP_MODE_BASIC:
402+
return BT_MODE_BASIC;
403+
case L2CAP_MODE_ERTM:
404+
return BT_MODE_ERTM;
405+
case L2CAP_MODE_STREAMING:
406+
return BT_MODE_STREAMING;
407+
case L2CAP_MODE_LE_FLOWCTL:
408+
return BT_MODE_LE_FLOWCTL;
409+
case L2CAP_MODE_EXT_FLOWCTL:
410+
return BT_MODE_EXT_FLOWCTL;
411+
}
412+
413+
return -EINVAL;
414+
}
415+
398416
static int l2cap_sock_getsockopt_old(struct socket *sock, int optname,
399417
char __user *optval, int __user *optlen)
400418
{
@@ -522,7 +540,7 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
522540
struct bt_security sec;
523541
struct bt_power pwr;
524542
u32 phys;
525-
int len, err = 0;
543+
int len, mode, err = 0;
526544

527545
BT_DBG("sk %p", sk);
528546

@@ -638,6 +656,27 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname,
638656
err = -EFAULT;
639657
break;
640658

659+
case BT_MODE:
660+
if (!enable_ecred) {
661+
err = -ENOPROTOOPT;
662+
break;
663+
}
664+
665+
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
666+
err = -EINVAL;
667+
break;
668+
}
669+
670+
mode = l2cap_get_mode(chan);
671+
if (mode < 0) {
672+
err = mode;
673+
break;
674+
}
675+
676+
if (put_user(mode, (u8 __user *) optval))
677+
err = -EFAULT;
678+
break;
679+
641680
default:
642681
err = -ENOPROTOOPT;
643682
break;
@@ -780,6 +819,45 @@ static int l2cap_sock_setsockopt_old(struct socket *sock, int optname,
780819
return err;
781820
}
782821

822+
static int l2cap_set_mode(struct l2cap_chan *chan, u8 mode)
823+
{
824+
switch (mode) {
825+
case BT_MODE_BASIC:
826+
if (bdaddr_type_is_le(chan->src_type))
827+
return -EINVAL;
828+
mode = L2CAP_MODE_BASIC;
829+
clear_bit(CONF_STATE2_DEVICE, &chan->conf_state);
830+
break;
831+
case BT_MODE_ERTM:
832+
if (!disable_ertm || bdaddr_type_is_le(chan->src_type))
833+
return -EINVAL;
834+
mode = L2CAP_MODE_ERTM;
835+
break;
836+
case BT_MODE_STREAMING:
837+
if (!disable_ertm || bdaddr_type_is_le(chan->src_type))
838+
return -EINVAL;
839+
mode = L2CAP_MODE_STREAMING;
840+
break;
841+
case BT_MODE_LE_FLOWCTL:
842+
if (!bdaddr_type_is_le(chan->src_type))
843+
return -EINVAL;
844+
mode = L2CAP_MODE_LE_FLOWCTL;
845+
break;
846+
case BT_MODE_EXT_FLOWCTL:
847+
/* TODO: Add support for ECRED PDUs to BR/EDR */
848+
if (!bdaddr_type_is_le(chan->src_type))
849+
return -EINVAL;
850+
mode = L2CAP_MODE_EXT_FLOWCTL;
851+
break;
852+
default:
853+
return -EINVAL;
854+
}
855+
856+
chan->mode = mode;
857+
858+
return 0;
859+
}
860+
783861
static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
784862
char __user *optval, unsigned int optlen)
785863
{
@@ -985,6 +1063,39 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
9851063

9861064
break;
9871065

1066+
case BT_MODE:
1067+
if (!enable_ecred) {
1068+
err = -ENOPROTOOPT;
1069+
break;
1070+
}
1071+
1072+
BT_DBG("sk->sk_state %u", sk->sk_state);
1073+
1074+
if (sk->sk_state != BT_BOUND) {
1075+
err = -EINVAL;
1076+
break;
1077+
}
1078+
1079+
if (chan->chan_type != L2CAP_CHAN_CONN_ORIENTED) {
1080+
err = -EINVAL;
1081+
break;
1082+
}
1083+
1084+
if (get_user(opt, (u8 __user *) optval)) {
1085+
err = -EFAULT;
1086+
break;
1087+
}
1088+
1089+
BT_DBG("opt %u", opt);
1090+
1091+
err = l2cap_set_mode(chan, opt);
1092+
if (err)
1093+
break;
1094+
1095+
BT_DBG("mode 0x%2.2x", chan->mode);
1096+
1097+
break;
1098+
9881099
default:
9891100
err = -ENOPROTOOPT;
9901101
break;

0 commit comments

Comments
 (0)