|
@@ -2610,6 +2610,119 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/* This function requires the caller holds hdev->lock */
|
|
|
+struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance)
|
|
|
+{
|
|
|
+ struct adv_info *adv_instance;
|
|
|
+
|
|
|
+ list_for_each_entry(adv_instance, &hdev->adv_instances, list) {
|
|
|
+ if (adv_instance->instance == instance)
|
|
|
+ return adv_instance;
|
|
|
+ }
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+/* This function requires the caller holds hdev->lock */
|
|
|
+struct adv_info *hci_get_next_instance(struct hci_dev *hdev, u8 instance) {
|
|
|
+ struct adv_info *cur_instance;
|
|
|
+
|
|
|
+ cur_instance = hci_find_adv_instance(hdev, instance);
|
|
|
+ if (!cur_instance)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ if (cur_instance == list_last_entry(&hdev->adv_instances,
|
|
|
+ struct adv_info, list))
|
|
|
+ return list_first_entry(&hdev->adv_instances,
|
|
|
+ struct adv_info, list);
|
|
|
+ else
|
|
|
+ return list_next_entry(cur_instance, list);
|
|
|
+}
|
|
|
+
|
|
|
+/* This function requires the caller holds hdev->lock */
|
|
|
+int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance)
|
|
|
+{
|
|
|
+ struct adv_info *adv_instance;
|
|
|
+
|
|
|
+ adv_instance = hci_find_adv_instance(hdev, instance);
|
|
|
+ if (!adv_instance)
|
|
|
+ return -ENOENT;
|
|
|
+
|
|
|
+ BT_DBG("%s removing %dMR", hdev->name, instance);
|
|
|
+
|
|
|
+ list_del(&adv_instance->list);
|
|
|
+ kfree(adv_instance);
|
|
|
+
|
|
|
+ hdev->adv_instance_cnt--;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* This function requires the caller holds hdev->lock */
|
|
|
+void hci_adv_instances_clear(struct hci_dev *hdev)
|
|
|
+{
|
|
|
+ struct adv_info *adv_instance, *n;
|
|
|
+
|
|
|
+ list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) {
|
|
|
+ list_del(&adv_instance->list);
|
|
|
+ kfree(adv_instance);
|
|
|
+ }
|
|
|
+
|
|
|
+ hdev->adv_instance_cnt = 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* This function requires the caller holds hdev->lock */
|
|
|
+int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags,
|
|
|
+ u16 adv_data_len, u8 *adv_data,
|
|
|
+ u16 scan_rsp_len, u8 *scan_rsp_data,
|
|
|
+ u16 timeout, u16 duration)
|
|
|
+{
|
|
|
+ struct adv_info *adv_instance;
|
|
|
+
|
|
|
+ adv_instance = hci_find_adv_instance(hdev, instance);
|
|
|
+ if (adv_instance) {
|
|
|
+ memset(adv_instance->adv_data, 0,
|
|
|
+ sizeof(adv_instance->adv_data));
|
|
|
+ memset(adv_instance->scan_rsp_data, 0,
|
|
|
+ sizeof(adv_instance->scan_rsp_data));
|
|
|
+ } else {
|
|
|
+ if (hdev->adv_instance_cnt >= HCI_MAX_ADV_INSTANCES ||
|
|
|
+ instance < 1 || instance > HCI_MAX_ADV_INSTANCES)
|
|
|
+ return -EOVERFLOW;
|
|
|
+
|
|
|
+ adv_instance = kmalloc(sizeof(*adv_instance), GFP_KERNEL);
|
|
|
+ if (!adv_instance)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ memset(adv_instance, 0, sizeof(*adv_instance));
|
|
|
+ adv_instance->instance = instance;
|
|
|
+ list_add(&adv_instance->list, &hdev->adv_instances);
|
|
|
+ hdev->adv_instance_cnt++;
|
|
|
+ }
|
|
|
+
|
|
|
+ adv_instance->flags = flags;
|
|
|
+ adv_instance->adv_data_len = adv_data_len;
|
|
|
+ adv_instance->scan_rsp_len = scan_rsp_len;
|
|
|
+
|
|
|
+ if (adv_data_len)
|
|
|
+ memcpy(adv_instance->adv_data, adv_data, adv_data_len);
|
|
|
+
|
|
|
+ if (scan_rsp_len)
|
|
|
+ memcpy(adv_instance->scan_rsp_data,
|
|
|
+ scan_rsp_data, scan_rsp_len);
|
|
|
+
|
|
|
+ adv_instance->timeout = timeout;
|
|
|
+
|
|
|
+ if (duration == 0)
|
|
|
+ adv_instance->duration = HCI_DEFAULT_ADV_DURATION;
|
|
|
+ else
|
|
|
+ adv_instance->duration = duration;
|
|
|
+
|
|
|
+ BT_DBG("%s for %dMR", hdev->name, instance);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list,
|
|
|
bdaddr_t *bdaddr, u8 type)
|
|
|
{
|
|
@@ -3015,6 +3128,8 @@ struct hci_dev *hci_alloc_dev(void)
|
|
|
hdev->manufacturer = 0xffff; /* Default to internal use */
|
|
|
hdev->inq_tx_power = HCI_TX_POWER_INVALID;
|
|
|
hdev->adv_tx_power = HCI_TX_POWER_INVALID;
|
|
|
+ hdev->adv_instance_cnt = 0;
|
|
|
+ hdev->cur_adv_instance = 0x00;
|
|
|
|
|
|
hdev->sniff_max_interval = 800;
|
|
|
hdev->sniff_min_interval = 80;
|
|
@@ -3056,6 +3171,7 @@ struct hci_dev *hci_alloc_dev(void)
|
|
|
INIT_LIST_HEAD(&hdev->pend_le_conns);
|
|
|
INIT_LIST_HEAD(&hdev->pend_le_reports);
|
|
|
INIT_LIST_HEAD(&hdev->conn_hash.list);
|
|
|
+ INIT_LIST_HEAD(&hdev->adv_instances);
|
|
|
|
|
|
INIT_WORK(&hdev->rx_work, hci_rx_work);
|
|
|
INIT_WORK(&hdev->cmd_work, hci_cmd_work);
|
|
@@ -3249,6 +3365,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
|
|
|
hci_smp_ltks_clear(hdev);
|
|
|
hci_smp_irks_clear(hdev);
|
|
|
hci_remote_oob_data_clear(hdev);
|
|
|
+ hci_adv_instances_clear(hdev);
|
|
|
hci_bdaddr_list_clear(&hdev->le_white_list);
|
|
|
hci_conn_params_clear_all(hdev);
|
|
|
hci_discovery_filter_clear(hdev);
|