diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 8c94841072a8f02601072cce9b7ff750142c6608..ce7ef339b1c4c4827e7c08d81027d9c9f4bbe63a 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -4043,7 +4043,7 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, { struct mgmt_mode *cp = data; struct pending_cmd *cmd; - u8 status; + u8 val, status; int err; BT_DBG("request for %s", hdev->name); @@ -4058,7 +4058,7 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, MGMT_STATUS_NOT_SUPPORTED); - if (cp->val != 0x00 && cp->val != 0x01) + if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02) return cmd_status(sk, hdev->id, MGMT_OP_SET_SECURE_CONN, MGMT_STATUS_INVALID_PARAMS); @@ -4067,12 +4067,18 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, if (!hdev_is_powered(hdev)) { bool changed; - if (cp->val) + if (cp->val) { changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags); - else + if (cp->val == 0x02) + set_bit(HCI_SC_ONLY, &hdev->dev_flags); + else + clear_bit(HCI_SC_ONLY, &hdev->dev_flags); + } else { changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags); + clear_bit(HCI_SC_ONLY, &hdev->dev_flags); + } err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev); if (err < 0) @@ -4090,7 +4096,10 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, goto failed; } - if (!!cp->val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) { + val = !!cp->val; + + if (val == test_bit(HCI_SC_ENABLED, &hdev->dev_flags) && + (cp->val == 0x02) == test_bit(HCI_SC_ONLY, &hdev->dev_flags)) { err = send_settings_rsp(sk, MGMT_OP_SET_SECURE_CONN, hdev); goto failed; } @@ -4101,12 +4110,17 @@ static int set_secure_conn(struct sock *sk, struct hci_dev *hdev, goto failed; } - err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &cp->val); + err = hci_send_cmd(hdev, HCI_OP_WRITE_SC_SUPPORT, 1, &val); if (err < 0) { mgmt_pending_remove(cmd); goto failed; } + if (cp->val == 0x02) + set_bit(HCI_SC_ONLY, &hdev->dev_flags); + else + clear_bit(HCI_SC_ONLY, &hdev->dev_flags); + failed: hci_dev_unlock(hdev); return err; @@ -5063,19 +5077,24 @@ void mgmt_sc_enable_complete(struct hci_dev *hdev, u8 enable, u8 status) if (status) { u8 mgmt_err = mgmt_status(status); - if (enable && test_and_clear_bit(HCI_SC_ENABLED, - &hdev->dev_flags)) - new_settings(hdev, NULL); + if (enable) { + if (test_and_clear_bit(HCI_SC_ENABLED, + &hdev->dev_flags)) + new_settings(hdev, NULL); + clear_bit(HCI_SC_ONLY, &hdev->dev_flags); + } mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev, cmd_status_rsp, &mgmt_err); return; } - if (enable) + if (enable) { changed = !test_and_set_bit(HCI_SC_ENABLED, &hdev->dev_flags); - else + } else { changed = test_and_clear_bit(HCI_SC_ENABLED, &hdev->dev_flags); + clear_bit(HCI_SC_ONLY, &hdev->dev_flags); + } mgmt_pending_foreach(MGMT_OP_SET_SECURE_CONN, hdev, settings_rsp, &match);