[PATCH v1] Bluetooth: Fix the HCI to MGMT status conversion table

2021-04-19 Thread Yu Liu
0x2B, 0x31 and 0x33 are reserved for future use but were not present in
the HCI to MGMT conversion table, this caused the conversion to be
incorrect for the HCI status code greater than 0x2A.

Reviewed-by: Miao-chen Chou 
Signed-off-by: Yu Liu 
---

Changes in v1:
- Initial change

 net/bluetooth/mgmt.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 40f75b8e1416..b44e19c69c44 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -252,12 +252,15 @@ static const u8 mgmt_status_table[] = {
MGMT_STATUS_TIMEOUT,/* Instant Passed */
MGMT_STATUS_NOT_SUPPORTED,  /* Pairing Not Supported */
MGMT_STATUS_FAILED, /* Transaction Collision */
+   MGMT_STATUS_FAILED, /* Reserved for future use */
MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
MGMT_STATUS_REJECTED,   /* QoS Rejected */
MGMT_STATUS_NOT_SUPPORTED,  /* Classification Not Supported */
MGMT_STATUS_REJECTED,   /* Insufficient Security */
MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
+   MGMT_STATUS_FAILED, /* Reserved for future use */
MGMT_STATUS_BUSY,   /* Role Switch Pending */
+   MGMT_STATUS_FAILED, /* Reserved for future use */
MGMT_STATUS_FAILED, /* Slot Violation */
MGMT_STATUS_FAILED, /* Role Switch Failed */
MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
-- 
2.31.1.368.gbe11c130af-goog



[PATCH v2] Bluetooth: Return whether a connection is outbound

2021-04-09 Thread Yu Liu
When an MGMT_EV_DEVICE_CONNECTED event is reported back to the user
space we will set the flags to tell if the established connection is
outbound or not. This is useful for the user space to log better metrics
and error messages.

Reviewed-by: Miao-chen Chou 
Reviewed-by: Alain Michaud 
Signed-off-by: Yu Liu 
---

Changes in v2:
- Defined the bit as MGMT_DEV_FOUND_INITIATED_CONN

Changes in v1:
- Initial change

 include/net/bluetooth/hci_core.h | 2 +-
 include/net/bluetooth/mgmt.h | 1 +
 net/bluetooth/hci_event.c| 8 
 net/bluetooth/l2cap_core.c   | 2 +-
 net/bluetooth/mgmt.c | 6 +-
 5 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index ca4ac6603b9a..d2876b758770 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1756,7 +1756,7 @@ void __mgmt_power_off(struct hci_dev *hdev);
 void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
   bool persistent);
 void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
-  u32 flags, u8 *name, u8 name_len);
+  u8 *name, u8 name_len);
 void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
  u8 link_type, u8 addr_type, u8 reason,
  bool mgmt_connected);
diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index a7cffb069565..a03c62b1dc2f 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -939,6 +939,7 @@ struct mgmt_ev_auth_failed {
 #define MGMT_DEV_FOUND_CONFIRM_NAME0x01
 #define MGMT_DEV_FOUND_LEGACY_PAIRING  0x02
 #define MGMT_DEV_FOUND_NOT_CONNECTABLE 0x04
+#define MGMT_DEV_FOUND_INITIATED_CONN  0x08
 
 #define MGMT_EV_DEVICE_FOUND   0x0012
 struct mgmt_ev_device_found {
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 593eafa282e3..35b1adb2287c 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -2071,7 +2071,7 @@ static void hci_check_pending_name(struct hci_dev *hdev, 
struct hci_conn *conn,
if (conn &&
(conn->state == BT_CONFIG || conn->state == BT_CONNECTED) &&
!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, >flags))
-   mgmt_device_connected(hdev, conn, 0, name, name_len);
+   mgmt_device_connected(hdev, conn, name, name_len);
 
if (discov->state == DISCOVERY_STOPPED)
return;
@@ -3258,7 +3258,7 @@ static void hci_remote_features_evt(struct hci_dev *hdev,
cp.pscan_rep_mode = 0x02;
hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), );
} else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, >flags))
-   mgmt_device_connected(hdev, conn, 0, NULL, 0);
+   mgmt_device_connected(hdev, conn, NULL, 0);
 
