diff options
author | Szymon Janc <szymon.janc@tieto.com> | 2014-11-03 08:20:56 -0500 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@intel.com> | 2014-11-03 08:43:05 -0500 |
commit | a736abc1ac09b824387fb75b2aa7887c6e3ed68a (patch) | |
tree | 8f2a6db8d601faec39c850882ec709d39175f653 | |
parent | 845472e8d50c898c73b4f69f4edad5249b13d6a9 (diff) |
Bluetooth: Fix invalid response for 'Start Discovery' command
According to Management Interface API 'Start Discovery' command should
generate a Command Complete event on failure. Currently kernel is
sending Command Status on early errors. This results in userspace
ignoring such event due to invalid size.
bluetoothd[28499]: src/adapter.c:trigger_start_discovery()
bluetoothd[28499]: src/adapter.c:cancel_passive_scanning()
bluetoothd[28499]: src/adapter.c:start_discovery_timeout()
bluetoothd[28499]: src/adapter.c:start_discovery_complete() status 0x0a
bluetoothd[28499]: Wrong size of start discovery return parameters
Reported-by: Jukka Taimisto <jtt@codenomicon.com>
Signed-off-by: Szymon Janc <szymon.janc@tieto.com>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
-rw-r--r-- | net/bluetooth/mgmt.c | 56 |
1 files changed, 35 insertions, 21 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 9c4daf715cf8..ce0272c6f71f 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -3727,20 +3727,23 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, | |||
3727 | hci_dev_lock(hdev); | 3727 | hci_dev_lock(hdev); |
3728 | 3728 | ||
3729 | if (!hdev_is_powered(hdev)) { | 3729 | if (!hdev_is_powered(hdev)) { |
3730 | err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, | 3730 | err = cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY, |
3731 | MGMT_STATUS_NOT_POWERED); | 3731 | MGMT_STATUS_NOT_POWERED, |
3732 | &cp->type, sizeof(cp->type)); | ||
3732 | goto failed; | 3733 | goto failed; |
3733 | } | 3734 | } |
3734 | 3735 | ||
3735 | if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) { | 3736 | if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) { |
3736 | err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, | 3737 | err = cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY, |
3737 | MGMT_STATUS_BUSY); | 3738 | MGMT_STATUS_BUSY, &cp->type, |
3739 | sizeof(cp->type)); | ||
3738 | goto failed; | 3740 | goto failed; |
3739 | } | 3741 | } |
3740 | 3742 | ||
3741 | if (hdev->discovery.state != DISCOVERY_STOPPED) { | 3743 | if (hdev->discovery.state != DISCOVERY_STOPPED) { |
3742 | err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, | 3744 | err = cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY, |
3743 | MGMT_STATUS_BUSY); | 3745 | MGMT_STATUS_BUSY, &cp->type, |
3746 | sizeof(cp->type)); | ||
3744 | goto failed; | 3747 | goto failed; |
3745 | } | 3748 | } |
3746 | 3749 | ||
@@ -3758,15 +3761,18 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, | |||
3758 | case DISCOV_TYPE_BREDR: | 3761 | case DISCOV_TYPE_BREDR: |
3759 | status = mgmt_bredr_support(hdev); | 3762 | status = mgmt_bredr_support(hdev); |
3760 | if (status) { | 3763 | if (status) { |
3761 | err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, | 3764 | err = cmd_complete(sk, hdev->id, |
3762 | status); | 3765 | MGMT_OP_START_DISCOVERY, status, |
3766 | &cp->type, sizeof(cp->type)); | ||
3763 | mgmt_pending_remove(cmd); | 3767 | mgmt_pending_remove(cmd); |
3764 | goto failed; | 3768 | goto failed; |
3765 | } | 3769 | } |
3766 | 3770 | ||
3767 | if (test_bit(HCI_INQUIRY, &hdev->flags)) { | 3771 | if (test_bit(HCI_INQUIRY, &hdev->flags)) { |
3768 | err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, | 3772 | err = cmd_complete(sk, hdev->id, |
3769 | MGMT_STATUS_BUSY); | 3773 | MGMT_OP_START_DISCOVERY, |
3774 | MGMT_STATUS_BUSY, &cp->type, | ||
3775 | sizeof(cp->type)); | ||
3770 | mgmt_pending_remove(cmd); | 3776 | mgmt_pending_remove(cmd); |
3771 | goto failed; | 3777 | goto failed; |
3772 | } | 3778 | } |
@@ -3783,16 +3789,19 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, | |||
3783 | case DISCOV_TYPE_INTERLEAVED: | 3789 | case DISCOV_TYPE_INTERLEAVED: |
3784 | status = mgmt_le_support(hdev); | 3790 | status = mgmt_le_support(hdev); |
3785 | if (status) { | 3791 | if (status) { |
3786 | err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, | 3792 | err = cmd_complete(sk, hdev->id, |
3787 | status); | 3793 | MGMT_OP_START_DISCOVERY, status, |
3794 | &cp->type, sizeof(cp->type)); | ||
3788 | mgmt_pending_remove(cmd); | 3795 | mgmt_pending_remove(cmd); |
3789 | goto failed; | 3796 | goto failed; |
3790 | } | 3797 | } |
3791 | 3798 | ||
3792 | if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED && | 3799 | if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED && |
3793 | !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) { | 3800 | !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) { |
3794 | err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, | 3801 | err = cmd_complete(sk, hdev->id, |
3795 | MGMT_STATUS_NOT_SUPPORTED); | 3802 | MGMT_OP_START_DISCOVERY, |
3803 | MGMT_STATUS_NOT_SUPPORTED, | ||
3804 | &cp->type, sizeof(cp->type)); | ||
3796 | mgmt_pending_remove(cmd); | 3805 | mgmt_pending_remove(cmd); |
3797 | goto failed; | 3806 | goto failed; |
3798 | } | 3807 | } |
@@ -3804,9 +3813,11 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, | |||
3804 | */ | 3813 | */ |
3805 | if (hci_conn_hash_lookup_state(hdev, LE_LINK, | 3814 | if (hci_conn_hash_lookup_state(hdev, LE_LINK, |
3806 | BT_CONNECT)) { | 3815 | BT_CONNECT)) { |
3807 | err = cmd_status(sk, hdev->id, | 3816 | err = cmd_complete(sk, hdev->id, |
3808 | MGMT_OP_START_DISCOVERY, | 3817 | MGMT_OP_START_DISCOVERY, |
3809 | MGMT_STATUS_REJECTED); | 3818 | MGMT_STATUS_REJECTED, |
3819 | &cp->type, | ||
3820 | sizeof(cp->type)); | ||
3810 | mgmt_pending_remove(cmd); | 3821 | mgmt_pending_remove(cmd); |
3811 | goto failed; | 3822 | goto failed; |
3812 | } | 3823 | } |
@@ -3829,8 +3840,10 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, | |||
3829 | */ | 3840 | */ |
3830 | err = hci_update_random_address(&req, true, &own_addr_type); | 3841 | err = hci_update_random_address(&req, true, &own_addr_type); |
3831 | if (err < 0) { | 3842 | if (err < 0) { |
3832 | err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, | 3843 | err = cmd_complete(sk, hdev->id, |
3833 | MGMT_STATUS_FAILED); | 3844 | MGMT_OP_START_DISCOVERY, |
3845 | MGMT_STATUS_FAILED, | ||
3846 | &cp->type, sizeof(cp->type)); | ||
3834 | mgmt_pending_remove(cmd); | 3847 | mgmt_pending_remove(cmd); |
3835 | goto failed; | 3848 | goto failed; |
3836 | } | 3849 | } |
@@ -3850,8 +3863,9 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, | |||
3850 | break; | 3863 | break; |
3851 | 3864 | ||
3852 | default: | 3865 | default: |
3853 | err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY, | 3866 | err = cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY, |
3854 | MGMT_STATUS_INVALID_PARAMS); | 3867 | MGMT_STATUS_INVALID_PARAMS, |
3868 | &cp->type, sizeof(cp->type)); | ||
3855 | mgmt_pending_remove(cmd); | 3869 | mgmt_pending_remove(cmd); |
3856 | goto failed; | 3870 | goto failed; |
3857 | } | 3871 | } |