summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/bluetooth/hci_conn.c2
-rw-r--r--net/bluetooth/hci_request.c59
-rw-r--r--net/bluetooth/hci_request.h2
-rw-r--r--net/bluetooth/mgmt.c6
4 files changed, 59 insertions, 10 deletions
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 8805d68e65f2..be67361ff2f0 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -931,7 +931,7 @@ static void hci_req_directed_advertising(struct hci_request *req,
* So it is required to remove adv set for handle 0x00. since we use
* instance 0 for directed adv.
*/
- hci_req_add(req, HCI_OP_LE_REMOVE_ADV_SET, sizeof(cp.handle), &cp.handle);
+ __hci_req_remove_ext_adv_instance(req, cp.handle);
hci_req_add(req, HCI_OP_LE_SET_EXT_ADV_PARAMS, sizeof(cp), &cp);
diff --git a/net/bluetooth/hci_request.c b/net/bluetooth/hci_request.c
index 770b93758112..7c0c2fda04ad 100644
--- a/net/bluetooth/hci_request.c
+++ b/net/bluetooth/hci_request.c
@@ -1179,13 +1179,8 @@ static u8 get_cur_adv_instance_scan_rsp_len(struct hci_dev *hdev)
void __hci_req_disable_advertising(struct hci_request *req)
{
if (ext_adv_capable(req->hdev)) {
- struct hci_cp_le_set_ext_adv_enable cp;
+ __hci_req_disable_ext_adv_instance(req, 0x00);
- cp.enable = 0x00;
- /* Disable all sets since we only support one set at the moment */
- cp.num_of_sets = 0x00;
-
- hci_req_add(req, HCI_OP_LE_SET_EXT_ADV_ENABLE, sizeof(cp), &cp);
} else {
u8 enable = 0x00;
@@ -1950,13 +1945,59 @@ int __hci_req_enable_ext_advertising(struct hci_request *req, u8 instance)
return 0;
}
+int __hci_req_disable_ext_adv_instance(struct hci_request *req, u8 instance)
+{
+ struct hci_dev *hdev = req->hdev;
+ struct hci_cp_le_set_ext_adv_enable *cp;
+ struct hci_cp_ext_adv_set *adv_set;
+ u8 data[sizeof(*cp) + sizeof(*adv_set) * 1];
+ u8 req_size;
+
+ /* If request specifies an instance that doesn't exist, fail */
+ if (instance > 0 && !hci_find_adv_instance(hdev, instance))
+ return -EINVAL;
+
+ memset(data, 0, sizeof(data));
+
+ cp = (void *)data;
+ adv_set = (void *)cp->data;
+
+ /* Instance 0x00 indicates all advertising instances will be disabled */
+ cp->num_of_sets = !!instance;
+ cp->enable = 0x00;
+
+ adv_set->handle = instance;
+
+ req_size = sizeof(*cp) + sizeof(*adv_set) * cp->num_of_sets;
+ hci_req_add(req, HCI_OP_LE_SET_EXT_ADV_ENABLE, req_size, data);
+
+ return 0;
+}
+
+int __hci_req_remove_ext_adv_instance(struct hci_request *req, u8 instance)
+{
+ struct hci_dev *hdev = req->hdev;
+
+ /* If request specifies an instance that doesn't exist, fail */
+ if (instance > 0 && !hci_find_adv_instance(hdev, instance))
+ return -EINVAL;
+
+ hci_req_add(req, HCI_OP_LE_REMOVE_ADV_SET, sizeof(instance), &instance);
+
+ return 0;
+}
+
int __hci_req_start_ext_adv(struct hci_request *req, u8 instance)
{
struct hci_dev *hdev = req->hdev;
+ struct adv_info *adv_instance = hci_find_adv_instance(hdev, instance);
int err;
- if (hci_dev_test_flag(hdev, HCI_LE_ADV))
- __hci_req_disable_advertising(req);
+ /* If instance isn't pending, the chip knows about it, and it's safe to
+ * disable
+ */
+ if (adv_instance && !adv_instance->pending)
+ __hci_req_disable_ext_adv_instance(req, instance);
err = __hci_req_setup_ext_adv_instance(req, instance);
if (err < 0)
@@ -2104,7 +2145,7 @@ void hci_req_clear_adv_instance(struct hci_dev *hdev, struct sock *sk,
hci_dev_test_flag(hdev, HCI_ADVERTISING))
return;
- if (next_instance)
+ if (next_instance && !ext_adv_capable(hdev))
__hci_req_schedule_adv_instance(req, next_instance->instance,
false);
}
diff --git a/net/bluetooth/hci_request.h b/net/bluetooth/hci_request.h
index 0e81614d235e..bbe892ab078a 100644
--- a/net/bluetooth/hci_request.h
+++ b/net/bluetooth/hci_request.h
@@ -86,6 +86,8 @@ void hci_req_clear_adv_instance(struct hci_dev *hdev, struct sock *sk,
int __hci_req_setup_ext_adv_instance(struct hci_request *req, u8 instance);
int __hci_req_start_ext_adv(struct hci_request *req, u8 instance);
int __hci_req_enable_ext_advertising(struct hci_request *req, u8 instance);
+int __hci_req_disable_ext_adv_instance(struct hci_request *req, u8 instance);
+int __hci_req_remove_ext_adv_instance(struct hci_request *req, u8 instance);
void __hci_req_clear_ext_adv_sets(struct hci_request *req);
int hci_get_random_address(struct hci_dev *hdev, bool require_privacy,
bool use_rpa, struct adv_info *adv_instance,
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 686ef4792831..f45105d2de77 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -7504,6 +7504,12 @@ static int remove_advertising(struct sock *sk, struct hci_dev *hdev,
hci_req_init(&req, hdev);
+ /* If we use extended advertising, instance is disabled and removed */
+ if (ext_adv_capable(hdev)) {
+ __hci_req_disable_ext_adv_instance(&req, cp->instance);
+ __hci_req_remove_ext_adv_instance(&req, cp->instance);
+ }
+
hci_req_clear_adv_instance(hdev, sk, &req, cp->instance, true);
if (list_empty(&hdev->adv_instances))