aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2012-02-22 05:38:31 -0500
committerJohan Hedberg <johan.hedberg@intel.com>2012-02-23 06:06:58 -0500
commitc0ecddc2507da980af307aae40d6bcdea4c195dc (patch)
tree350d74d094791bf00ab69146f1a3947fb17afe34
parent2e99b0afc7445769bb886dc14a31aaa0dc17c4b5 (diff)
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,
1006int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type, 1006int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
1007 u8 addr_type, u8 status); 1007 u8 addr_type, u8 status);
1008int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status); 1008int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status);
1009int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status); 1009int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status);
1010int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status); 1010int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status);
1011int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash, 1011int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
1012 u8 *randomizer, u8 status); 1012 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)
427 427
428 BT_DBG("%s status 0x%x", hdev->name, status); 428 BT_DBG("%s status 0x%x", hdev->name, status);
429 429
430 if (status)
431 goto done;
432
433 sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_MODE); 430 sent = hci_sent_cmd_data(hdev, HCI_OP_WRITE_SSP_MODE);
434 if (!sent) 431 if (!sent)
435 return; 432 return;
436 433
437 if (*((u8 *) sent))
438 set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
439 else
440 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
441
442done:
443 if (test_bit(HCI_MGMT, &hdev->dev_flags)) 434 if (test_bit(HCI_MGMT, &hdev->dev_flags))
444 mgmt_ssp_enable_complete(hdev, status); 435 mgmt_ssp_enable_complete(hdev, *((u8 *) sent), status);
436 else if (!status) {
437 if (*((u8 *) sent))
438 set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
439 else
440 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
441 }
445} 442}
446 443
447static u8 hci_get_inquiry_mode(struct hci_dev *hdev) 444static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
@@ -560,7 +557,8 @@ static void hci_setup(struct hci_dev *hdev)
560 if (hdev->hci_ver > BLUETOOTH_VER_1_1) 557 if (hdev->hci_ver > BLUETOOTH_VER_1_1)
561 hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL); 558 hci_send_cmd(hdev, HCI_OP_READ_LOCAL_COMMANDS, 0, NULL);
562 559
563 if (hdev->features[6] & LMP_SIMPLE_PAIR) { 560 if (hdev->features[6] & LMP_SIMPLE_PAIR &&
561 test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
564 u8 mode = 0x01; 562 u8 mode = 0x01;
565 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode); 563 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(mode), &mode);
566 } 564 }
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)
1138 1138
1139 hci_dev_lock(hdev); 1139 hci_dev_lock(hdev);
1140 1140
1141 val = !!cp->val;
1142
1141 if (!hdev_is_powered(hdev)) { 1143 if (!hdev_is_powered(hdev)) {
1142 err = cmd_status(sk, index, MGMT_OP_SET_SSP, 1144 bool changed = false;
1143 MGMT_STATUS_NOT_POWERED); 1145
1146 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1147 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1148 changed = true;
1149 }
1150
1151 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1152 if (err < 0)
1153 goto failed;
1154
1155 if (changed)
1156 err = new_settings(hdev, sk);
1157
1144 goto failed; 1158 goto failed;
1145 } 1159 }
1146 1160
@@ -1155,8 +1169,6 @@ static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1155 goto failed; 1169 goto failed;
1156 } 1170 }
1157 1171
1158 val = !!cp->val;
1159
1160 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) { 1172 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1161 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev); 1173 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1162 goto failed; 1174 goto failed;
@@ -3393,21 +3405,37 @@ static int clear_eir(struct hci_dev *hdev)
3393 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp); 3405 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3394} 3406}
3395 3407
3396int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status) 3408int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3397{ 3409{
3398 struct cmd_lookup match = { NULL, hdev }; 3410 struct cmd_lookup match = { NULL, hdev };
3399 int err; 3411 bool changed = false;
3412 int err = 0;
3400 3413
3401 if (status) { 3414 if (status) {
3402 u8 mgmt_err = mgmt_status(status); 3415 u8 mgmt_err = mgmt_status(status);
3416
3417 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3418 &hdev->dev_flags))
3419 err = new_settings(hdev, NULL);
3420
3403 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, 3421 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3404 cmd_status_rsp, &mgmt_err); 3422 cmd_status_rsp, &mgmt_err);
3405 return 0; 3423
3424 return err;
3425 }
3426
3427 if (enable) {
3428 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3429 changed = true;
3430 } else {
3431 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3432 changed = true;
3406 } 3433 }
3407 3434
3408 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match); 3435 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3409 3436
3410 err = new_settings(hdev, match.sk); 3437 if (changed)
3438 err = new_settings(hdev, match.sk);
3411 3439
3412 if (match.sk) { 3440 if (match.sk) {
3413 sock_put(match.sk); 3441 sock_put(match.sk);