if (!hci_outgoing_auth_needed(hdev, conn)) {
conn->state = BT_CONNECTED;
@@ -4332,7 +4332,7 @@ static void hci_remote_ext_features_evt(struct hci_dev 
*hdev,
cp.pscan_rep_mode = 0x02;
hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), );
} else if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, >flags))
-   mgmt_device_connected(hdev, conn, 0, NULL, 0);
+   mgmt_device_connected(hdev, conn, NULL, 0);
 
if (!hci_outgoing_auth_needed(hdev, conn)) {
conn->state = BT_CONNECTED;
@@ -5206,7 +5206,7 @@ static void le_conn_complete_evt(struct hci_dev *hdev, u8 
status,
}
 
if (!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, >flags))
-   mgmt_device_connected(hdev, conn, 0, NULL, 0);
+   mgmt_device_connected(hdev, conn, NULL, 0);
 
conn->sec_level = BT_SECURITY_LOW;
conn->handle = handle;
diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
index 140669456b6f..821d46ba6e74 100644
--- a/net/bluetooth/l2cap_core.c
+++ b/net/bluetooth/l2cap_core.c
@@ -4237,7 +4237,7 @@ static int l2cap_connect_req(struct l2cap_conn *conn,
hci_dev_lock(hdev);
if (hci_dev_test_flag(hdev, HCI_MGMT) &&
!test_and_set_bit(HCI_CONN_MGMT_CONNECTED, >flags))
-   mgmt_device_connected(hdev, hcon, 0, NULL, 0);
+   mgmt_device_connected(hdev, hcon, NULL, 0);
hci_dev_unlock(hdev);
 
l2cap_connect(conn, cmd, data, L2CAP_CONN_RSP, 0);
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 09e099c419f2..c594e0c2dd23 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -8765,15 +8765,19 @@ void mgmt_new_conn_param(struct hci_dev *hdev, bdaddr_t 
*bdaddr,
 }
 
 void mgmt_device_connected(struct hci_dev *hdev, struct hci_conn *conn,
-  u32 flags, u8 *name, u8 name_len)
+  u8 

[PATCH v1] Bluetooth: Return whether a connection is outbound

2021-04-02 Thread Yu Liu
When an MGMT_EV_DEVICE_CONNECTED event is reported back to the user
space we will set the flags to tell if the established connection is
outbound or not. This is useful for the user space to log better metrics
and error messages.

Reviewed-by: Miao-chen Chou 
Reviewed-by: Alain Michaud 
Signed-off-by: Yu Liu 
---

Changes in v1:
- Initial change

 include/net/bluetooth/mgmt.h | 2 ++
 net/bluetooth/mgmt.c | 5 +
 2 files changed, 7 insertions(+)

diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index a7cffb069565..7cc724386b00 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -885,6 +885,8 @@ struct mgmt_ev_new_long_term_key {
struct mgmt_ltk_info key;
 } __packed;
 
+#define MGMT_DEV_CONN_INITIATED_CONNECTION 0x08
+
 #define MGMT_EV_DEVICE_CONNECTED   0x000B
 struct mgmt_ev_device_connected {
struct mgmt_addr_info addr;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 09e099c419f2..77213e67e8e4 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -8774,6 +8774,11 @@ void mgmt_device_connected(struct hci_dev *hdev, struct 
hci_conn *conn,
bacpy(>addr.bdaddr, >dst);
ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
 
+   if (conn->out)
+   flags |= MGMT_DEV_CONN_INITIATED_CONNECTION;
+   else
+   flags &= ~MGMT_DEV_CONN_INITIATED_CONNECTION;
+
ev->flags = __cpu_to_le32(flags);
 
/* We must ensure that the EIR Data fields are ordered and
-- 
2.31.0.208.g409f899ff0-goog



[PATCH v1] Bluetooth: Return whether a connection is outbound

2021-03-23 Thread Yu Liu
When an MGMT_EV_DEVICE_CONNECTED event is reported back to the user
space we will set the flags to tell if the established connection is
outbound or not. This is useful for the user space to log better metrics
and error messages.

Reviewed-by: Miao-chen Chou 
Reviewed-by: Alain Michaud 

Signed-off-by: Yu Liu 
---

Changes in v1:
- Initial change

 include/net/bluetooth/mgmt.h | 2 ++
 net/bluetooth/mgmt.c | 5 +
 2 files changed, 7 insertions(+)

diff --git a/include/net/bluetooth/mgmt.h b/include/net/bluetooth/mgmt.h
index a7cffb069565..d66bc6938b58 100644
--- a/include/net/bluetooth/mgmt.h
+++ b/include/net/bluetooth/mgmt.h
@@ -885,6 +885,8 @@ struct mgmt_ev_new_long_term_key {
struct mgmt_ltk_info key;
 } __packed;
 
+#define MGMT_DEV_CONN_DIRECTION_OUT0x01
+
 #define MGMT_EV_DEVICE_CONNECTED   0x000B
 struct mgmt_ev_device_connected {
struct mgmt_addr_info addr;
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 90334ac4a135..fc0ff6dc7ebf 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -8772,6 +8772,11 @@ void mgmt_device_connected(struct hci_dev *hdev, struct 
hci_conn *conn,
bacpy(>addr.bdaddr, >dst);
ev->addr.type = link_to_bdaddr(conn->type, conn->dst_type);
 
+   if (conn->out)
+   flags |= MGMT_DEV_CONN_DIRECTION_OUT;
+   else
+   flags &= ~MGMT_DEV_CONN_DIRECTION_OUT;
+
ev->flags = __cpu_to_le32(flags);
 
/* We must ensure that the EIR Data fields are ordered and
-- 
2.31.0.291.g576ba9dcdaf-goog



[PATCH v3] Bluetooth: Skip eSCO 2M params when not supported

2021-01-29 Thread Yu Liu
If a peer device doesn't support eSCO 2M we should skip the params that
use it when setting up sync connection since they will always fail.

Signed-off-by: Yu Liu 
Reviewed-by: Abhishek Pandit-Subedi 
---

Changes in v3:
- Use pkt_type instead of adding new field

Changes in v2:
- Fix title

Changes in v1:
- Initial change

 include/net/bluetooth/hci_core.h |  1 +
 net/bluetooth/hci_conn.c | 20 ++--
 2 files changed, 19 insertions(+), 2 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 239ab72f16c6e..71468a9ea798a 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1237,6 +1237,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
 #define lmp_le_capable(dev)((dev)->features[0][4] & LMP_LE)
 #define lmp_sniffsubr_capable(dev) ((dev)->features[0][5] & LMP_SNIFF_SUBR)
 #define lmp_pause_enc_capable(dev) ((dev)->features[0][5] & LMP_PAUSE_ENC)
+#define lmp_esco_2m_capable(dev)   ((dev)->features[0][5] & LMP_EDR_ESCO_2M)
 #define lmp_ext_inq_capable(dev)   ((dev)->features[0][6] & LMP_EXT_INQ)
 #define lmp_le_br_capable(dev) (!!((dev)->features[0][6] & 
LMP_SIMUL_LE_BR))
 #define lmp_ssp_capable(dev)   ((dev)->features[0][6] & LMP_SIMPLE_PAIR)
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 07c34c55fc508..357ce0cfbc5c9 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -278,6 +278,20 @@ static void hci_add_sco(struct hci_conn *conn, __u16 
handle)
hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), );
 }
 
+static bool find_next_esco_param(struct hci_conn *conn,
+const struct sco_param *esco_param, int size)
+{
+   for (; conn->attempt <= size; conn->attempt++) {
+   if (lmp_esco_2m_capable(conn->link) ||
+   (esco_param[conn->attempt - 1].pkt_type & ESCO_2EV3))
+   break;
+   BT_DBG("hcon %p skipped attempt %d, eSCO 2M not supported",
+  conn, conn->attempt);
+   }
+
+   return conn->attempt <= size;
+}
+
 bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
 {
struct hci_dev *hdev = conn->hdev;
@@ -299,13 +313,15 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
 
switch (conn->setting & SCO_AIRMODE_MASK) {
case SCO_AIRMODE_TRANSP:
-   if (conn->attempt > ARRAY_SIZE(esco_param_msbc))
+   if (!find_next_esco_param(conn, esco_param_msbc,
+ ARRAY_SIZE(esco_param_msbc)))
return false;
param = _param_msbc[conn->attempt - 1];
break;
case SCO_AIRMODE_CVSD:
if (lmp_esco_capable(conn->link)) {
-   if (conn->attempt > ARRAY_SIZE(esco_param_cvsd))
+   if (!find_next_esco_param(conn, esco_param_cvsd,
+ ARRAY_SIZE(esco_param_cvsd)))
return false;
param = _param_cvsd[conn->attempt - 1];
} else {
-- 
2.30.0.365.g02bc693789-goog



[PATCH v2] Bluetooth: Skip eSCO 2M params when not supported

2021-01-27 Thread Yu Liu
If a peer device doesn't support eSCO 2M we should skip the params that
use it when setting up sync connection since they will always fail.

Signed-off-by: Yu Liu 
Reviewed-by: Abhishek Pandit-Subedi 
---

Changes in v2:
- Fix title

Changes in v1:
- Initial change

 include/net/bluetooth/hci_core.h |  1 +
 net/bluetooth/hci_conn.c | 39 +++-
 2 files changed, 29 insertions(+), 11 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 239ab72f16c6e..71468a9ea798a 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1237,6 +1237,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
 #define lmp_le_capable(dev)((dev)->features[0][4] & LMP_LE)
 #define lmp_sniffsubr_capable(dev) ((dev)->features[0][5] & LMP_SNIFF_SUBR)
 #define lmp_pause_enc_capable(dev) ((dev)->features[0][5] & LMP_PAUSE_ENC)
+#define lmp_esco_2m_capable(dev)   ((dev)->features[0][5] & LMP_EDR_ESCO_2M)
 #define lmp_ext_inq_capable(dev)   ((dev)->features[0][6] & LMP_EXT_INQ)
 #define lmp_le_br_capable(dev) (!!((dev)->features[0][6] & 
LMP_SIMUL_LE_BR))
 #define lmp_ssp_capable(dev)   ((dev)->features[0][6] & LMP_SIMPLE_PAIR)
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 07c34c55fc508..18740af603963 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -39,24 +39,25 @@ struct sco_param {
u16 pkt_type;
u16 max_latency;
u8  retrans_effort;
+   bool cap_2m_reqd;
 };
 
 static const struct sco_param esco_param_cvsd[] = {
-   { EDR_ESCO_MASK & ~ESCO_2EV3, 0x000a,   0x01 }, /* S3 */
-   { EDR_ESCO_MASK & ~ESCO_2EV3, 0x0007,   0x01 }, /* S2 */
-   { EDR_ESCO_MASK | ESCO_EV3,   0x0007,   0x01 }, /* S1 */
-   { EDR_ESCO_MASK | ESCO_HV3,   0x,   0x01 }, /* D1 */
-   { EDR_ESCO_MASK | ESCO_HV1,   0x,   0x01 }, /* D0 */
+   { EDR_ESCO_MASK & ~ESCO_2EV3, 0x000a,   0x01,   true  }, /* S3 */
+   { EDR_ESCO_MASK & ~ESCO_2EV3, 0x0007,   0x01,   true  }, /* S2 */
+   { EDR_ESCO_MASK | ESCO_EV3,   0x0007,   0x01,   false }, /* S1 */
+   { EDR_ESCO_MASK | ESCO_HV3,   0x,   0x01,   false }, /* D1 */
+   { EDR_ESCO_MASK | ESCO_HV1,   0x,   0x01,   false }, /* D0 */
 };
 
 static const struct sco_param sco_param_cvsd[] = {
-   { EDR_ESCO_MASK | ESCO_HV3,   0x,   0xff }, /* D1 */
-   { EDR_ESCO_MASK | ESCO_HV1,   0x,   0xff }, /* D0 */
+   { EDR_ESCO_MASK | ESCO_HV3,   0x,   0xff,   false }, /* D1 */
+   { EDR_ESCO_MASK | ESCO_HV1,   0x,   0xff,   false }, /* D0 */
 };
 
 static const struct sco_param esco_param_msbc[] = {
-   { EDR_ESCO_MASK & ~ESCO_2EV3, 0x000d,   0x02 }, /* T2 */
-   { EDR_ESCO_MASK | ESCO_EV3,   0x0008,   0x02 }, /* T1 */
+   { EDR_ESCO_MASK & ~ESCO_2EV3, 0x000d,   0x02,   true  }, /* T2 */
+   { EDR_ESCO_MASK | ESCO_EV3,   0x0008,   0x02,   false }, /* T1 */
 };
 
 /* This function requires the caller holds hdev->lock */
@@ -278,6 +279,20 @@ static void hci_add_sco(struct hci_conn *conn, __u16 
handle)
hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), );
 }
 
