diff options
author | Johan Hedberg <johan.hedberg@intel.com> | 2013-03-15 18:06:55 -0400 |
---|---|---|
committer | Gustavo Padovan <gustavo.padovan@collabora.co.uk> | 2013-03-18 13:02:01 -0400 |
commit | 92da609750e75d5f46e809fd42e0cace61f6f4d5 (patch) | |
tree | 763dbb315b5f5ed6b479bbea19e2e4016af137d5 /net/bluetooth | |
parent | 0cab9c80ffc5006bf0f6922d805a7540e4949877 (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.c | 73 |
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 | ||
1381 | static 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 | |||
1396 | unlock: | ||
1397 | hci_dev_unlock(hdev); | ||
1398 | } | ||
1399 | |||
1400 | static 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 | |||
1381 | static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | 1407 | static 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 | ||
1479 | static 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 | |||
1451 | static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data, | 1486 | static 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 | ||
1564 | static 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 | |||
1527 | static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data, | 1571 | static 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 | ||
3703 | static void class_rsp(struct pending_cmd *cmd, void *data) | 3749 | static 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 | ||
3720 | int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class, | 3759 | int 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, |