diff options
author | David S. Miller <davem@davemloft.net> | 2015-03-31 12:45:58 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-03-31 12:45:58 -0400 |
commit | 89a3f3c55ba54e08968b12a5f8e7d1787a0bbb4a (patch) | |
tree | d5f5308662279892195231e2313f9d47dc1bb4f5 /net | |
parent | 32eaf120e66b1763626ed564adf1e42e69da82f4 (diff) | |
parent | a7a484bfca218f9671a3e3bc98851eab6b628310 (diff) |
Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth-next
Johan Hedberg says:
====================
pull request: bluetooth-next 2015-03-27
Here's another set of Bluetooth & 802.15.4 patches for 4.1:
- New API to control LE advertising data (i.e. peripheral role)
- mac802154 & at86rf230 cleanups
- Support for toggling quirks from debugfs (useful for testing)
- Memory leak fix for LE scanning
- Extra version info reading support for Broadcom controllers
Please let me know if there are any issues pulling. Thanks.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/bluetooth/hci_core.c | 18 | ||||
-rw-r--r-- | net/bluetooth/hci_debugfs.c | 60 | ||||
-rw-r--r-- | net/bluetooth/mgmt.c | 715 | ||||
-rw-r--r-- | net/mac802154/iface.c | 20 |
4 files changed, 731 insertions, 82 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 773f2164d9a1..e6bfeb7b4415 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c | |||
@@ -2874,7 +2874,6 @@ static void le_scan_disable_work_complete(struct hci_dev *hdev, u8 status, | |||
2874 | { | 2874 | { |
2875 | /* General inquiry access code (GIAC) */ | 2875 | /* General inquiry access code (GIAC) */ |
2876 | u8 lap[3] = { 0x33, 0x8b, 0x9e }; | 2876 | u8 lap[3] = { 0x33, 0x8b, 0x9e }; |
2877 | struct hci_request req; | ||
2878 | struct hci_cp_inquiry cp; | 2877 | struct hci_cp_inquiry cp; |
2879 | int err; | 2878 | int err; |
2880 | 2879 | ||
@@ -2893,13 +2892,6 @@ static void le_scan_disable_work_complete(struct hci_dev *hdev, u8 status, | |||
2893 | break; | 2892 | break; |
2894 | 2893 | ||
2895 | case DISCOV_TYPE_INTERLEAVED: | 2894 | case DISCOV_TYPE_INTERLEAVED: |
2896 | hci_req_init(&req, hdev); | ||
2897 | |||
2898 | memset(&cp, 0, sizeof(cp)); | ||
2899 | memcpy(&cp.lap, lap, sizeof(cp.lap)); | ||
2900 | cp.length = DISCOV_INTERLEAVED_INQUIRY_LEN; | ||
2901 | hci_req_add(&req, HCI_OP_INQUIRY, sizeof(cp), &cp); | ||
2902 | |||
2903 | hci_dev_lock(hdev); | 2895 | hci_dev_lock(hdev); |
2904 | 2896 | ||
2905 | if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, | 2897 | if (test_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, |
@@ -2914,8 +2906,17 @@ static void le_scan_disable_work_complete(struct hci_dev *hdev, u8 status, | |||
2914 | hci_discovery_set_state(hdev, | 2906 | hci_discovery_set_state(hdev, |
2915 | DISCOVERY_STOPPED); | 2907 | DISCOVERY_STOPPED); |
2916 | } else { | 2908 | } else { |
2909 | struct hci_request req; | ||
2910 | |||
2917 | hci_inquiry_cache_flush(hdev); | 2911 | hci_inquiry_cache_flush(hdev); |
2918 | 2912 | ||
2913 | hci_req_init(&req, hdev); | ||
2914 | |||
2915 | memset(&cp, 0, sizeof(cp)); | ||
2916 | memcpy(&cp.lap, lap, sizeof(cp.lap)); | ||
2917 | cp.length = DISCOV_INTERLEAVED_INQUIRY_LEN; | ||
2918 | hci_req_add(&req, HCI_OP_INQUIRY, sizeof(cp), &cp); | ||
2919 | |||
2919 | err = hci_req_run(&req, inquiry_complete); | 2920 | err = hci_req_run(&req, inquiry_complete); |
2920 | if (err) { | 2921 | if (err) { |
2921 | BT_ERR("Inquiry request failed: err %d", err); | 2922 | BT_ERR("Inquiry request failed: err %d", err); |
@@ -3125,6 +3126,7 @@ struct hci_dev *hci_alloc_dev(void) | |||
3125 | 3126 | ||
3126 | hci_init_sysfs(hdev); | 3127 | hci_init_sysfs(hdev); |
3127 | discovery_init(hdev); | 3128 | discovery_init(hdev); |
3129 | adv_info_init(hdev); | ||
3128 | 3130 | ||
3129 | return hdev; | 3131 | return hdev; |
3130 | } | 3132 | } |
diff --git a/net/bluetooth/hci_debugfs.c b/net/bluetooth/hci_debugfs.c index 0818fabf346a..e6255833a258 100644 --- a/net/bluetooth/hci_debugfs.c +++ b/net/bluetooth/hci_debugfs.c | |||
@@ -28,6 +28,54 @@ | |||
28 | 28 | ||
29 | #include "hci_debugfs.h" | 29 | #include "hci_debugfs.h" |
30 | 30 | ||
31 | #define DEFINE_QUIRK_ATTRIBUTE(__name, __quirk) \ | ||
32 | static ssize_t __name ## _read(struct file *file, \ | ||
33 | char __user *user_buf, \ | ||
34 | size_t count, loff_t *ppos) \ | ||
35 | { \ | ||
36 | struct hci_dev *hdev = file->private_data; \ | ||
37 | char buf[3]; \ | ||
38 | \ | ||
39 | buf[0] = test_bit(__quirk, &hdev->quirks) ? 'Y' : 'N'; \ | ||
40 | buf[1] = '\n'; \ | ||
41 | buf[2] = '\0'; \ | ||
42 | return simple_read_from_buffer(user_buf, count, ppos, buf, 2); \ | ||
43 | } \ | ||
44 | \ | ||
45 | static ssize_t __name ## _write(struct file *file, \ | ||
46 | const char __user *user_buf, \ | ||
47 | size_t count, loff_t *ppos) \ | ||
48 | { \ | ||
49 | struct hci_dev *hdev = file->private_data; \ | ||
50 | char buf[32]; \ | ||
51 | size_t buf_size = min(count, (sizeof(buf) - 1)); \ | ||
52 | bool enable; \ | ||
53 | \ | ||
54 | if (test_bit(HCI_UP, &hdev->flags)) \ | ||
55 | return -EBUSY; \ | ||
56 | \ | ||
57 | if (copy_from_user(buf, user_buf, buf_size)) \ | ||
58 | return -EFAULT; \ | ||
59 | \ | ||
60 | buf[buf_size] = '\0'; \ | ||
61 | if (strtobool(buf, &enable)) \ | ||
62 | return -EINVAL; \ | ||
63 | \ | ||
64 | if (enable == test_bit(__quirk, &hdev->quirks)) \ | ||
65 | return -EALREADY; \ | ||
66 | \ | ||
67 | change_bit(__quirk, &hdev->quirks); \ | ||
68 | \ | ||
69 | return count; \ | ||
70 | } \ | ||
71 | \ | ||
72 | static const struct file_operations __name ## _fops = { \ | ||
73 | .open = simple_open, \ | ||
74 | .read = __name ## _read, \ | ||
75 | .write = __name ## _write, \ | ||
76 | .llseek = default_llseek, \ | ||
77 | } \ | ||
78 | |||
31 | static int features_show(struct seq_file *f, void *ptr) | 79 | static int features_show(struct seq_file *f, void *ptr) |
32 | { | 80 | { |
33 | struct hci_dev *hdev = f->private; | 81 | struct hci_dev *hdev = f->private; |
@@ -997,6 +1045,11 @@ static int adv_max_interval_get(void *data, u64 *val) | |||
997 | DEFINE_SIMPLE_ATTRIBUTE(adv_max_interval_fops, adv_max_interval_get, | 1045 | DEFINE_SIMPLE_ATTRIBUTE(adv_max_interval_fops, adv_max_interval_get, |
998 | adv_max_interval_set, "%llu\n"); | 1046 | adv_max_interval_set, "%llu\n"); |
999 | 1047 | ||
1048 | DEFINE_QUIRK_ATTRIBUTE(quirk_strict_duplicate_filter, | ||
1049 | HCI_QUIRK_STRICT_DUPLICATE_FILTER); | ||
1050 | DEFINE_QUIRK_ATTRIBUTE(quirk_simultaneous_discovery, | ||
1051 | HCI_QUIRK_SIMULTANEOUS_DISCOVERY); | ||
1052 | |||
1000 | void hci_debugfs_create_le(struct hci_dev *hdev) | 1053 | void hci_debugfs_create_le(struct hci_dev *hdev) |
1001 | { | 1054 | { |
1002 | debugfs_create_file("identity", 0400, hdev->debugfs, hdev, | 1055 | debugfs_create_file("identity", 0400, hdev->debugfs, hdev, |
@@ -1041,6 +1094,13 @@ void hci_debugfs_create_le(struct hci_dev *hdev) | |||
1041 | &adv_max_interval_fops); | 1094 | &adv_max_interval_fops); |
1042 | debugfs_create_u16("discov_interleaved_timeout", 0644, hdev->debugfs, | 1095 | debugfs_create_u16("discov_interleaved_timeout", 0644, hdev->debugfs, |
1043 | &hdev->discov_interleaved_timeout); | 1096 | &hdev->discov_interleaved_timeout); |
1097 | |||
1098 | debugfs_create_file("quirk_strict_duplicate_filter", 0644, | ||
1099 | hdev->debugfs, hdev, | ||
1100 | &quirk_strict_duplicate_filter_fops); | ||
1101 | debugfs_create_file("quirk_simultaneous_discovery", 0644, | ||
1102 | hdev->debugfs, hdev, | ||
1103 | &quirk_simultaneous_discovery_fops); | ||
1044 | } | 1104 | } |
1045 | 1105 | ||
1046 | void hci_debugfs_create_conn(struct hci_conn *conn) | 1106 | void hci_debugfs_create_conn(struct hci_conn *conn) |
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index f3a957905193..fb2e764c6211 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c | |||
@@ -100,6 +100,8 @@ static const u16 mgmt_commands[] = { | |||
100 | MGMT_OP_READ_LOCAL_OOB_EXT_DATA, | 100 | MGMT_OP_READ_LOCAL_OOB_EXT_DATA, |
101 | MGMT_OP_READ_EXT_INDEX_LIST, | 101 | MGMT_OP_READ_EXT_INDEX_LIST, |
102 | MGMT_OP_READ_ADV_FEATURES, | 102 | MGMT_OP_READ_ADV_FEATURES, |
103 | MGMT_OP_ADD_ADVERTISING, | ||
104 | MGMT_OP_REMOVE_ADVERTISING, | ||
103 | }; | 105 | }; |
104 | 106 | ||
105 | static const u16 mgmt_events[] = { | 107 | static const u16 mgmt_events[] = { |
@@ -135,6 +137,29 @@ static const u16 mgmt_events[] = { | |||
135 | MGMT_EV_EXT_INDEX_ADDED, | 137 | MGMT_EV_EXT_INDEX_ADDED, |
136 | MGMT_EV_EXT_INDEX_REMOVED, | 138 | MGMT_EV_EXT_INDEX_REMOVED, |
137 | MGMT_EV_LOCAL_OOB_DATA_UPDATED, | 139 | MGMT_EV_LOCAL_OOB_DATA_UPDATED, |
140 | MGMT_EV_ADVERTISING_ADDED, | ||
141 | MGMT_EV_ADVERTISING_REMOVED, | ||
142 | }; | ||
143 | |||
144 | static const u16 mgmt_untrusted_commands[] = { | ||
145 | MGMT_OP_READ_INDEX_LIST, | ||
146 | MGMT_OP_READ_INFO, | ||
147 | MGMT_OP_READ_UNCONF_INDEX_LIST, | ||
148 | MGMT_OP_READ_CONFIG_INFO, | ||
149 | MGMT_OP_READ_EXT_INDEX_LIST, | ||
150 | }; | ||
151 | |||
152 | static const u16 mgmt_untrusted_events[] = { | ||
153 | MGMT_EV_INDEX_ADDED, | ||
154 | MGMT_EV_INDEX_REMOVED, | ||
155 | MGMT_EV_NEW_SETTINGS, | ||
156 | MGMT_EV_CLASS_OF_DEV_CHANGED, | ||
157 | MGMT_EV_LOCAL_NAME_CHANGED, | ||
158 | MGMT_EV_UNCONF_INDEX_ADDED, | ||
159 | MGMT_EV_UNCONF_INDEX_REMOVED, | ||
160 | MGMT_EV_NEW_CONFIG_OPTIONS, | ||
161 | MGMT_EV_EXT_INDEX_ADDED, | ||
162 | MGMT_EV_EXT_INDEX_REMOVED, | ||
138 | }; | 163 | }; |
139 | 164 | ||
140 | #define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000) | 165 | #define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000) |
@@ -261,14 +286,20 @@ static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data, | |||
261 | u16 data_len) | 286 | u16 data_len) |
262 | { | 287 | { |
263 | struct mgmt_rp_read_commands *rp; | 288 | struct mgmt_rp_read_commands *rp; |
264 | const u16 num_commands = ARRAY_SIZE(mgmt_commands); | 289 | u16 num_commands, num_events; |
265 | const u16 num_events = ARRAY_SIZE(mgmt_events); | ||
266 | __le16 *opcode; | ||
267 | size_t rp_size; | 290 | size_t rp_size; |
268 | int i, err; | 291 | int i, err; |
269 | 292 | ||
270 | BT_DBG("sock %p", sk); | 293 | BT_DBG("sock %p", sk); |
271 | 294 | ||
295 | if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) { | ||
296 | num_commands = ARRAY_SIZE(mgmt_commands); | ||
297 | num_events = ARRAY_SIZE(mgmt_events); | ||
298 | } else { | ||
299 | num_commands = ARRAY_SIZE(mgmt_untrusted_commands); | ||
300 | num_events = ARRAY_SIZE(mgmt_untrusted_events); | ||
301 | } | ||
302 | |||
272 | rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16)); | 303 | rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16)); |
273 | 304 | ||
274 | rp = kmalloc(rp_size, GFP_KERNEL); | 305 | rp = kmalloc(rp_size, GFP_KERNEL); |
@@ -278,11 +309,23 @@ static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data, | |||
278 | rp->num_commands = cpu_to_le16(num_commands); | 309 | rp->num_commands = cpu_to_le16(num_commands); |
279 | rp->num_events = cpu_to_le16(num_events); | 310 | rp->num_events = cpu_to_le16(num_events); |
280 | 311 | ||
281 | for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++) | 312 | if (hci_sock_test_flag(sk, HCI_SOCK_TRUSTED)) { |
282 | put_unaligned_le16(mgmt_commands[i], opcode); | 313 | __le16 *opcode = rp->opcodes; |
314 | |||
315 | for (i = 0; i < num_commands; i++, opcode++) | ||
316 | put_unaligned_le16(mgmt_commands[i], opcode); | ||
283 | 317 | ||
284 | for (i = 0; i < num_events; i++, opcode++) | 318 | for (i = 0; i < num_events; i++, opcode++) |
285 | put_unaligned_le16(mgmt_events[i], opcode); | 319 | put_unaligned_le16(mgmt_events[i], opcode); |
320 | } else { | ||
321 | __le16 *opcode = rp->opcodes; | ||
322 | |||
323 | for (i = 0; i < num_commands; i++, opcode++) | ||
324 | put_unaligned_le16(mgmt_untrusted_commands[i], opcode); | ||
325 | |||
326 | for (i = 0; i < num_events; i++, opcode++) | ||
327 | put_unaligned_le16(mgmt_untrusted_events[i], opcode); | ||
328 | } | ||
286 | 329 | ||
287 | err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, | 330 | err = mgmt_cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, |
288 | rp, rp_size); | 331 | rp, rp_size); |
@@ -650,7 +693,7 @@ static u32 get_current_settings(struct hci_dev *hdev) | |||
650 | * the second is to indicate if it is actually set. | 693 | * the second is to indicate if it is actually set. |
651 | * | 694 | * |
652 | * This means if the static address is not configured, this flag | 695 | * This means if the static address is not configured, this flag |
653 | * will never bet set. If the address is configured, then if the | 696 | * will never be set. If the address is configured, then if the |
654 | * address is actually used decides if the flag is set or not. | 697 | * address is actually used decides if the flag is set or not. |
655 | * | 698 | * |
656 | * For single mode LE only controllers and dual-mode controllers | 699 | * For single mode LE only controllers and dual-mode controllers |
@@ -789,7 +832,7 @@ static struct mgmt_pending_cmd *pending_find_data(u16 opcode, | |||
789 | return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data); | 832 | return mgmt_pending_find_data(HCI_CHANNEL_CONTROL, opcode, hdev, data); |
790 | } | 833 | } |
791 | 834 | ||
792 | static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr) | 835 | static u8 create_default_scan_rsp_data(struct hci_dev *hdev, u8 *ptr) |
793 | { | 836 | { |
794 | u8 ad_len = 0; | 837 | u8 ad_len = 0; |
795 | size_t name_len; | 838 | size_t name_len; |
@@ -815,7 +858,19 @@ static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr) | |||
815 | return ad_len; | 858 | return ad_len; |
816 | } | 859 | } |
817 | 860 | ||
818 | static void update_scan_rsp_data(struct hci_request *req) | 861 | static u8 create_instance_scan_rsp_data(struct hci_dev *hdev, u8 *ptr) |
862 | { | ||
863 | /* TODO: Set the appropriate entries based on advertising instance flags | ||
864 | * here once flags other than 0 are supported. | ||
865 | */ | ||
866 | memcpy(ptr, hdev->adv_instance.scan_rsp_data, | ||
867 | hdev->adv_instance.scan_rsp_len); | ||
868 | |||
869 | return hdev->adv_instance.scan_rsp_len; | ||
870 | } | ||
871 | |||
872 | static void update_scan_rsp_data_for_instance(struct hci_request *req, | ||
873 | u8 instance) | ||
819 | { | 874 | { |
820 | struct hci_dev *hdev = req->hdev; | 875 | struct hci_dev *hdev = req->hdev; |
821 | struct hci_cp_le_set_scan_rsp_data cp; | 876 | struct hci_cp_le_set_scan_rsp_data cp; |
@@ -826,10 +881,13 @@ static void update_scan_rsp_data(struct hci_request *req) | |||
826 | 881 | ||
827 | memset(&cp, 0, sizeof(cp)); | 882 | memset(&cp, 0, sizeof(cp)); |
828 | 883 | ||
829 | len = create_scan_rsp_data(hdev, cp.data); | 884 | if (instance) |
885 | len = create_instance_scan_rsp_data(hdev, cp.data); | ||
886 | else | ||
887 | len = create_default_scan_rsp_data(hdev, cp.data); | ||
830 | 888 | ||
831 | if (hdev->scan_rsp_data_len == len && | 889 | if (hdev->scan_rsp_data_len == len && |
832 | memcmp(cp.data, hdev->scan_rsp_data, len) == 0) | 890 | !memcmp(cp.data, hdev->scan_rsp_data, len)) |
833 | return; | 891 | return; |
834 | 892 | ||
835 | memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data)); | 893 | memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data)); |
@@ -840,6 +898,25 @@ static void update_scan_rsp_data(struct hci_request *req) | |||
840 | hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp); | 898 | hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp); |
841 | } | 899 | } |
842 | 900 | ||
901 | static void update_scan_rsp_data(struct hci_request *req) | ||
902 | { | ||
903 | struct hci_dev *hdev = req->hdev; | ||
904 | u8 instance; | ||
905 | |||
906 | /* The "Set Advertising" setting supersedes the "Add Advertising" | ||
907 | * setting. Here we set the scan response data based on which | ||
908 | * setting was set. When neither apply, default to the global settings, | ||
909 | * represented by instance "0". | ||
910 | */ | ||
911 | if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) && | ||
912 | !hci_dev_test_flag(hdev, HCI_ADVERTISING)) | ||
913 | instance = 0x01; | ||
914 | else | ||
915 | instance = 0x00; | ||
916 | |||
917 | update_scan_rsp_data_for_instance(req, instance); | ||
918 | } | ||
919 | |||
843 | static u8 get_adv_discov_flags(struct hci_dev *hdev) | 920 | static u8 get_adv_discov_flags(struct hci_dev *hdev) |
844 | { | 921 | { |
845 | struct mgmt_pending_cmd *cmd; | 922 | struct mgmt_pending_cmd *cmd; |
@@ -864,39 +941,116 @@ static u8 get_adv_discov_flags(struct hci_dev *hdev) | |||
864 | return 0; | 941 | return 0; |
865 | } | 942 | } |
866 | 943 | ||
867 | static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr) | 944 | static u8 get_current_adv_instance(struct hci_dev *hdev) |
945 | { | ||
946 | /* The "Set Advertising" setting supersedes the "Add Advertising" | ||
947 | * setting. Here we set the advertising data based on which | ||
948 | * setting was set. When neither apply, default to the global settings, | ||
949 | * represented by instance "0". | ||
950 | */ | ||
951 | if (hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE) && | ||
952 | !hci_dev_test_flag(hdev, HCI_ADVERTISING)) | ||
953 | return 0x01; | ||
954 | |||
955 | return 0x00; | ||
956 | } | ||
957 | |||
958 | static bool get_connectable(struct hci_dev *hdev) | ||
959 | { | ||
960 | struct mgmt_pending_cmd *cmd; | ||
961 | |||
962 | /* If there's a pending mgmt command the flag will not yet have | ||
963 | * it's final value, so check for this first. | ||
964 | */ | ||
965 | cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev); | ||
966 | if (cmd) { | ||
967 | struct mgmt_mode *cp = cmd->param; | ||
968 | |||
969 | return cp->val; | ||
970 | } | ||
971 | |||
972 | return hci_dev_test_flag(hdev, HCI_CONNECTABLE); | ||
973 | } | ||
974 | |||
975 | static u32 get_adv_instance_flags(struct hci_dev *hdev, u8 instance) | ||
976 | { | ||
977 | u32 flags; | ||
978 | |||
979 | if (instance > 0x01) | ||
980 | return 0; | ||
981 | |||
982 | if (instance == 0x01) | ||
983 | return hdev->adv_instance.flags; | ||
984 | |||
985 | /* Instance 0 always manages the "Tx Power" and "Flags" fields */ | ||
986 | flags = MGMT_ADV_FLAG_TX_POWER | MGMT_ADV_FLAG_MANAGED_FLAGS; | ||
987 | |||
988 | /* For instance 0, assemble the flags from global settings */ | ||
989 | if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE) || | ||
990 | get_connectable(hdev)) | ||
991 | flags |= MGMT_ADV_FLAG_CONNECTABLE; | ||
992 | |||
993 | return flags; | ||
994 | } | ||
995 | |||
996 | static u8 create_instance_adv_data(struct hci_dev *hdev, u8 instance, u8 *ptr) | ||
868 | { | 997 | { |
869 | u8 ad_len = 0, flags = 0; | 998 | u8 ad_len = 0, flags = 0; |
999 | u32 instance_flags = get_adv_instance_flags(hdev, instance); | ||
870 | 1000 | ||
871 | flags |= get_adv_discov_flags(hdev); | 1001 | /* The Add Advertising command allows userspace to set both the general |
1002 | * and limited discoverable flags. | ||
1003 | */ | ||
1004 | if (instance_flags & MGMT_ADV_FLAG_DISCOV) | ||
1005 | flags |= LE_AD_GENERAL; | ||
872 | 1006 | ||
873 | if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) | 1007 | if (instance_flags & MGMT_ADV_FLAG_LIMITED_DISCOV) |
874 | flags |= LE_AD_NO_BREDR; | 1008 | flags |= LE_AD_LIMITED; |
875 | 1009 | ||
876 | if (flags) { | 1010 | if (flags || (instance_flags & MGMT_ADV_FLAG_MANAGED_FLAGS)) { |
877 | BT_DBG("adv flags 0x%02x", flags); | 1011 | /* If a discovery flag wasn't provided, simply use the global |
1012 | * settings. | ||
1013 | */ | ||
1014 | if (!flags) | ||
1015 | flags |= get_adv_discov_flags(hdev); | ||
878 | 1016 | ||
879 | ptr[0] = 2; | 1017 | if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) |
880 | ptr[1] = EIR_FLAGS; | 1018 | flags |= LE_AD_NO_BREDR; |
881 | ptr[2] = flags; | ||
882 | 1019 | ||
883 | ad_len += 3; | 1020 | /* If flags would still be empty, then there is no need to |
884 | ptr += 3; | 1021 | * include the "Flags" AD field". |
1022 | */ | ||
1023 | if (flags) { | ||
1024 | ptr[0] = 0x02; | ||
1025 | ptr[1] = EIR_FLAGS; | ||
1026 | ptr[2] = flags; | ||
1027 | |||
1028 | ad_len += 3; | ||
1029 | ptr += 3; | ||
1030 | } | ||
885 | } | 1031 | } |
886 | 1032 | ||
887 | if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) { | 1033 | /* Provide Tx Power only if we can provide a valid value for it */ |
888 | ptr[0] = 2; | 1034 | if (hdev->adv_tx_power != HCI_TX_POWER_INVALID && |
1035 | (instance_flags & MGMT_ADV_FLAG_TX_POWER)) { | ||
1036 | ptr[0] = 0x02; | ||
889 | ptr[1] = EIR_TX_POWER; | 1037 | ptr[1] = EIR_TX_POWER; |
890 | ptr[2] = (u8) hdev->adv_tx_power; | 1038 | ptr[2] = (u8)hdev->adv_tx_power; |
891 | 1039 | ||
892 | ad_len += 3; | 1040 | ad_len += 3; |
893 | ptr += 3; | 1041 | ptr += 3; |
894 | } | 1042 | } |
895 | 1043 | ||
1044 | if (instance) { | ||
1045 | memcpy(ptr, hdev->adv_instance.adv_data, | ||
1046 | hdev->adv_instance.adv_data_len); | ||
1047 | ad_len += hdev->adv_instance.adv_data_len; | ||
1048 | } | ||
1049 | |||
896 | return ad_len; | 1050 | return ad_len; |
897 | } | 1051 | } |
898 | 1052 | ||
899 | static void update_adv_data(struct hci_request *req) | 1053 | static void update_adv_data_for_instance(struct hci_request *req, u8 instance) |
900 | { | 1054 | { |
901 | struct hci_dev *hdev = req->hdev; | 1055 | struct hci_dev *hdev = req->hdev; |
902 | struct hci_cp_le_set_adv_data cp; | 1056 | struct hci_cp_le_set_adv_data cp; |
@@ -907,8 +1061,9 @@ static void update_adv_data(struct hci_request *req) | |||
907 | 1061 | ||
908 | memset(&cp, 0, sizeof(cp)); | 1062 | memset(&cp, 0, sizeof(cp)); |
909 | 1063 | ||
910 | len = create_adv_data(hdev, cp.data); | 1064 | len = create_instance_adv_data(hdev, instance, cp.data); |
911 | 1065 | ||
1066 | /* There's nothing to do if the data hasn't changed */ | ||
912 | if (hdev->adv_data_len == len && | 1067 | if (hdev->adv_data_len == len && |
913 | memcmp(cp.data, hdev->adv_data, len) == 0) | 1068 | memcmp(cp.data, hdev->adv_data, len) == 0) |
914 | return; | 1069 | return; |
@@ -921,6 +1076,14 @@ static void update_adv_data(struct hci_request *req) | |||
921 | hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp); | 1076 | hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp); |
922 | } | 1077 | } |
923 | 1078 | ||
1079 | static void update_adv_data(struct hci_request *req) | ||
1080 | { | ||
1081 | struct hci_dev *hdev = req->hdev; | ||
1082 | u8 instance = get_current_adv_instance(hdev); | ||
1083 | |||
1084 | update_adv_data_for_instance(req, instance); | ||
1085 | } | ||
1086 | |||
924 | int mgmt_update_adv_data(struct hci_dev *hdev) | 1087 | int mgmt_update_adv_data(struct hci_dev *hdev) |
925 | { | 1088 | { |
926 | struct hci_request req; | 1089 | struct hci_request req; |
@@ -1048,22 +1211,6 @@ static void update_class(struct hci_request *req) | |||
1048 | hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod); | 1211 | hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod); |
1049 | } | 1212 | } |
1050 | 1213 | ||
1051 | static bool get_connectable(struct hci_dev *hdev) | ||
1052 | { | ||
1053 | struct mgmt_pending_cmd *cmd; | ||
1054 | |||
1055 | /* If there's a pending mgmt command the flag will not yet have | ||
1056 | * it's final value, so check for this first. | ||
1057 | */ | ||
1058 | cmd = pending_find(MGMT_OP_SET_CONNECTABLE, hdev); | ||
1059 | if (cmd) { | ||
1060 | struct mgmt_mode *cp = cmd->param; | ||
1061 | return cp->val; | ||
1062 | } | ||
1063 | |||
1064 | return hci_dev_test_flag(hdev, HCI_CONNECTABLE); | ||
1065 | } | ||
1066 | |||
1067 | static void disable_advertising(struct hci_request *req) | 1214 | static void disable_advertising(struct hci_request *req) |
1068 | { | 1215 | { |
1069 | u8 enable = 0x00; | 1216 | u8 enable = 0x00; |
@@ -1077,6 +1224,8 @@ static void enable_advertising(struct hci_request *req) | |||
1077 | struct hci_cp_le_set_adv_param cp; | 1224 | struct hci_cp_le_set_adv_param cp; |
1078 | u8 own_addr_type, enable = 0x01; | 1225 | u8 own_addr_type, enable = 0x01; |
1079 | bool connectable; | 1226 | bool connectable; |
1227 | u8 instance; | ||
1228 | u32 flags; | ||
1080 | 1229 | ||
1081 | if (hci_conn_num(hdev, LE_LINK) > 0) | 1230 | if (hci_conn_num(hdev, LE_LINK) > 0) |
1082 | return; | 1231 | return; |
@@ -1091,10 +1240,9 @@ static void enable_advertising(struct hci_request *req) | |||
1091 | */ | 1240 | */ |
1092 | hci_dev_clear_flag(hdev, HCI_LE_ADV); | 1241 | hci_dev_clear_flag(hdev, HCI_LE_ADV); |
1093 | 1242 | ||
1094 | if (hci_dev_test_flag(hdev, HCI_ADVERTISING_CONNECTABLE)) | 1243 | instance = get_current_adv_instance(hdev); |
1095 | connectable = true; | 1244 | flags = get_adv_instance_flags(hdev, instance); |
1096 | else | 1245 | connectable = (flags & MGMT_ADV_FLAG_CONNECTABLE); |
1097 | connectable = get_connectable(hdev); | ||
1098 | 1246 | ||
1099 | /* Set require_privacy to true only when non-connectable | 1247 | /* Set require_privacy to true only when non-connectable |
1100 | * advertising is used. In that case it is fine to use a | 1248 | * advertising is used. In that case it is fine to use a |
@@ -1264,6 +1412,49 @@ static bool hci_stop_discovery(struct hci_request *req) | |||
1264 | return false; | 1412 | return false; |
1265 | } | 1413 | } |
1266 | 1414 | ||
1415 | static void advertising_added(struct sock *sk, struct hci_dev *hdev, | ||
1416 | u8 instance) | ||
1417 | { | ||
1418 | struct mgmt_ev_advertising_added ev; | ||
1419 | |||
1420 | ev.instance = instance; | ||
1421 | |||
1422 | mgmt_event(MGMT_EV_ADVERTISING_ADDED, hdev, &ev, sizeof(ev), sk); | ||
1423 | } | ||
1424 | |||
1425 | static void advertising_removed(struct sock *sk, struct hci_dev *hdev, | ||
1426 | u8 instance) | ||
1427 | { | ||
1428 | struct mgmt_ev_advertising_removed ev; | ||
1429 | |||
1430 | ev.instance = instance; | ||
1431 | |||
1432 | mgmt_event(MGMT_EV_ADVERTISING_REMOVED, hdev, &ev, sizeof(ev), sk); | ||
1433 | } | ||
1434 | |||
1435 | static void clear_adv_instance(struct hci_dev *hdev) | ||
1436 | { | ||
1437 | struct hci_request req; | ||
1438 | |||
1439 | if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE)) | ||
1440 | return; | ||
1441 | |||
1442 | if (hdev->adv_instance.timeout) | ||
1443 | cancel_delayed_work(&hdev->adv_instance.timeout_exp); | ||
1444 | |||
1445 | memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance)); | ||
1446 | advertising_removed(NULL, hdev, 1); | ||
1447 | hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE); | ||
1448 | |||
1449 | if (!hdev_is_powered(hdev) || | ||
1450 | hci_dev_test_flag(hdev, HCI_ADVERTISING)) | ||
1451 | return; | ||
1452 | |||
1453 | hci_req_init(&req, hdev); | ||
1454 | disable_advertising(&req); | ||
1455 | hci_req_run(&req, NULL); | ||
1456 | } | ||
1457 | |||
1267 | static int clean_up_hci_state(struct hci_dev *hdev) | 1458 | static int clean_up_hci_state(struct hci_dev *hdev) |
1268 | { | 1459 | { |
1269 | struct hci_request req; | 1460 | struct hci_request req; |
@@ -1279,6 +1470,9 @@ static int clean_up_hci_state(struct hci_dev *hdev) | |||
1279 | hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); | 1470 | hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan); |
1280 | } | 1471 | } |
1281 | 1472 | ||
1473 | if (hdev->adv_instance.timeout) | ||
1474 | clear_adv_instance(hdev); | ||
1475 | |||
1282 | if (hci_dev_test_flag(hdev, HCI_LE_ADV)) | 1476 | if (hci_dev_test_flag(hdev, HCI_LE_ADV)) |
1283 | disable_advertising(&req); | 1477 | disable_advertising(&req); |
1284 | 1478 | ||
@@ -2209,10 +2403,22 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len) | |||
2209 | return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE, | 2403 | return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE, |
2210 | MGMT_STATUS_INVALID_PARAMS); | 2404 | MGMT_STATUS_INVALID_PARAMS); |
2211 | 2405 | ||
2212 | /* LE-only devices do not allow toggling LE on/off */ | 2406 | /* Bluetooth single mode LE only controllers or dual-mode |
2213 | if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) | 2407 | * controllers configured as LE only devices, do not allow |
2408 | * switching LE off. These have either LE enabled explicitly | ||
2409 | * or BR/EDR has been previously switched off. | ||
2410 | * | ||
2411 | * When trying to enable an already enabled LE, then gracefully | ||
2412 | * send a positive response. Trying to disable it however will | ||
2413 | * result into rejection. | ||
2414 | */ | ||
2415 | if (!hci_dev_test_flag(hdev, HCI_BREDR_ENABLED)) { | ||
2416 | if (cp->val == 0x01) | ||
2417 | return send_settings_rsp(sk, MGMT_OP_SET_LE, hdev); | ||
2418 | |||
2214 | return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE, | 2419 | return mgmt_cmd_status(sk, hdev->id, MGMT_OP_SET_LE, |
2215 | MGMT_STATUS_REJECTED); | 2420 | MGMT_STATUS_REJECTED); |
2421 | } | ||
2216 | 2422 | ||
2217 | hci_dev_lock(hdev); | 2423 | hci_dev_lock(hdev); |
2218 | 2424 | ||
@@ -4362,10 +4568,17 @@ static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data, | |||
4362 | return err; | 4568 | return err; |
4363 | } | 4569 | } |
4364 | 4570 | ||
4571 | static void enable_advertising_instance(struct hci_dev *hdev, u8 status, | ||
4572 | u16 opcode) | ||
4573 | { | ||
4574 | BT_DBG("status %d", status); | ||
4575 | } | ||
4576 | |||
4365 | static void set_advertising_complete(struct hci_dev *hdev, u8 status, | 4577 | static void set_advertising_complete(struct hci_dev *hdev, u8 status, |
4366 | u16 opcode) | 4578 | u16 opcode) |
4367 | { | 4579 | { |
4368 | struct cmd_lookup match = { NULL, hdev }; | 4580 | struct cmd_lookup match = { NULL, hdev }; |
4581 | struct hci_request req; | ||
4369 | 4582 | ||
4370 | hci_dev_lock(hdev); | 4583 | hci_dev_lock(hdev); |
4371 | 4584 | ||
@@ -4390,6 +4603,21 @@ static void set_advertising_complete(struct hci_dev *hdev, u8 status, | |||
4390 | if (match.sk) | 4603 | if (match.sk) |
4391 | sock_put(match.sk); | 4604 | sock_put(match.sk); |
4392 | 4605 | ||
4606 | /* If "Set Advertising" was just disabled and instance advertising was | ||
4607 | * set up earlier, then enable the advertising instance. | ||
4608 | */ | ||
4609 | if (hci_dev_test_flag(hdev, HCI_ADVERTISING) || | ||
4610 | !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE)) | ||
4611 | goto unlock; | ||
4612 | |||
4613 | hci_req_init(&req, hdev); | ||
4614 | |||
4615 | update_adv_data(&req); | ||
4616 | enable_advertising(&req); | ||
4617 | |||
4618 | if (hci_req_run(&req, enable_advertising_instance) < 0) | ||
4619 | BT_ERR("Failed to re-configure advertising"); | ||
4620 | |||
4393 | unlock: | 4621 | unlock: |
4394 | hci_dev_unlock(hdev); | 4622 | hci_dev_unlock(hdev); |
4395 | } | 4623 | } |
@@ -4472,10 +4700,14 @@ static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data, | |||
4472 | else | 4700 | else |
4473 | hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE); | 4701 | hci_dev_clear_flag(hdev, HCI_ADVERTISING_CONNECTABLE); |
4474 | 4702 | ||
4475 | if (val) | 4703 | if (val) { |
4704 | /* Switch to instance "0" for the Set Advertising setting. */ | ||
4705 | update_adv_data_for_instance(&req, 0); | ||
4706 | update_scan_rsp_data_for_instance(&req, 0); | ||
4476 | enable_advertising(&req); | 4707 | enable_advertising(&req); |
4477 | else | 4708 | } else { |
4478 | disable_advertising(&req); | 4709 | disable_advertising(&req); |
4710 | } | ||
4479 | 4711 | ||
4480 | err = hci_req_run(&req, set_advertising_complete); | 4712 | err = hci_req_run(&req, set_advertising_complete); |
4481 | if (err < 0) | 4713 | if (err < 0) |
@@ -6281,29 +6513,69 @@ done: | |||
6281 | return err; | 6513 | return err; |
6282 | } | 6514 | } |
6283 | 6515 | ||
6516 | static u32 get_supported_adv_flags(struct hci_dev *hdev) | ||
6517 | { | ||
6518 | u32 flags = 0; | ||
6519 | |||
6520 | flags |= MGMT_ADV_FLAG_CONNECTABLE; | ||
6521 | flags |= MGMT_ADV_FLAG_DISCOV; | ||
6522 | flags |= MGMT_ADV_FLAG_LIMITED_DISCOV; | ||
6523 | flags |= MGMT_ADV_FLAG_MANAGED_FLAGS; | ||
6524 | |||
6525 | if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) | ||
6526 | flags |= MGMT_ADV_FLAG_TX_POWER; | ||
6527 | |||
6528 | return flags; | ||
6529 | } | ||
6530 | |||
6284 | static int read_adv_features(struct sock *sk, struct hci_dev *hdev, | 6531 | static int read_adv_features(struct sock *sk, struct hci_dev *hdev, |
6285 | void *data, u16 data_len) | 6532 | void *data, u16 data_len) |
6286 | { | 6533 | { |
6287 | struct mgmt_rp_read_adv_features *rp; | 6534 | struct mgmt_rp_read_adv_features *rp; |
6288 | size_t rp_len; | 6535 | size_t rp_len; |
6289 | int err; | 6536 | int err; |
6537 | bool instance; | ||
6538 | u32 supported_flags; | ||
6290 | 6539 | ||
6291 | BT_DBG("%s", hdev->name); | 6540 | BT_DBG("%s", hdev->name); |
6292 | 6541 | ||
6542 | if (!lmp_le_capable(hdev)) | ||
6543 | return mgmt_cmd_status(sk, hdev->id, MGMT_OP_READ_ADV_FEATURES, | ||
6544 | MGMT_STATUS_REJECTED); | ||
6545 | |||
6293 | hci_dev_lock(hdev); | 6546 | hci_dev_lock(hdev); |
6294 | 6547 | ||
6295 | rp_len = sizeof(*rp); | 6548 | rp_len = sizeof(*rp); |
6549 | |||
6550 | /* Currently only one instance is supported, so just add 1 to the | ||
6551 | * response length. | ||
6552 | */ | ||
6553 | instance = hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE); | ||
6554 | if (instance) | ||
6555 | rp_len++; | ||
6556 | |||
6296 | rp = kmalloc(rp_len, GFP_ATOMIC); | 6557 | rp = kmalloc(rp_len, GFP_ATOMIC); |
6297 | if (!rp) { | 6558 | if (!rp) { |
6298 | hci_dev_unlock(hdev); | 6559 | hci_dev_unlock(hdev); |
6299 | return -ENOMEM; | 6560 | return -ENOMEM; |
6300 | } | 6561 | } |
6301 | 6562 | ||
6302 | rp->supported_flags = cpu_to_le32(0); | 6563 | supported_flags = get_supported_adv_flags(hdev); |
6303 | rp->max_adv_data_len = 31; | 6564 | |
6304 | rp->max_scan_rsp_len = 31; | 6565 | rp->supported_flags = cpu_to_le32(supported_flags); |
6305 | rp->max_instances = 0; | 6566 | rp->max_adv_data_len = HCI_MAX_AD_LENGTH; |
6306 | rp->num_instances = 0; | 6567 | rp->max_scan_rsp_len = HCI_MAX_AD_LENGTH; |
6568 | rp->max_instances = 1; | ||
6569 | |||
6570 | /* Currently only one instance is supported, so simply return the | ||
6571 | * current instance number. | ||
6572 | */ | ||
6573 | if (instance) { | ||
6574 | rp->num_instances = 1; | ||
6575 | rp->instance[0] = 1; | ||
6576 | } else { | ||
6577 | rp->num_instances = 0; | ||
6578 | } | ||
6307 | 6579 | ||
6308 | hci_dev_unlock(hdev); | 6580 | hci_dev_unlock(hdev); |
6309 | 6581 | ||
@@ -6315,6 +6587,318 @@ static int read_adv_features(struct sock *sk, struct hci_dev *hdev, | |||
6315 | return err; | 6587 | return err; |
6316 | } | 6588 | } |
6317 | 6589 | ||
6590 | static bool tlv_data_is_valid(struct hci_dev *hdev, u32 adv_flags, u8 *data, | ||
6591 | u8 len, bool is_adv_data) | ||
6592 | { | ||
6593 | u8 max_len = HCI_MAX_AD_LENGTH; | ||
6594 | int i, cur_len; | ||
6595 | bool flags_managed = false; | ||
6596 | bool tx_power_managed = false; | ||
6597 | u32 flags_params = MGMT_ADV_FLAG_DISCOV | MGMT_ADV_FLAG_LIMITED_DISCOV | | ||
6598 | MGMT_ADV_FLAG_MANAGED_FLAGS; | ||
6599 | |||
6600 | if (is_adv_data && (adv_flags & flags_params)) { | ||
6601 | flags_managed = true; | ||
6602 | max_len -= 3; | ||
6603 | } | ||
6604 | |||
6605 | if (is_adv_data && (adv_flags & MGMT_ADV_FLAG_TX_POWER)) { | ||
6606 | tx_power_managed = true; | ||
6607 | max_len -= 3; | ||
6608 | } | ||
6609 | |||
6610 | if (len > max_len) | ||
6611 | return false; | ||
6612 | |||
6613 | /* Make sure that the data is correctly formatted. */ | ||
6614 | for (i = 0, cur_len = 0; i < len; i += (cur_len + 1)) { | ||
6615 | cur_len = data[i]; | ||
6616 | |||
6617 | if (flags_managed && data[i + 1] == EIR_FLAGS) | ||
6618 | return false; | ||
6619 | |||
6620 | if (tx_power_managed && data[i + 1] == EIR_TX_POWER) | ||
6621 | return false; | ||
6622 | |||
6623 | /* If the current field length would exceed the total data | ||
6624 | * length, then it's invalid. | ||
6625 | */ | ||
6626 | if (i + cur_len >= len) | ||
6627 | return false; | ||
6628 | } | ||
6629 | |||
6630 | return true; | ||
6631 | } | ||
6632 | |||
6633 | static void add_advertising_complete(struct hci_dev *hdev, u8 status, | ||
6634 | u16 opcode) | ||
6635 | { | ||
6636 | struct mgmt_pending_cmd *cmd; | ||
6637 | struct mgmt_rp_add_advertising rp; | ||
6638 | |||
6639 | BT_DBG("status %d", status); | ||
6640 | |||
6641 | hci_dev_lock(hdev); | ||
6642 | |||
6643 | cmd = pending_find(MGMT_OP_ADD_ADVERTISING, hdev); | ||
6644 | |||
6645 | if (status) { | ||
6646 | hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE); | ||
6647 | memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance)); | ||
6648 | advertising_removed(cmd ? cmd->sk : NULL, hdev, 1); | ||
6649 | } | ||
6650 | |||
6651 | if (!cmd) | ||
6652 | goto unlock; | ||
6653 | |||
6654 | rp.instance = 0x01; | ||
6655 | |||
6656 | if (status) | ||
6657 | mgmt_cmd_status(cmd->sk, cmd->index, cmd->opcode, | ||
6658 | mgmt_status(status)); | ||
6659 | else | ||
6660 | mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, | ||
6661 | mgmt_status(status), &rp, sizeof(rp)); | ||
6662 | |||
6663 | mgmt_pending_remove(cmd); | ||
6664 | |||
6665 | unlock: | ||
6666 | hci_dev_unlock(hdev); | ||
6667 | } | ||
6668 | |||
6669 | static void adv_timeout_expired(struct work_struct *work) | ||
6670 | { | ||
6671 | struct hci_dev *hdev = container_of(work, struct hci_dev, | ||
6672 | adv_instance.timeout_exp.work); | ||
6673 | |||
6674 | hdev->adv_instance.timeout = 0; | ||
6675 | |||
6676 | hci_dev_lock(hdev); | ||
6677 | clear_adv_instance(hdev); | ||
6678 | hci_dev_unlock(hdev); | ||
6679 | } | ||
6680 | |||
6681 | static int add_advertising(struct sock *sk, struct hci_dev *hdev, | ||
6682 | void *data, u16 data_len) | ||
6683 | { | ||
6684 | struct mgmt_cp_add_advertising *cp = data; | ||
6685 | struct mgmt_rp_add_advertising rp; | ||
6686 | u32 flags; | ||
6687 | u32 supported_flags; | ||
6688 | u8 status; | ||
6689 | u16 timeout; | ||
6690 | int err; | ||
6691 | struct mgmt_pending_cmd *cmd; | ||
6692 | struct hci_request req; | ||
6693 | |||
6694 | BT_DBG("%s", hdev->name); | ||
6695 | |||
6696 | status = mgmt_le_support(hdev); | ||
6697 | if (status) | ||
6698 | return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING, | ||
6699 | status); | ||
6700 | |||
6701 | flags = __le32_to_cpu(cp->flags); | ||
6702 | timeout = __le16_to_cpu(cp->timeout); | ||
6703 | |||
6704 | /* The current implementation only supports adding one instance and only | ||
6705 | * a subset of the specified flags. | ||
6706 | */ | ||
6707 | supported_flags = get_supported_adv_flags(hdev); | ||
6708 | if (cp->instance != 0x01 || (flags & ~supported_flags)) | ||
6709 | return mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING, | ||
6710 | MGMT_STATUS_INVALID_PARAMS); | ||
6711 | |||
6712 | hci_dev_lock(hdev); | ||
6713 | |||
6714 | if (timeout && !hdev_is_powered(hdev)) { | ||
6715 | err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING, | ||
6716 | MGMT_STATUS_REJECTED); | ||
6717 | goto unlock; | ||
6718 | } | ||
6719 | |||
6720 | if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) || | ||
6721 | pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) || | ||
6722 | pending_find(MGMT_OP_SET_LE, hdev)) { | ||
6723 | err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING, | ||
6724 | MGMT_STATUS_BUSY); | ||
6725 | goto unlock; | ||
6726 | } | ||
6727 | |||
6728 | if (!tlv_data_is_valid(hdev, flags, cp->data, cp->adv_data_len, true) || | ||
6729 | !tlv_data_is_valid(hdev, flags, cp->data + cp->adv_data_len, | ||
6730 | cp->scan_rsp_len, false)) { | ||
6731 | err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_ADD_ADVERTISING, | ||
6732 | MGMT_STATUS_INVALID_PARAMS); | ||
6733 | goto unlock; | ||
6734 | } | ||
6735 | |||
6736 | INIT_DELAYED_WORK(&hdev->adv_instance.timeout_exp, adv_timeout_expired); | ||
6737 | |||
6738 | hdev->adv_instance.flags = flags; | ||
6739 | hdev->adv_instance.adv_data_len = cp->adv_data_len; | ||
6740 | hdev->adv_instance.scan_rsp_len = cp->scan_rsp_len; | ||
6741 | |||
6742 | if (cp->adv_data_len) | ||
6743 | memcpy(hdev->adv_instance.adv_data, cp->data, cp->adv_data_len); | ||
6744 | |||
6745 | if (cp->scan_rsp_len) | ||
6746 | memcpy(hdev->adv_instance.scan_rsp_data, | ||
6747 | cp->data + cp->adv_data_len, cp->scan_rsp_len); | ||
6748 | |||
6749 | if (hdev->adv_instance.timeout) | ||
6750 | cancel_delayed_work(&hdev->adv_instance.timeout_exp); | ||
6751 | |||
6752 | hdev->adv_instance.timeout = timeout; | ||
6753 | |||
6754 | if (timeout) | ||
6755 | queue_delayed_work(hdev->workqueue, | ||
6756 | &hdev->adv_instance.timeout_exp, | ||
6757 | msecs_to_jiffies(timeout * 1000)); | ||
6758 | |||
6759 | if (!hci_dev_test_and_set_flag(hdev, HCI_ADVERTISING_INSTANCE)) | ||
6760 | advertising_added(sk, hdev, 1); | ||
6761 | |||
6762 | /* If the HCI_ADVERTISING flag is set or the device isn't powered then | ||
6763 | * we have no HCI communication to make. Simply return. | ||
6764 | */ | ||
6765 | if (!hdev_is_powered(hdev) || | ||
6766 | hci_dev_test_flag(hdev, HCI_ADVERTISING)) { | ||
6767 | rp.instance = 0x01; | ||
6768 | err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_ADD_ADVERTISING, | ||
6769 | MGMT_STATUS_SUCCESS, &rp, sizeof(rp)); | ||
6770 | goto unlock; | ||
6771 | } | ||
6772 | |||
6773 | /* We're good to go, update advertising data, parameters, and start | ||
6774 | * advertising. | ||
6775 | */ | ||
6776 | cmd = mgmt_pending_add(sk, MGMT_OP_ADD_ADVERTISING, hdev, data, | ||
6777 | data_len); | ||
6778 | if (!cmd) { | ||
6779 | err = -ENOMEM; | ||
6780 | goto unlock; | ||
6781 | } | ||
6782 | |||
6783 | hci_req_init(&req, hdev); | ||
6784 | |||
6785 | update_adv_data(&req); | ||
6786 | update_scan_rsp_data(&req); | ||
6787 | enable_advertising(&req); | ||
6788 | |||
6789 | err = hci_req_run(&req, add_advertising_complete); | ||
6790 | if (err < 0) | ||
6791 | mgmt_pending_remove(cmd); | ||
6792 | |||
6793 | unlock: | ||
6794 | hci_dev_unlock(hdev); | ||
6795 | |||
6796 | return err; | ||
6797 | } | ||
6798 | |||
6799 | static void remove_advertising_complete(struct hci_dev *hdev, u8 status, | ||
6800 | u16 opcode) | ||
6801 | { | ||
6802 | struct mgmt_pending_cmd *cmd; | ||
6803 | struct mgmt_rp_remove_advertising rp; | ||
6804 | |||
6805 | BT_DBG("status %d", status); | ||
6806 | |||
6807 | hci_dev_lock(hdev); | ||
6808 | |||
6809 | /* A failure status here only means that we failed to disable | ||
6810 | * advertising. Otherwise, the advertising instance has been removed, | ||
6811 | * so report success. | ||
6812 | */ | ||
6813 | cmd = pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev); | ||
6814 | if (!cmd) | ||
6815 | goto unlock; | ||
6816 | |||
6817 | rp.instance = 1; | ||
6818 | |||
6819 | mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode, MGMT_STATUS_SUCCESS, | ||
6820 | &rp, sizeof(rp)); | ||
6821 | mgmt_pending_remove(cmd); | ||
6822 | |||
6823 | unlock: | ||
6824 | hci_dev_unlock(hdev); | ||
6825 | } | ||
6826 | |||
6827 | static int remove_advertising(struct sock *sk, struct hci_dev *hdev, | ||
6828 | void *data, u16 data_len) | ||
6829 | { | ||
6830 | struct mgmt_cp_remove_advertising *cp = data; | ||
6831 | struct mgmt_rp_remove_advertising rp; | ||
6832 | int err; | ||
6833 | struct mgmt_pending_cmd *cmd; | ||
6834 | struct hci_request req; | ||
6835 | |||
6836 | BT_DBG("%s", hdev->name); | ||
6837 | |||
6838 | /* The current implementation only allows modifying instance no 1. A | ||
6839 | * value of 0 indicates that all instances should be cleared. | ||
6840 | */ | ||
6841 | if (cp->instance > 1) | ||
6842 | return mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING, | ||
6843 | MGMT_STATUS_INVALID_PARAMS); | ||
6844 | |||
6845 | hci_dev_lock(hdev); | ||
6846 | |||
6847 | if (pending_find(MGMT_OP_ADD_ADVERTISING, hdev) || | ||
6848 | pending_find(MGMT_OP_REMOVE_ADVERTISING, hdev) || | ||
6849 | pending_find(MGMT_OP_SET_LE, hdev)) { | ||
6850 | err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING, | ||
6851 | MGMT_STATUS_BUSY); | ||
6852 | goto unlock; | ||
6853 | } | ||
6854 | |||
6855 | if (!hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE)) { | ||
6856 | err = mgmt_cmd_status(sk, hdev->id, MGMT_OP_REMOVE_ADVERTISING, | ||
6857 | MGMT_STATUS_INVALID_PARAMS); | ||
6858 | goto unlock; | ||
6859 | } | ||
6860 | |||
6861 | if (hdev->adv_instance.timeout) | ||
6862 | cancel_delayed_work(&hdev->adv_instance.timeout_exp); | ||
6863 | |||
6864 | memset(&hdev->adv_instance, 0, sizeof(hdev->adv_instance)); | ||
6865 | |||
6866 | advertising_removed(sk, hdev, 1); | ||
6867 | |||
6868 | hci_dev_clear_flag(hdev, HCI_ADVERTISING_INSTANCE); | ||
6869 | |||
6870 | /* If the HCI_ADVERTISING flag is set or the device isn't powered then | ||
6871 | * we have no HCI communication to make. Simply return. | ||
6872 | */ | ||
6873 | if (!hdev_is_powered(hdev) || | ||
6874 | hci_dev_test_flag(hdev, HCI_ADVERTISING)) { | ||
6875 | rp.instance = 1; | ||
6876 | err = mgmt_cmd_complete(sk, hdev->id, | ||
6877 | MGMT_OP_REMOVE_ADVERTISING, | ||
6878 | MGMT_STATUS_SUCCESS, &rp, sizeof(rp)); | ||
6879 | goto unlock; | ||
6880 | } | ||
6881 | |||
6882 | cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_ADVERTISING, hdev, data, | ||
6883 | data_len); | ||
6884 | if (!cmd) { | ||
6885 | err = -ENOMEM; | ||
6886 | goto unlock; | ||
6887 | } | ||
6888 | |||
6889 | hci_req_init(&req, hdev); | ||
6890 | disable_advertising(&req); | ||
6891 | |||
6892 | err = hci_req_run(&req, remove_advertising_complete); | ||
6893 | if (err < 0) | ||
6894 | mgmt_pending_remove(cmd); | ||
6895 | |||
6896 | unlock: | ||
6897 | hci_dev_unlock(hdev); | ||
6898 | |||
6899 | return err; | ||
6900 | } | ||
6901 | |||
6318 | static const struct hci_mgmt_handler mgmt_handlers[] = { | 6902 | static const struct hci_mgmt_handler mgmt_handlers[] = { |
6319 | { NULL }, /* 0x0000 (no command) */ | 6903 | { NULL }, /* 0x0000 (no command) */ |
6320 | { read_version, MGMT_READ_VERSION_SIZE, | 6904 | { read_version, MGMT_READ_VERSION_SIZE, |
@@ -6399,6 +6983,9 @@ static const struct hci_mgmt_handler mgmt_handlers[] = { | |||
6399 | HCI_MGMT_NO_HDEV | | 6983 | HCI_MGMT_NO_HDEV | |
6400 | HCI_MGMT_UNTRUSTED }, | 6984 | HCI_MGMT_UNTRUSTED }, |
6401 | { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE }, | 6985 | { read_adv_features, MGMT_READ_ADV_FEATURES_SIZE }, |
6986 | { add_advertising, MGMT_ADD_ADVERTISING_SIZE, | ||
6987 | HCI_MGMT_VAR_LEN }, | ||
6988 | { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE }, | ||
6402 | }; | 6989 | }; |
6403 | 6990 | ||
6404 | void mgmt_index_added(struct hci_dev *hdev) | 6991 | void mgmt_index_added(struct hci_dev *hdev) |
@@ -6570,7 +7157,8 @@ static int powered_update_hci(struct hci_dev *hdev) | |||
6570 | update_scan_rsp_data(&req); | 7157 | update_scan_rsp_data(&req); |
6571 | } | 7158 | } |
6572 | 7159 | ||
6573 | if (hci_dev_test_flag(hdev, HCI_ADVERTISING)) | 7160 | if (hci_dev_test_flag(hdev, HCI_ADVERTISING) || |
7161 | hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE)) | ||
6574 | enable_advertising(&req); | 7162 | enable_advertising(&req); |
6575 | 7163 | ||
6576 | restart_le_actions(&req); | 7164 | restart_le_actions(&req); |
@@ -6682,7 +7270,13 @@ void mgmt_discoverable_timeout(struct hci_dev *hdev) | |||
6682 | sizeof(scan), &scan); | 7270 | sizeof(scan), &scan); |
6683 | } | 7271 | } |
6684 | update_class(&req); | 7272 | update_class(&req); |
6685 | update_adv_data(&req); | 7273 | |
7274 | /* Advertising instances don't use the global discoverable setting, so | ||
7275 | * only update AD if advertising was enabled using Set Advertising. | ||
7276 | */ | ||
7277 | if (hci_dev_test_flag(hdev, HCI_ADVERTISING)) | ||
7278 | update_adv_data(&req); | ||
7279 | |||
6686 | hci_req_run(&req, NULL); | 7280 | hci_req_run(&req, NULL); |
6687 | 7281 | ||
6688 | hdev->discov_timeout = 0; | 7282 | hdev->discov_timeout = 0; |
@@ -7583,7 +8177,8 @@ void mgmt_reenable_advertising(struct hci_dev *hdev) | |||
7583 | { | 8177 | { |
7584 | struct hci_request req; | 8178 | struct hci_request req; |
7585 | 8179 | ||
7586 | if (!hci_dev_test_flag(hdev, HCI_ADVERTISING)) | 8180 | if (!hci_dev_test_flag(hdev, HCI_ADVERTISING) && |
8181 | !hci_dev_test_flag(hdev, HCI_ADVERTISING_INSTANCE)) | ||
7587 | return; | 8182 | return; |
7588 | 8183 | ||
7589 | hci_req_init(&req, hdev); | 8184 | hci_req_init(&req, hdev); |
diff --git a/net/mac802154/iface.c b/net/mac802154/iface.c index 6fb6bdf9868c..38b56f9d9386 100644 --- a/net/mac802154/iface.c +++ b/net/mac802154/iface.c | |||
@@ -174,24 +174,16 @@ ieee802154_check_mac_settings(struct ieee802154_local *local, | |||
174 | } | 174 | } |
175 | 175 | ||
176 | if (local->hw.flags & IEEE802154_HW_AFILT) { | 176 | if (local->hw.flags & IEEE802154_HW_AFILT) { |
177 | if (wpan_dev->pan_id != nwpan_dev->pan_id) | 177 | if (wpan_dev->pan_id != nwpan_dev->pan_id || |
178 | return -EBUSY; | 178 | wpan_dev->short_addr != nwpan_dev->short_addr || |
179 | 179 | wpan_dev->extended_addr != nwpan_dev->extended_addr) | |
180 | if (wpan_dev->short_addr != nwpan_dev->short_addr) | ||
181 | return -EBUSY; | ||
182 | |||
183 | if (wpan_dev->extended_addr != nwpan_dev->extended_addr) | ||
184 | return -EBUSY; | 180 | return -EBUSY; |
185 | } | 181 | } |
186 | 182 | ||
187 | if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) { | 183 | if (local->hw.flags & IEEE802154_HW_CSMA_PARAMS) { |
188 | if (wpan_dev->min_be != nwpan_dev->min_be) | 184 | if (wpan_dev->min_be != nwpan_dev->min_be || |
189 | return -EBUSY; | 185 | wpan_dev->max_be != nwpan_dev->max_be || |
190 | 186 | wpan_dev->csma_retries != nwpan_dev->csma_retries) | |
191 | if (wpan_dev->max_be != nwpan_dev->max_be) | ||
192 | return -EBUSY; | ||
193 | |||
194 | if (wpan_dev->csma_retries != nwpan_dev->csma_retries) | ||
195 | return -EBUSY; | 187 | return -EBUSY; |
196 | } | 188 | } |
197 | 189 | ||