+static bool find_next_esco_param(struct hci_conn *conn,
+const struct sco_param *esco_param, int size)
+{
+   for (; conn->attempt <= size; conn->attempt++) {
+   if (lmp_esco_2m_capable(conn->link) ||
+   !esco_param[conn->attempt - 1].cap_2m_reqd)
+   break;
+   BT_DBG("hcon %p skipped attempt %d, eSCO 2M not supported",
+  conn, conn->attempt);
+   }
+
+   return conn->attempt <= size;
+}
+
 bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
 {
struct hci_dev *hdev = conn->hdev;
@@ -299,13 +314,15 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
 
switch (conn->setting & SCO_AIRMODE_MASK) {
case SCO_AIRMODE_TRANSP:
-   if (conn->attempt > ARRAY_SIZE(esco_param_msbc))
+   if (!find_next_esco_param(conn, esco_param_msbc,
+ ARRAY_SIZE(esco_param_msbc)))
return false;
param = _param_msbc[conn->attempt - 1];
break;
case SCO_AIRMODE_CVSD:
if (lmp_esco_capable(conn->link)) {
-   if (conn->attempt > ARRAY_SIZE(esco_param_cvsd))
+   if (!find_next_esco_param(conn, esco_param_cvsd,
+ ARRAY_SIZE(esco_param_cvsd)))
return false;
param = _param_cvsd[conn->attempt - 1];
} else {
-- 
2.30.0.280.ga3ce27912f-goog



[PATCH v1] Bluetooth: Skip eSCO 2M params when not supported.

2021-01-27 Thread Yu Liu
If a peer device doesn't support eSCO 2M we should skip the params that
use it when setting up sync connection since they will always fail.

Signed-off-by: Yu Liu 
Reviewed-by: Abhishek Pandit-Subedi 
---

Changes in v1:
- Initial change

 include/net/bluetooth/hci_core.h |  1 +
 net/bluetooth/hci_conn.c | 39 +++-
 2 files changed, 29 insertions(+), 11 deletions(-)

diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 239ab72f16c6e..71468a9ea798a 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1237,6 +1237,7 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
 #define lmp_le_capable(dev)((dev)->features[0][4] & LMP_LE)
 #define lmp_sniffsubr_capable(dev) ((dev)->features[0][5] & LMP_SNIFF_SUBR)
 #define lmp_pause_enc_capable(dev) ((dev)->features[0][5] & LMP_PAUSE_ENC)
+#define lmp_esco_2m_capable(dev)   ((dev)->features[0][5] & LMP_EDR_ESCO_2M)
 #define lmp_ext_inq_capable(dev)   ((dev)->features[0][6] & LMP_EXT_INQ)
 #define lmp_le_br_capable(dev) (!!((dev)->features[0][6] & 
LMP_SIMUL_LE_BR))
 #define lmp_ssp_capable(dev)   ((dev)->features[0][6] & LMP_SIMPLE_PAIR)
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 07c34c55fc508..18740af603963 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -39,24 +39,25 @@ struct sco_param {
u16 pkt_type;
u16 max_latency;
u8  retrans_effort;
+   bool cap_2m_reqd;
 };
 
 static const struct sco_param esco_param_cvsd[] = {
-   { EDR_ESCO_MASK & ~ESCO_2EV3, 0x000a,   0x01 }, /* S3 */
-   { EDR_ESCO_MASK & ~ESCO_2EV3, 0x0007,   0x01 }, /* S2 */
-   { EDR_ESCO_MASK | ESCO_EV3,   0x0007,   0x01 }, /* S1 */
-   { EDR_ESCO_MASK | ESCO_HV3,   0x,   0x01 }, /* D1 */
-   { EDR_ESCO_MASK | ESCO_HV1,   0x,   0x01 }, /* D0 */
+   { EDR_ESCO_MASK & ~ESCO_2EV3, 0x000a,   0x01,   true  }, /* S3 */
+   { EDR_ESCO_MASK & ~ESCO_2EV3, 0x0007,   0x01,   true  }, /* S2 */
+   { EDR_ESCO_MASK | ESCO_EV3,   0x0007,   0x01,   false }, /* S1 */
+   { EDR_ESCO_MASK | ESCO_HV3,   0x,   0x01,   false }, /* D1 */
+   { EDR_ESCO_MASK | ESCO_HV1,   0x,   0x01,   false }, /* D0 */
 };
 
 static const struct sco_param sco_param_cvsd[] = {
-   { EDR_ESCO_MASK | ESCO_HV3,   0x,   0xff }, /* D1 */
-   { EDR_ESCO_MASK | ESCO_HV1,   0x,   0xff }, /* D0 */
+   { EDR_ESCO_MASK | ESCO_HV3,   0x,   0xff,   false }, /* D1 */
+   { EDR_ESCO_MASK | ESCO_HV1,   0x,   0xff,   false }, /* D0 */
 };
 
 static const struct sco_param esco_param_msbc[] = {
-   { EDR_ESCO_MASK & ~ESCO_2EV3, 0x000d,   0x02 }, /* T2 */
-   { EDR_ESCO_MASK | ESCO_EV3,   0x0008,   0x02 }, /* T1 */
+   { EDR_ESCO_MASK & ~ESCO_2EV3, 0x000d,   0x02,   true  }, /* T2 */
+   { EDR_ESCO_MASK | ESCO_EV3,   0x0008,   0x02,   false }, /* T1 */
 };
 
 /* This function requires the caller holds hdev->lock */
@@ -278,6 +279,20 @@ static void hci_add_sco(struct hci_conn *conn, __u16 
handle)
hci_send_cmd(hdev, HCI_OP_ADD_SCO, sizeof(cp), );
 }
 
