summaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorKuba Pawlak <kubax.t.pawlak@intel.com>2014-11-06 19:36:52 +0100
committerMarcel Holtmann <marcel@holtmann.org>2014-11-06 19:38:42 +0100
commit50fc85f1b04908301c463e5b963f16d18a90d5cc (patch)
tree25b58968cdfa61f1351b36e1e34f2fdd9017db43 /net/bluetooth
parentat86rf230: fix simple_return.cocci warnings (diff)
downloadlinux-50fc85f1b04908301c463e5b963f16d18a90d5cc.tar.xz
linux-50fc85f1b04908301c463e5b963f16d18a90d5cc.zip
Bluetooth: Clear role switch pending flag
If role switch was rejected by the controller and HCI Event: Command Status returned with status "Command Disallowed" (0x0C) the flag HCI_CONN_RSWITCH_PEND remains set. No further role switches are possible as this flag prevents us from sending any new HCI Switch Role requests and the only way to clear it is to receive a valid HCI Event Switch Role. This patch clears the flag if command was rejected. 2013-01-01 00:03:44.209913 < HCI Command: Switch Role (0x02|0x000b) plen 7 bdaddr BC:C6:DB:C4:6F:79 role 0x00 Role: Master 2013-01-01 00:03:44.210867 > HCI Event: Command Status (0x0f) plen 4 Switch Role (0x02|0x000b) status 0x0c ncmd 1 Error: Command Disallowed Signed-off-by: Kuba Pawlak <kubax.t.pawlak@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/hci_event.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 2f02ff0ed781..73d9bb4a2c1e 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1947,6 +1947,29 @@ unlock:
hci_dev_unlock(hdev);
}
+static void hci_cs_switch_role(struct hci_dev *hdev, u8 status)
+{
+ struct hci_cp_switch_role *cp;
+ struct hci_conn *conn;
+
+ BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+ if (!status)
+ return;
+
+ cp = hci_sent_cmd_data(hdev, HCI_OP_SWITCH_ROLE);
+ if (!cp)
+ return;
+
+ hci_dev_lock(hdev);
+
+ conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
+ if (conn)
+ clear_bit(HCI_CONN_RSWITCH_PEND, &conn->flags);
+
+ hci_dev_unlock(hdev);
+}
+
static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
{
__u8 status = *((__u8 *) skb->data);
@@ -2886,6 +2909,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
hci_cs_exit_sniff_mode(hdev, ev->status);
break;
+ case HCI_OP_SWITCH_ROLE:
+ hci_cs_switch_role(hdev, ev->status);
+ break;
+
case HCI_OP_DISCONNECT:
hci_cs_disconnect(hdev, ev->status);
break;