aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/mgmt.c
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2012-02-23 16:09:40 -0500
committerJohan Hedberg <johan.hedberg@intel.com>2012-02-23 17:15:26 -0500
commit90e704543d6702971ecfe3fe2325829d89b76f6b (patch)
tree6c124ca14e56456ebe838003ca97e5c867c0d404 /net/bluetooth/mgmt.c
parentc95f0ba76f902bc8b540468b695bcfe8948e8e46 (diff)
Bluetooth: mgmt: Fix dev_class related command response timing
All mgmt commands that may fire off a hci_write_class_of_device command should wait for the completion of the HCI command before sending a response to user space. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Acked-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/bluetooth/mgmt.c')
-rw-r--r--net/bluetooth/mgmt.c70
1 files changed, 65 insertions, 5 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 9f912dc71bae..7a906d6e0236 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1332,6 +1332,7 @@ failed:
1332static int add_uuid(struct sock *sk, u16 index, void *data, u16 len) 1332static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
1333{ 1333{
1334 struct mgmt_cp_add_uuid *cp = data; 1334 struct mgmt_cp_add_uuid *cp = data;
1335 struct pending_cmd *cmd;
1335 struct hci_dev *hdev; 1336 struct hci_dev *hdev;
1336 struct bt_uuid *uuid; 1337 struct bt_uuid *uuid;
1337 int err; 1338 int err;
@@ -1374,7 +1375,17 @@ static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
1374 if (err < 0) 1375 if (err < 0)
1375 goto failed; 1376 goto failed;
1376 1377
1377 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, hdev->dev_class, 3); 1378 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1379 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0,
1380 hdev->dev_class, 3);
1381 goto failed;
1382 }
1383
1384 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
1385 if (!cmd) {
1386 err = -ENOMEM;
1387 goto failed;
1388 }
1378 1389
1379failed: 1390failed:
1380 hci_dev_unlock(hdev); 1391 hci_dev_unlock(hdev);
@@ -1386,6 +1397,7 @@ failed:
1386static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len) 1397static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
1387{ 1398{
1388 struct mgmt_cp_remove_uuid *cp = data; 1399 struct mgmt_cp_remove_uuid *cp = data;
1400 struct pending_cmd *cmd;
1389 struct list_head *p, *n; 1401 struct list_head *p, *n;
1390 struct hci_dev *hdev; 1402 struct hci_dev *hdev;
1391 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 1403 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
@@ -1448,8 +1460,17 @@ update_class:
1448 if (err < 0) 1460 if (err < 0)
1449 goto unlock; 1461 goto unlock;
1450 1462
1451 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, 1463 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1464 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0,
1452 hdev->dev_class, 3); 1465 hdev->dev_class, 3);
1466 goto unlock;
1467 }
1468
1469 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
1470 if (!cmd) {
1471 err = -ENOMEM;
1472 goto unlock;
1473 }
1453 1474
1454unlock: 1475unlock:
1455 hci_dev_unlock(hdev); 1476 hci_dev_unlock(hdev);
@@ -1462,6 +1483,7 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
1462{ 1483{
1463 struct hci_dev *hdev; 1484 struct hci_dev *hdev;
1464 struct mgmt_cp_set_dev_class *cp = data; 1485 struct mgmt_cp_set_dev_class *cp = data;
1486 struct pending_cmd *cmd;
1465 int err; 1487 int err;
1466 1488
1467 BT_DBG("request for hci%u", index); 1489 BT_DBG("request for hci%u", index);
@@ -1500,10 +1522,20 @@ static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
1500 } 1522 }
1501 1523
1502 err = update_class(hdev); 1524 err = update_class(hdev);
1525 if (err < 0)
1526 goto unlock;
1503 1527
1504 if (err == 0) 1528 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1505 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0, 1529 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1506 hdev->dev_class, 3); 1530 hdev->dev_class, 3);
1531 goto unlock;
1532 }
1533
1534 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
1535 if (!cmd) {
1536 err = -ENOMEM;
1537 goto unlock;
1538 }
1507 1539
1508unlock: 1540unlock:
1509 hci_dev_unlock(hdev); 1541 hci_dev_unlock(hdev);
@@ -3110,6 +3142,7 @@ int mgmt_index_removed(struct hci_dev *hdev)
3110struct cmd_lookup { 3142struct cmd_lookup {
3111 struct sock *sk; 3143 struct sock *sk;
3112 struct hci_dev *hdev; 3144 struct hci_dev *hdev;
3145 u8 mgmt_status;
3113}; 3146};
3114 3147
3115static void settings_rsp(struct pending_cmd *cmd, void *data) 3148static void settings_rsp(struct pending_cmd *cmd, void *data)
@@ -3632,14 +3665,41 @@ int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3632 return err; 3665 return err;
3633} 3666}
3634 3667
3668static void class_rsp(struct pending_cmd *cmd, void *data)
3669{
3670 struct cmd_lookup *match = data;
3671
3672 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
3673 match->hdev->dev_class, 3);
3674
3675 list_del(&cmd->list);
3676
3677 if (match->sk == NULL) {
3678 match->sk = cmd->sk;
3679 sock_hold(match->sk);
3680 }
3681
3682 mgmt_pending_free(cmd);
3683}
3684
3635int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, 3685int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
3636 u8 status) 3686 u8 status)
3637{ 3687{
3638 int err; 3688 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3689 int err = 0;
3639 3690
3640 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags); 3691 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3641 3692
3642 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3, NULL); 3693 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3694 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3695 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3696
3697 if (!status)
3698 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3699 dev_class, 3, NULL);
3700
3701 if (match.sk)
3702 sock_put(match.sk);
3643 3703
3644 return err; 3704 return err;
3645} 3705}