Commit efc7688b authored by Marcel Holtmann's avatar Marcel Holtmann

Bluetooth: Add SCO fallback for eSCO connection attempts

When attempting to setup eSCO connections it can happen that some link
manager implementations fail to properly negotiate the eSCO parameters
and thus fail the eSCO setup. Normally the link manager is responsible
for the negotiation of the parameters and actually fallback to SCO if
no agreement can be reached. In cases where the link manager is just too
stupid, then at least try to establish a SCO link if eSCO fails.

For the Bluetooth devices with EDR support this includes handling packet
types of EDR basebands. This is particular tricky since for the EDR the
logic of enabling/disabling one specific packet type is turned around.
This fix contains an extra bitmask to disable eSCO EDR packet when
trying to fallback to a SCO connection.
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 255c7601
...@@ -133,8 +133,13 @@ enum { ...@@ -133,8 +133,13 @@ enum {
#define ESCO_EV3 0x0008 #define ESCO_EV3 0x0008
#define ESCO_EV4 0x0010 #define ESCO_EV4 0x0010
#define ESCO_EV5 0x0020 #define ESCO_EV5 0x0020
#define ESCO_2EV3 0x0040
#define ESCO_3EV3 0x0080
#define ESCO_2EV5 0x0100
#define ESCO_3EV5 0x0200
#define SCO_ESCO_MASK (ESCO_HV1 | ESCO_HV2 | ESCO_HV3) #define SCO_ESCO_MASK (ESCO_HV1 | ESCO_HV2 | ESCO_HV3)
#define EDR_ESCO_MASK (ESCO_2EV3 | ESCO_3EV3 | ESCO_2EV5 | ESCO_3EV5)
/* ACL flags */ /* ACL flags */
#define ACL_CONT 0x01 #define ACL_CONT 0x01
...@@ -176,6 +181,9 @@ enum { ...@@ -176,6 +181,9 @@ enum {
#define LMP_EV5 0x02 #define LMP_EV5 0x02
#define LMP_SNIFF_SUBR 0x02 #define LMP_SNIFF_SUBR 0x02
#define LMP_EDR_ESCO_2M 0x20
#define LMP_EDR_ESCO_3M 0x40
#define LMP_EDR_3S_ESCO 0x80
#define LMP_SIMPLE_PAIR 0x08 #define LMP_SIMPLE_PAIR 0x08
......
...@@ -123,6 +123,8 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle) ...@@ -123,6 +123,8 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
conn->state = BT_CONNECT; conn->state = BT_CONNECT;
conn->out = 1; conn->out = 1;
conn->attempt++;
cp.handle = cpu_to_le16(handle); cp.handle = cpu_to_le16(handle);
cp.pkt_type = cpu_to_le16(conn->pkt_type); cp.pkt_type = cpu_to_le16(conn->pkt_type);
...@@ -139,6 +141,8 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle) ...@@ -139,6 +141,8 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
conn->state = BT_CONNECT; conn->state = BT_CONNECT;
conn->out = 1; conn->out = 1;
conn->attempt++;
cp.handle = cpu_to_le16(handle); cp.handle = cpu_to_le16(handle);
cp.pkt_type = cpu_to_le16(conn->pkt_type); cp.pkt_type = cpu_to_le16(conn->pkt_type);
...@@ -216,12 +220,13 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst) ...@@ -216,12 +220,13 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
break; break;
case SCO_LINK: case SCO_LINK:
if (lmp_esco_capable(hdev)) if (lmp_esco_capable(hdev))
conn->pkt_type = hdev->esco_type & SCO_ESCO_MASK; conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
(hdev->esco_type & EDR_ESCO_MASK);
else else
conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK; conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK;
break; break;
case ESCO_LINK: case ESCO_LINK:
conn->pkt_type = hdev->esco_type; conn->pkt_type = hdev->esco_type & ~EDR_ESCO_MASK;
break; break;
} }
......
...@@ -484,6 +484,15 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb ...@@ -484,6 +484,15 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb
if (hdev->features[4] & LMP_EV5) if (hdev->features[4] & LMP_EV5)
hdev->esco_type |= (ESCO_EV5); hdev->esco_type |= (ESCO_EV5);
if (hdev->features[5] & LMP_EDR_ESCO_2M)
hdev->esco_type |= (ESCO_2EV3);
if (hdev->features[5] & LMP_EDR_ESCO_3M)
hdev->esco_type |= (ESCO_3EV3);
if (hdev->features[5] & LMP_EDR_3S_ESCO)
hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5);
BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name, BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name,
hdev->features[0], hdev->features[1], hdev->features[0], hdev->features[1],
hdev->features[2], hdev->features[3], hdev->features[2], hdev->features[3],
...@@ -1639,6 +1648,13 @@ static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_bu ...@@ -1639,6 +1648,13 @@ static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_bu
conn->type = SCO_LINK; conn->type = SCO_LINK;
} }
if (conn->out && ev->status == 0x1c && conn->attempt < 2) {
conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
(hdev->esco_type & EDR_ESCO_MASK);
hci_setup_sync(conn, conn->link->handle);
goto unlock;
}
if (!ev->status) { if (!ev->status) {
conn->handle = __le16_to_cpu(ev->handle); conn->handle = __le16_to_cpu(ev->handle);
conn->state = BT_CONNECTED; conn->state = BT_CONNECTED;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment