diff options
author | Florian Grandel <fgrandel@gmail.com> | 2015-06-17 21:16:34 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2015-06-18 12:11:51 -0400 |
commit | d2609b345ebf0547015a78588c4d7ad68c9ccf26 (patch) | |
tree | 2b0d35d71227e87a1b1906158bada9dbb63e8fe1 | |
parent | aebceccc18bf49f8fb208ac4548b7bd402b6662c (diff) |
Bluetooth: hci_core/mgmt: Introduce multi-adv list
The current hci dev structure only supports a single advertising
instance. To support multi-instance advertising it is necessary to
introduce a linked list of advertising instances so that multiple
advertising instances can be dynamically added and/or removed.
In a first step, the existing adv_instance member of the hci_dev
struct is supplemented by a linked list of advertising instances.
This patch introduces the list and supporting list management
infrastructure. The list is not being used yet.
Signed-off-by: Florian Grandel <fgrandel@gmail.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r-- | include/net/bluetooth/hci_core.h | 17 | ||||
-rw-r--r-- | net/bluetooth/hci_core.c | 117 | ||||
-rw-r--r-- | net/bluetooth/mgmt.c | 2 |
3 files changed, 135 insertions, 1 deletions
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 3fbb793e634d..4242dbfb4cf5 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h | |||
@@ -157,15 +157,20 @@ struct oob_data { | |||
157 | 157 | ||
158 | struct adv_info { | 158 | struct adv_info { |
159 | struct delayed_work timeout_exp; | 159 | struct delayed_work timeout_exp; |
160 | struct list_head list; | ||
160 | __u8 instance; | 161 | __u8 instance; |
161 | __u32 flags; | 162 | __u32 flags; |
162 | __u16 timeout; | 163 | __u16 timeout; |
164 | __u16 duration; | ||
163 | __u16 adv_data_len; | 165 | __u16 adv_data_len; |
164 | __u8 adv_data[HCI_MAX_AD_LENGTH]; | 166 | __u8 adv_data[HCI_MAX_AD_LENGTH]; |
165 | __u16 scan_rsp_len; | 167 | __u16 scan_rsp_len; |
166 | __u8 scan_rsp_data[HCI_MAX_AD_LENGTH]; | 168 | __u8 scan_rsp_data[HCI_MAX_AD_LENGTH]; |
167 | }; | 169 | }; |
168 | 170 | ||
171 | #define HCI_MAX_ADV_INSTANCES 1 | ||
172 | #define HCI_DEFAULT_ADV_DURATION 2 | ||
173 | |||
169 | #define HCI_MAX_SHORT_NAME_LENGTH 10 | 174 | #define HCI_MAX_SHORT_NAME_LENGTH 10 |
170 | 175 | ||
171 | /* Default LE RPA expiry time, 15 minutes */ | 176 | /* Default LE RPA expiry time, 15 minutes */ |
@@ -374,6 +379,9 @@ struct hci_dev { | |||
374 | __u8 scan_rsp_data_len; | 379 | __u8 scan_rsp_data_len; |
375 | 380 | ||
376 | struct adv_info adv_instance; | 381 | struct adv_info adv_instance; |
382 | struct list_head adv_instances; | ||
383 | unsigned int adv_instance_cnt; | ||
384 | __u8 cur_adv_instance; | ||
377 | 385 | ||
378 | __u8 irk[16]; | 386 | __u8 irk[16]; |
379 | __u32 rpa_timeout; | 387 | __u32 rpa_timeout; |
@@ -1019,6 +1027,15 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, | |||
1019 | int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, | 1027 | int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, |
1020 | u8 bdaddr_type); | 1028 | u8 bdaddr_type); |
1021 | 1029 | ||
1030 | void hci_adv_instances_clear(struct hci_dev *hdev); | ||
1031 | struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance); | ||
1032 | struct adv_info *hci_get_next_instance(struct hci_dev *hdev, u8 instance); | ||
1033 | int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags, | ||
1034 | u16 adv_data_len, u8 *adv_data, | ||
1035 | u16 scan_rsp_len, u8 *scan_rsp_data, | ||
1036 | u16 timeout, u16 duration); | ||
1037 | int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance); | ||
1038 | |||
1022 | void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); | 1039 | void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); |
1023 | 1040 | ||
1024 | int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb); | 1041 | int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb); |
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 573711c2d09e..ebf37ebcfd12 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -2610,6 +2610,119 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, | |||
2610 | return 0; | 2610 | return 0; |
2611 | } | 2611 | } |
2612 | 2612 | ||
2613 | /* This function requires the caller holds hdev->lock */ | ||
2614 | struct adv_info *hci_find_adv_instance(struct hci_dev *hdev, u8 instance) | ||
2615 | { | ||
2616 | struct adv_info *adv_instance; | ||
2617 | |||
2618 | list_for_each_entry(adv_instance, &hdev->adv_instances, list) { | ||
2619 | if (adv_instance->instance == instance) | ||
2620 | return adv_instance; | ||
2621 | } | ||
2622 | |||
2623 | return NULL; | ||
2624 | } | ||
2625 | |||
2626 | /* This function requires the caller holds hdev->lock */ | ||
2627 | struct adv_info *hci_get_next_instance(struct hci_dev *hdev, u8 instance) { | ||
2628 | struct adv_info *cur_instance; | ||
2629 | |||
2630 | cur_instance = hci_find_adv_instance(hdev, instance); | ||
2631 | if (!cur_instance) | ||
2632 | return NULL; | ||
2633 | |||
2634 | if (cur_instance == list_last_entry(&hdev->adv_instances, | ||
2635 | struct adv_info, list)) | ||
2636 | return list_first_entry(&hdev->adv_instances, | ||
2637 | struct adv_info, list); | ||
2638 | else | ||
2639 | return list_next_entry(cur_instance, list); | ||
2640 | } | ||
2641 | |||
2642 | /* This function requires the caller holds hdev->lock */ | ||
2643 | int hci_remove_adv_instance(struct hci_dev *hdev, u8 instance) | ||
2644 | { | ||
2645 | struct adv_info *adv_instance; | ||
2646 | |||
2647 | adv_instance = hci_find_adv_instance(hdev, instance); | ||
2648 | if (!adv_instance) | ||
2649 | return -ENOENT; | ||
2650 | |||
2651 | BT_DBG("%s removing %dMR", hdev->name, instance); | ||
2652 | |||
2653 | list_del(&adv_instance->list); | ||
2654 | kfree(adv_instance); | ||
2655 | |||
2656 | hdev->adv_instance_cnt--; | ||
2657 | |||
2658 | return 0; | ||
2659 | } | ||
2660 | |||
2661 | /* This function requires the caller holds hdev->lock */ | ||
2662 | void hci_adv_instances_clear(struct hci_dev *hdev) | ||
2663 | { | ||
2664 | struct adv_info *adv_instance, *n; | ||
2665 | |||
2666 | list_for_each_entry_safe(adv_instance, n, &hdev->adv_instances, list) { | ||
2667 | list_del(&adv_instance->list); | ||
2668 | kfree(adv_instance); | ||
2669 | } | ||
2670 | |||
2671 | hdev->adv_instance_cnt = 0; | ||
2672 | } | ||
2673 | |||
2674 | /* This function requires the caller holds hdev->lock */ | ||
2675 | int hci_add_adv_instance(struct hci_dev *hdev, u8 instance, u32 flags, | ||
2676 | u16 adv_data_len, u8 *adv_data, | ||
2677 | u16 scan_rsp_len, u8 *scan_rsp_data, | ||
2678 | u16 timeout, u16 duration) | ||
2679 | { | ||
2680 | struct adv_info *adv_instance; | ||
2681 | |||
2682 | adv_instance = hci_find_adv_instance(hdev, instance); | ||
2683 | if (adv_instance) { | ||
2684 | memset(adv_instance->adv_data, 0, | ||
2685 | sizeof(adv_instance->adv_data)); | ||
2686 | memset(adv_instance->scan_rsp_data, 0, | ||
2687 | sizeof(adv_instance->scan_rsp_data)); | ||
2688 | } else { | ||
2689 | if (hdev->adv_instance_cnt >= HCI_MAX_ADV_INSTANCES || | ||
2690 | instance < 1 || instance > HCI_MAX_ADV_INSTANCES) | ||
2691 | return -EOVERFLOW; | ||
2692 | |||
2693 | adv_instance = kmalloc(sizeof(*adv_instance), GFP_KERNEL); | ||
2694 | if (!adv_instance) | ||
2695 | return -ENOMEM; | ||
2696 | |||
2697 | memset(adv_instance, 0, sizeof(*adv_instance)); | ||
2698 | adv_instance->instance = instance; | ||
2699 | list_add(&adv_instance->list, &hdev->adv_instances); | ||
2700 | hdev->adv_instance_cnt++; | ||
2701 | } | ||
2702 | |||
2703 | adv_instance->flags = flags; | ||
2704 | adv_instance->adv_data_len = adv_data_len; | ||
2705 | adv_instance->scan_rsp_len = scan_rsp_len; | ||
2706 | |||
2707 | if (adv_data_len) | ||
2708 | memcpy(adv_instance->adv_data, adv_data, adv_data_len); | ||
2709 | |||
2710 | if (scan_rsp_len) | ||
2711 | memcpy(adv_instance->scan_rsp_data, | ||
2712 | scan_rsp_data, scan_rsp_len); | ||
2713 | |||
2714 | adv_instance->timeout = timeout; | ||
2715 | |||
2716 | if (duration == 0) | ||
2717 | adv_instance->duration = HCI_DEFAULT_ADV_DURATION; | ||
2718 | else | ||
2719 | adv_instance->duration = duration; | ||
2720 | |||
2721 | BT_DBG("%s for %dMR", hdev->name, instance); | ||
2722 | |||
2723 | return 0; | ||
2724 | } | ||
2725 | |||
2613 | struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list, | 2726 | struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list, |
2614 | bdaddr_t *bdaddr, u8 type) | 2727 | bdaddr_t *bdaddr, u8 type) |
2615 | { | 2728 | { |
@@ -3015,6 +3128,8 @@ struct hci_dev *hci_alloc_dev(void) | |||
3015 | hdev->manufacturer = 0xffff; /* Default to internal use */ | 3128 | hdev->manufacturer = 0xffff; /* Default to internal use */ |
3016 | hdev->inq_tx_power = HCI_TX_POWER_INVALID; | 3129 | hdev->inq_tx_power = HCI_TX_POWER_INVALID; |
3017 | hdev->adv_tx_power = HCI_TX_POWER_INVALID; | 3130 | hdev->adv_tx_power = HCI_TX_POWER_INVALID; |
3131 | hdev->adv_instance_cnt = 0; | ||
3132 | hdev->cur_adv_instance = 0x00; | ||
3018 | 3133 | ||
3019 | hdev->sniff_max_interval = 800; | 3134 | hdev->sniff_max_interval = 800; |
3020 | hdev->sniff_min_interval = 80; | 3135 | hdev->sniff_min_interval = 80; |
@@ -3056,6 +3171,7 @@ struct hci_dev *hci_alloc_dev(void) | |||
3056 | INIT_LIST_HEAD(&hdev->pend_le_conns); | 3171 | INIT_LIST_HEAD(&hdev->pend_le_conns); |
3057 | INIT_LIST_HEAD(&hdev->pend_le_reports); | 3172 | INIT_LIST_HEAD(&hdev->pend_le_reports); |
3058 | INIT_LIST_HEAD(&hdev->conn_hash.list); | 3173 | INIT_LIST_HEAD(&hdev->conn_hash.list); |
3174 | INIT_LIST_HEAD(&hdev->adv_instances); | ||
3059 | 3175 | ||
3060 | INIT_WORK(&hdev->rx_work, hci_rx_work); | 3176 | INIT_WORK(&hdev->rx_work, hci_rx_work); |
3061 | INIT_WORK(&hdev->cmd_work, hci_cmd_work); | 3177 | INIT_WORK(&hdev->cmd_work, hci_cmd_work); |
@@ -3249,6 +3365,7 @@ void hci_unregister_dev(struct hci_dev *hdev) | |||
3249 | hci_smp_ltks_clear(hdev); | 3365 | hci_smp_ltks_clear(hdev); |
3250 | hci_smp_irks_clear(hdev); | 3366 | hci_smp_irks_clear(hdev); |
3251 | hci_remote_oob_data_clear(hdev); | 3367 | hci_remote_oob_data_clear(hdev); |
3368 | hci_adv_instances_clear(hdev); | ||
3252 | hci_bdaddr_list_clear(&hdev->le_white_list); | 3369 | hci_bdaddr_list_clear(&hdev->le_white_list); |
3253 | hci_conn_params_clear_all(hdev); | 3370 | hci_conn_params_clear_all(hdev); |
3254 | hci_discovery_filter_clear(hdev); | 3371 | hci_discovery_filter_clear(hdev); |
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index e41bbe28a36e..92c50a17fdf9 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -6813,7 +6813,7 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev, | |||
6813 | rp->supported_flags = cpu_to_le32(supported_flags); | 6813 | rp->supported_flags = cpu_to_le32(supported_flags); |
6814 | rp->max_adv_data_len = HCI_MAX_AD_LENGTH; | 6814 | rp->max_adv_data_len = HCI_MAX_AD_LENGTH; |
6815 | rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH; | 6815 | rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH; |
6816 | rp->max_instances = 1; | 6816 | rp->max_instances = HCI_MAX_ADV_INSTANCES; |
6817 | 6817 | ||
6818 | /* Currently only one instance is supported, so simply return the | 6818 | /* Currently only one instance is supported, so simply return the |
6819 | * current instance number. | 6819 | * current instance number. |