aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/mgmt.c
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2014-12-04 05:36:36 -0500
committerJohan Hedberg <johan.hedberg@intel.com>2014-12-04 05:52:29 -0500
commit8019044dcb5944c0f578a1e59cecbd09d7b7c7f3 (patch)
treec5deaac5141acf76c2f46135c954b02696f4c7b0 /net/bluetooth/mgmt.c
parent11e6e25d052478235a0c3f94d2f2faddeb58eb96 (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/bluetooth/mgmt.c')
-rw-r--r--net/bluetooth/mgmt.c214
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
3689static 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(&param_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 &param_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
3689static void start_discovery_complete(struct hci_dev *hdev, u8 status) 3786static 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(&param_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 &param_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 }