diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2014-12-04 05:36:36 -0500 |
---|---|---|
committer | Johan Hedberg <johan.hedberg@intel.com> | 2014-12-04 05:52:29 -0500 |
commit | 8019044dcb5944c0f578a1e59cecbd09d7b7c7f3 (patch) | |
tree | c5deaac5141acf76c2f46135c954b02696f4c7b0 /net | |
parent | 11e6e25d052478235a0c3f94d2f2faddeb58eb96 (diff) |
Bluetooth: Split triggering of discovery commands into separate function
The actual process of compiling the correct HCI commands for triggering
discovery is something that should be generic. So instead of mixing it
into the Start Discover operation handling, split it out into its own
function utilizing HCI request handling and just providing status in
case of errors or invalid parameters.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/mgmt.c | 214 |
1 files changed, 100 insertions, 114 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 311984fcac55..415ba4179326 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -3686,6 +3686,103 @@ done: | |||
3686 | return err; | 3686 | return err; |
3687 | } | 3687 | } |
3688 | 3688 | ||
3689 | static bool trigger_discovery(struct hci_request *req, u8 *status) | ||
3690 | { | ||
3691 | struct hci_dev *hdev = req->hdev; | ||
3692 | struct hci_cp_le_set_scan_param param_cp; | ||
3693 | struct hci_cp_le_set_scan_enable enable_cp; | ||
3694 | struct hci_cp_inquiry inq_cp; | ||
3695 | /* General inquiry access code (GIAC) */ | ||
3696 | u8 lap[3] = { 0x33, 0x8b, 0x9e }; | ||
3697 | u8 own_addr_type; | ||
3698 | int err; | ||
3699 | |||
3700 | switch (hdev->discovery.type) { | ||
3701 | case DISCOV_TYPE_BREDR: | ||
3702 | *status = mgmt_bredr_support(hdev); | ||
3703 | if (*status) | ||
3704 | return false; | ||
3705 | |||
3706 | if (test_bit(HCI_INQUIRY, &hdev->flags)) { | ||
3707 | *status = MGMT_STATUS_BUSY; | ||
3708 | return false; | ||
3709 | } | ||
3710 | |||
3711 | hci_inquiry_cache_flush(hdev); | ||
3712 | |||
3713 | memset(&inq_cp, 0, sizeof(inq_cp)); | ||
3714 | memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap)); | ||
3715 | inq_cp.length = DISCOV_BREDR_INQUIRY_LEN; | ||
3716 | hci_req_add(req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp); | ||
3717 | break; | ||
3718 | |||
3719 | case DISCOV_TYPE_LE: | ||
3720 | case DISCOV_TYPE_INTERLEAVED: | ||
3721 | *status = mgmt_le_support(hdev); | ||
3722 | if (*status) | ||
3723 | return false; | ||
3724 | |||
3725 | if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED && | ||
3726 | !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) { | ||
3727 | *status = MGMT_STATUS_NOT_SUPPORTED; | ||
3728 | return false; | ||
3729 | } | ||
3730 | |||
3731 | if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) { | ||
3732 | /* Don't let discovery abort an outgoing | ||
3733 | * connection attempt that's using directed | ||
3734 | * advertising. | ||
3735 | */ | ||
3736 | if (hci_conn_hash_lookup_state(hdev, LE_LINK, | ||
3737 | BT_CONNECT)) { | ||
3738 | *status = MGMT_STATUS_REJECTED; | ||
3739 | return false; | ||
3740 | } | ||
3741 | |||
3742 | disable_advertising(req); | ||
3743 | } | ||
3744 | |||
3745 | /* If controller is scanning, it means the background scanning | ||
3746 | * is running. Thus, we should temporarily stop it in order to | ||
3747 | * set the discovery scanning parameters. | ||
3748 | */ | ||
3749 | if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) | ||
3750 | hci_req_add_le_scan_disable(req); | ||
3751 | |||
3752 | memset(¶m_cp, 0, sizeof(param_cp)); | ||
3753 | |||
3754 | /* All active scans will be done with either a resolvable | ||
3755 | * private address (when privacy feature has been enabled) | ||
3756 | * or unresolvable private address. | ||
3757 | */ | ||
3758 | err = hci_update_random_address(req, true, &own_addr_type); | ||
3759 | if (err < 0) { | ||
3760 | *status = MGMT_STATUS_FAILED; | ||
3761 | return false; | ||
3762 | } | ||
3763 | |||
3764 | param_cp.type = LE_SCAN_ACTIVE; | ||
3765 | param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT); | ||
3766 | param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN); | ||
3767 | param_cp.own_address_type = own_addr_type; | ||
3768 | hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp), | ||
3769 | ¶m_cp); | ||
3770 | |||
3771 | memset(&enable_cp, 0, sizeof(enable_cp)); | ||
3772 | enable_cp.enable = LE_SCAN_ENABLE; | ||
3773 | enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE; | ||
3774 | hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp), | ||
3775 | &enable_cp); | ||
3776 | break; | ||
3777 | |||
3778 | default: | ||
3779 | *status = MGMT_STATUS_INVALID_PARAMS; | ||
3780 | return false; | ||
3781 | } | ||
3782 | |||
3783 | return true; | ||
3784 | } | ||
3785 | |||
3689 | static void start_discovery_complete(struct hci_dev *hdev, u8 status) | 3786 | static void start_discovery_complete(struct hci_dev *hdev, u8 status) |
3690 | { | 3787 | { |
3691 | struct pending_cmd *cmd; | 3788 | struct pending_cmd *cmd; |
@@ -3740,13 +3837,8 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, | |||
3740 | { | 3837 | { |
3741 | struct mgmt_cp_start_discovery *cp = data; | 3838 | struct mgmt_cp_start_discovery *cp = data; |
3742 | struct pending_cmd *cmd; | 3839 | struct pending_cmd *cmd; |
3743 | struct hci_cp_le_set_scan_param param_cp; | ||
3744 | struct hci_cp_le_set_scan_enable enable_cp; | ||
3745 | struct hci_cp_inquiry inq_cp; | ||
3746 | struct hci_request req; | 3840 | struct hci_request req; |
3747 | /* General inquiry access code (GIAC) */ | 3841 | u8 status; |
3748 | u8 lap[3] = { 0x33, 0x8b, 0x9e }; | ||
3749 | u8 status, own_addr_type; | ||
3750 | int err; | 3842 | int err; |
3751 | 3843 | ||
3752 | BT_DBG("%s", hdev->name); | 3844 | BT_DBG("%s", hdev->name); |
@@ -3778,115 +3870,9 @@ static int start_discovery(struct sock *sk, struct hci_dev *hdev, | |||
3778 | 3870 | ||
3779 | hci_req_init(&req, hdev); | 3871 | hci_req_init(&req, hdev); |
3780 | 3872 | ||
3781 | switch (hdev->discovery.type) { | 3873 | if (!trigger_discovery(&req, &status)) { |
3782 | case DISCOV_TYPE_BREDR: | ||
3783 | status = mgmt_bredr_support(hdev); | ||
3784 | if (status) { | ||
3785 | err = cmd_complete(sk, hdev->id, | ||
3786 | MGMT_OP_START_DISCOVERY, status, | ||
3787 | &cp->type, sizeof(cp->type)); | ||
3788 | mgmt_pending_remove(cmd); | ||
3789 | goto failed; | ||
3790 | } | ||
3791 | |||
3792 | if (test_bit(HCI_INQUIRY, &hdev->flags)) { | ||
3793 | err = cmd_complete(sk, hdev->id, | ||
3794 | MGMT_OP_START_DISCOVERY, | ||
3795 | MGMT_STATUS_BUSY, &cp->type, | ||
3796 | sizeof(cp->type)); | ||
3797 | mgmt_pending_remove(cmd); | ||
3798 | goto failed; | ||
3799 | } | ||
3800 | |||
3801 | hci_inquiry_cache_flush(hdev); | ||
3802 | |||
3803 | memset(&inq_cp, 0, sizeof(inq_cp)); | ||
3804 | memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap)); | ||
3805 | inq_cp.length = DISCOV_BREDR_INQUIRY_LEN; | ||
3806 | hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp); | ||
3807 | break; | ||
3808 | |||
3809 | case DISCOV_TYPE_LE: | ||
3810 | case DISCOV_TYPE_INTERLEAVED: | ||
3811 | status = mgmt_le_support(hdev); | ||
3812 | if (status) { | ||
3813 | err = cmd_complete(sk, hdev->id, | ||
3814 | MGMT_OP_START_DISCOVERY, status, | ||
3815 | &cp->type, sizeof(cp->type)); | ||
3816 | mgmt_pending_remove(cmd); | ||
3817 | goto failed; | ||
3818 | } | ||
3819 | |||
3820 | if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED && | ||
3821 | !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) { | ||
3822 | err = cmd_complete(sk, hdev->id, | ||
3823 | MGMT_OP_START_DISCOVERY, | ||
3824 | MGMT_STATUS_NOT_SUPPORTED, | ||
3825 | &cp->type, sizeof(cp->type)); | ||
3826 | mgmt_pending_remove(cmd); | ||
3827 | goto failed; | ||
3828 | } | ||
3829 | |||
3830 | if (test_bit(HCI_LE_ADV, &hdev->dev_flags)) { | ||
3831 | /* Don't let discovery abort an outgoing | ||
3832 | * connection attempt that's using directed | ||
3833 | * advertising. | ||
3834 | */ | ||
3835 | if (hci_conn_hash_lookup_state(hdev, LE_LINK, | ||
3836 | BT_CONNECT)) { | ||
3837 | err = cmd_complete(sk, hdev->id, | ||
3838 | MGMT_OP_START_DISCOVERY, | ||
3839 | MGMT_STATUS_REJECTED, | ||
3840 | &cp->type, | ||
3841 | sizeof(cp->type)); | ||
3842 | mgmt_pending_remove(cmd); | ||
3843 | goto failed; | ||
3844 | } | ||
3845 | |||
3846 | disable_advertising(&req); | ||
3847 | } | ||
3848 | |||
3849 | /* If controller is scanning, it means the background scanning | ||
3850 | * is running. Thus, we should temporarily stop it in order to | ||
3851 | * set the discovery scanning parameters. | ||
3852 | */ | ||
3853 | if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) | ||
3854 | hci_req_add_le_scan_disable(&req); | ||
3855 | |||
3856 | memset(¶m_cp, 0, sizeof(param_cp)); | ||
3857 | |||
3858 | /* All active scans will be done with either a resolvable | ||
3859 | * private address (when privacy feature has been enabled) | ||
3860 | * or unresolvable private address. | ||
3861 | */ | ||
3862 | err = hci_update_random_address(&req, true, &own_addr_type); | ||
3863 | if (err < 0) { | ||
3864 | err = cmd_complete(sk, hdev->id, | ||
3865 | MGMT_OP_START_DISCOVERY, | ||
3866 | MGMT_STATUS_FAILED, | ||
3867 | &cp->type, sizeof(cp->type)); | ||
3868 | mgmt_pending_remove(cmd); | ||
3869 | goto failed; | ||
3870 | } | ||
3871 | |||
3872 | param_cp.type = LE_SCAN_ACTIVE; | ||
3873 | param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT); | ||
3874 | param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN); | ||
3875 | param_cp.own_address_type = own_addr_type; | ||
3876 | hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp), | ||
3877 | ¶m_cp); | ||
3878 | |||
3879 | memset(&enable_cp, 0, sizeof(enable_cp)); | ||
3880 | enable_cp.enable = LE_SCAN_ENABLE; | ||
3881 | enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE; | ||
3882 | hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp), | ||
3883 | &enable_cp); | ||
3884 | break; | ||
3885 | |||
3886 | default: | ||
3887 | err = cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY, | 3874 | err = cmd_complete(sk, hdev->id, MGMT_OP_START_DISCOVERY, |
3888 | MGMT_STATUS_INVALID_PARAMS, | 3875 | status, &cp->type, sizeof(cp->type)); |
3889 | &cp->type, sizeof(cp->type)); | ||
3890 | mgmt_pending_remove(cmd); | 3876 | mgmt_pending_remove(cmd); |
3891 | goto failed; | 3877 | goto failed; |
3892 | } | 3878 | } |