+static bool find_next_esco_param(struct hci_conn *conn,
+const struct sco_param *esco_param, int size)
+{
+   for (; conn->attempt <= size; conn->attempt++) {
+   if (lmp_esco_2m_capable(conn->link) ||
+   !esco_param[conn->attempt - 1].cap_2m_reqd)
+   break;
+   BT_DBG("hcon %p skipped attempt %d, eSCO 2M not supported",
+  conn, conn->attempt);
+   }
+
+   return conn->attempt <= size;
+}
+
 bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
 {
struct hci_dev *hdev = conn->hdev;
@@ -299,13 +314,15 @@ bool hci_setup_sync(struct hci_conn *conn, __u16 handle)
 
switch (conn->setting & SCO_AIRMODE_MASK) {
case SCO_AIRMODE_TRANSP:
-   if (conn->attempt > ARRAY_SIZE(esco_param_msbc))
+   if (!find_next_esco_param(conn, esco_param_msbc,
+ ARRAY_SIZE(esco_param_msbc)))
return false;
param = _param_msbc[conn->attempt - 1];
break;
case SCO_AIRMODE_CVSD:
if (lmp_esco_capable(conn->link)) {
-   if (conn->attempt > ARRAY_SIZE(esco_param_cvsd))
+   if (!find_next_esco_param(conn, esco_param_cvsd,
+ ARRAY_SIZE(esco_param_cvsd)))
return false;
param = _param_cvsd[conn->attempt - 1];
} else {
-- 
2.30.0.280.ga3ce27912f-goog