summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2012-02-22 12:38:31 +0200
committerJohan Hedberg <johan.hedberg@intel.com>2012-02-23 13:06:58 +0200
commitc0ecddc2507da980af307aae40d6bcdea4c195dc (patch)
tree350d74d094791bf00ab69146f1a3947fb17afe34
parent2e99b0afc7445769bb886dc14a31aaa0dc17c4b5 (diff)
downloadlinux-c0ecddc2507da980af307aae40d6bcdea4c195dc.tar.gz
linux-c0ecddc2507da980af307aae40d6bcdea4c195dc.tar.bz2
linux-c0ecddc2507da980af307aae40d6bcdea4c195dc.zip
Bluetooth: mgmt: Make Set SSP command callable while powered off
This patch makes it possible to enable SSP through mgmt even when powered off. The setting will then get automatically actiated when powering on. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Acked-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r--include/net/bluetooth/hci_core.h2
-rw-r--r--net/bluetooth/hci_event.c20
-rw-r--r--net/bluetooth/mgmt.c44
3 files changed, 46 insertions, 20 deletions
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 094b5dbdb130..6ba3a4b1078e 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -1006,7 +1006,7 @@ int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
u8 addr_type, u8 status);
int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status);
-int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status);
+int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status);
int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
u8 *randomizer, u8 status);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 1b1c3480a24d..240dc1640c04 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -427,21 +427,18 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
BT_DBG("%s status 0x%x", hdev->name, status);
- if (status)
- goto done;
-
sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_MODE);
if (!sent)
return;
- if (*((u8 *) sent))
- set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
- else
- clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
-
-done:
if (test_bit(HCI_MGMT, &hdev->dev_flags))
- mgmt_ssp_enable_complete(hdev, status);
+ mgmt_ssp_enable_complete(hdev, *((u8 *) sent), status);
+ else if (!status) {
+ if (*((u8 *) sent))
+ set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
+ else
+ clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
+ }
}
static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
@@ -560,7 +557,8 @@ static void hci_setup(struct hci_dev *hdev)
if (hdev->hci_ver > BLUETOOTH_VER_1_1)
hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
- if (hdev->features[6] & LMP_SIMPLE_PAIR) {
+ if (hdev->features[6] & LMP_SIMPLE_PAIR &&
+ test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
u8 mode = 0x01;
hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
}
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 69d4e1a699a3..eefd08468002 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1138,9 +1138,23 @@ static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
hci_dev_lock(hdev);
+ val = !!cp->val;
+
if (!hdev_is_powered(hdev)) {
- err = cmd_status(sk, index, MGMT_OP_SET_SSP,
- MGMT_STATUS_NOT_POWERED);
+ bool changed = false;
+
+ if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
+ change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
+ changed = true;
+ }
+
+ err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
+ if (err < 0)
+ goto failed;
+
+ if (changed)
+ err = new_settings(hdev, sk);
+
goto failed;
}
@@ -1155,8 +1169,6 @@ static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
goto failed;
}
- val = !!cp->val;
-
if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
goto failed;
@@ -3393,21 +3405,37 @@ static int clear_eir(struct hci_dev *hdev)
return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
}
-int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status)
+int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
{
struct cmd_lookup match = { NULL, hdev };
- int err;
+ bool changed = false;
+ int err = 0;
if (status) {
u8 mgmt_err = mgmt_status(status);
+
+ if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
+ &hdev->dev_flags))
+ err = new_settings(hdev, NULL);
+
mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
cmd_status_rsp, &mgmt_err);
- return 0;
+
+ return err;
+ }
+
+ if (enable) {
+ if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
+ changed = true;
+ } else {
+ if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
+ changed = true;
}
mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
- err = new_settings(hdev, match.sk);
+ if (changed)
+ err = new_settings(hdev, match.sk);
if (match.sk) {
sock_put(match.sk);