aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorJohan Hedberg <johan.hedberg@intel.com>2013-03-15 18:06:55 -0400
committerGustavo Padovan <gustavo.padovan@collabora.co.uk>2013-03-18 13:02:01 -0400
commit92da609750e75d5f46e809fd42e0cace61f6f4d5 (patch)
tree763dbb315b5f5ed6b479bbea19e2e4016af137d5 /net/bluetooth
parent0cab9c80ffc5006bf0f6922d805a7540e4949877 (diff)
Bluetooth: Fix UUID/class mgmt command response synchronization
We should only return a mgmt command complete once all HCI commands to a mgmt_set_dev_class or mgmt_add/remove_uuid command have completed. This patch fixes the issue by having a proper async request complete callback for these actions and responding to user space in the callback. Signed-off-by: Johan Hedberg <johan.hedberg@intel.com> Acked-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: Gustavo Padovan <gustavo.padovan@collabora.co.uk>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/mgmt.c73
1 files changed, 56 insertions, 17 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 367837d0da2d..8a0bbb914bed 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -1378,6 +1378,32 @@ static u8 get_uuid_size(const u8 *uuid)
1378 return 16; 1378 return 16;
1379} 1379}
1380 1380
1381static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1382{
1383 struct pending_cmd *cmd;
1384
1385 hci_dev_lock(hdev);
1386
1387 cmd = mgmt_pending_find(mgmt_op, hdev);
1388 if (!cmd)
1389 goto unlock;
1390
1391 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1392 hdev->dev_class, 3);
1393
1394 mgmt_pending_remove(cmd);
1395
1396unlock:
1397 hci_dev_unlock(hdev);
1398}
1399
1400static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1401{
1402 BT_DBG("status 0x%02x", status);
1403
1404 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1405}
1406
1381static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) 1407static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
1382{ 1408{
1383 struct mgmt_cp_add_uuid *cp = data; 1409 struct mgmt_cp_add_uuid *cp = data;
@@ -1413,9 +1439,11 @@ static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
1413 update_class(&req); 1439 update_class(&req);
1414 update_eir(&req); 1440 update_eir(&req);
1415 1441
1416 hci_req_run(&req, NULL); 1442 err = hci_req_run(&req, add_uuid_complete);
1443 if (err < 0) {
1444 if (err != -ENODATA)
1445 goto failed;
1417 1446
1418 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1419 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0, 1447 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
1420 hdev->dev_class, 3); 1448 hdev->dev_class, 3);
1421 goto failed; 1449 goto failed;
@@ -1448,6 +1476,13 @@ static bool enable_service_cache(struct hci_dev *hdev)
1448 return false; 1476 return false;
1449} 1477}
1450 1478
1479static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1480{
1481 BT_DBG("status 0x%02x", status);
1482
1483 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1484}
1485
1451static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, 1486static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
1452 u16 len) 1487 u16 len)
1453{ 1488{
@@ -1503,9 +1538,11 @@ update_class:
1503 update_class(&req); 1538 update_class(&req);
1504 update_eir(&req); 1539 update_eir(&req);
1505 1540
1506 hci_req_run(&req, NULL); 1541 err = hci_req_run(&req, remove_uuid_complete);
1542 if (err < 0) {
1543 if (err != -ENODATA)
1544 goto unlock;
1507 1545
1508 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1509 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0, 1546 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
1510 hdev->dev_class, 3); 1547 hdev->dev_class, 3);
1511 goto unlock; 1548 goto unlock;
@@ -1524,6 +1561,13 @@ unlock:
1524 return err; 1561 return err;
1525} 1562}
1526 1563
1564static void set_class_complete(struct hci_dev *hdev, u8 status)
1565{
1566 BT_DBG("status 0x%02x", status);
1567
1568 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1569}
1570
1527static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, 1571static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
1528 u16 len) 1572 u16 len)
1529{ 1573{
@@ -1572,9 +1616,11 @@ static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
1572 1616
1573 update_class(&req); 1617 update_class(&req);
1574 1618
1575 hci_req_run(&req, NULL); 1619 err = hci_req_run(&req, set_class_complete);
1620 if (err < 0) {
1621 if (err != -ENODATA)
1622 goto unlock;
1576 1623
1577 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
1578 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0, 1624 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
1579 hdev->dev_class, 3); 1625 hdev->dev_class, 3);
1580 goto unlock; 1626 goto unlock;
@@ -3700,21 +3746,14 @@ int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3700 return err; 3746 return err;
3701} 3747}
3702 3748
3703static void class_rsp(struct pending_cmd *cmd, void *data) 3749static void sk_lookup(struct pending_cmd *cmd, void *data)
3704{ 3750{
3705 struct cmd_lookup *match = data; 3751 struct cmd_lookup *match = data;
3706 3752
3707 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
3708 match->hdev->dev_class, 3);
3709
3710 list_del(&cmd->list);
3711
3712 if (match->sk == NULL) { 3753 if (match->sk == NULL) {
3713 match->sk = cmd->sk; 3754 match->sk = cmd->sk;
3714 sock_hold(match->sk); 3755 sock_hold(match->sk);
3715 } 3756 }
3716
3717 mgmt_pending_free(cmd);
3718} 3757}
3719 3758
3720int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, 3759int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
@@ -3725,9 +3764,9 @@ int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
3725 3764
3726 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags); 3765 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3727 3766
3728 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match); 3767 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
3729 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match); 3768 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
3730 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match); 3769 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
3731 3770
3732 if (!status) 3771 if (!status)
3733 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3772 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,