aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2013-10-20 12:00:07 -0400
committerMarcel Holtmann <marcel@holtmann.org>2013-10-20 12:05:41 -0400
commit9a43e25fff07a94f40d4a9e1081458e30c840256 (patch)
treef1c855714f256f6aa5a26601c0af8e5b5d1b3c34 /net
parentb456f87cb0c726cf97ce1e88aecfcbacf1cdf5fe (diff)
Bluetooth: Update Set Discoverable to support LE
This patch updates the Set Discoverable management command to also be applicable for LE. In particular this affects the advertising flags where we can say "general discoverable" or "limited discoverable". Since the device flags may not be up-to-date when the advertising data is written this patch introduces a get_adv_discov_flags() helper function which also looks at any pending mgmt commands (a pending set_discoverable would be the exception when the flags are not yet correct). The patch also adds HCI_DISCOVERABLE flag clearing to the mgmt_discoverable_timeout function, since the code was previously relying on the mgmt_discoverable callback to handle this, which is only called for the BR/EDR-only HCI_Write_Scan_Enable command. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/mgmt.c80
1 files changed, 69 insertions, 11 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 796db5849795..bd91ee5f130c 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -599,12 +599,35 @@ static void update_scan_rsp_data(struct hci_request *req)
599 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp); 599 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
600} 600}
601 601
602static u8 get_adv_discov_flags(struct hci_dev *hdev)
603{
604 struct pending_cmd *cmd;
605
606 /* If there's a pending mgmt command the flags will not yet have
607 * their final values, so check for this first.
608 */
609 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
610 if (cmd) {
611 struct mgmt_mode *cp = cmd->param;
612 if (cp->val == 0x01)
613 return LE_AD_GENERAL;
614 else if (cp->val == 0x02)
615 return LE_AD_LIMITED;
616 } else {
617 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
618 return LE_AD_LIMITED;
619 else if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
620 return LE_AD_GENERAL;
621 }
622
623 return 0;
624}
625
602static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr) 626static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
603{ 627{
604 u8 ad_len = 0, flags = 0; 628 u8 ad_len = 0, flags = 0;
605 629
606 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) 630 flags |= get_adv_discov_flags(hdev);
607 flags |= LE_AD_GENERAL;
608 631
609 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) { 632 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
610 if (lmp_le_br_capable(hdev)) 633 if (lmp_le_br_capable(hdev))
@@ -1120,15 +1143,15 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
1120 struct pending_cmd *cmd; 1143 struct pending_cmd *cmd;
1121 struct hci_request req; 1144 struct hci_request req;
1122 u16 timeout; 1145 u16 timeout;
1123 u8 scan, status; 1146 u8 scan;
1124 int err; 1147 int err;
1125 1148
1126 BT_DBG("request for %s", hdev->name); 1149 BT_DBG("request for %s", hdev->name);
1127 1150
1128 status = mgmt_bredr_support(hdev); 1151 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1129 if (status) 1152 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1130 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, 1153 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1131 status); 1154 MGMT_STATUS_REJECTED);
1132 1155
1133 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02) 1156 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
1134 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE, 1157 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
@@ -1228,6 +1251,12 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
1228 1251
1229 hci_req_init(&req, hdev); 1252 hci_req_init(&req, hdev);
1230 1253
1254 /* The procedure for LE-only controllers is much simpler - just
1255 * update the advertising data.
1256 */
1257 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1258 goto update_ad;
1259
1231 scan = SCAN_PAGE; 1260 scan = SCAN_PAGE;
1232 1261
1233 if (cp->val) { 1262 if (cp->val) {
@@ -1260,6 +1289,9 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
1260 1289
1261 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan); 1290 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
1262 1291
1292update_ad:
1293 update_adv_data(&req);
1294
1263 err = hci_req_run(&req, set_discoverable_complete); 1295 err = hci_req_run(&req, set_discoverable_complete);
1264 if (err < 0) 1296 if (err < 0)
1265 mgmt_pending_remove(cmd); 1297 mgmt_pending_remove(cmd);
@@ -1451,8 +1483,17 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
1451 1483
1452 hci_req_init(&req, hdev); 1484 hci_req_init(&req, hdev);
1453 1485
1454 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) && 1486 /* If BR/EDR is not enabled and we disable advertising as a
1455 cp->val != test_bit(HCI_PSCAN, &hdev->flags)) { 1487 * by-product of disabling connectable, we need to update the
1488 * advertising flags.
1489 */
1490 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
1491 if (!cp->val) {
1492 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1493 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1494 }
1495 update_adv_data(&req);
1496 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
1456 if (cp->val) { 1497 if (cp->val) {
1457 scan = SCAN_PAGE; 1498 scan = SCAN_PAGE;
1458 } else { 1499 } else {
@@ -4348,6 +4389,7 @@ void mgmt_discoverable_timeout(struct hci_dev *hdev)
4348 * safe to unconditionally clear the flag. 4389 * safe to unconditionally clear the flag.
4349 */ 4390 */
4350 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags); 4391 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
4392 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
4351 4393
4352 hci_req_init(&req, hdev); 4394 hci_req_init(&req, hdev);
4353 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) { 4395 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
@@ -4356,10 +4398,13 @@ void mgmt_discoverable_timeout(struct hci_dev *hdev)
4356 sizeof(scan), &scan); 4398 sizeof(scan), &scan);
4357 } 4399 }
4358 update_class(&req); 4400 update_class(&req);
4401 update_adv_data(&req);
4359 hci_req_run(&req, NULL); 4402 hci_req_run(&req, NULL);
4360 4403
4361 hdev->discov_timeout = 0; 4404 hdev->discov_timeout = 0;
4362 4405
4406 new_settings(hdev, NULL);
4407
4363 hci_dev_unlock(hdev); 4408 hci_dev_unlock(hdev);
4364} 4409}
4365 4410
@@ -4374,13 +4419,26 @@ void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
4374 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev)) 4419 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
4375 return; 4420 return;
4376 4421
4377 if (discoverable) 4422 if (discoverable) {
4378 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags); 4423 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
4379 else 4424 } else {
4425 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
4380 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags); 4426 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
4427 }
4428
4429 if (changed) {
4430 struct hci_request req;
4431
4432 /* In case this change in discoverable was triggered by
4433 * a disabling of connectable there could be a need to
4434 * update the advertising flags.
4435 */
4436 hci_req_init(&req, hdev);
4437 update_adv_data(&req);
4438 hci_req_run(&req, NULL);
4381 4439
4382 if (changed)
4383 new_settings(hdev, NULL); 4440 new_settings(hdev, NULL);
4441 }
4384} 4442}
4385 4443
4386void mgmt_connectable(struct hci_dev *hdev, u8 connectable) 4444void mgmt_connectable(struct hci_dev *hdev, u8 connectable)