aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth
diff options
context:
space:
mode:
authorMarcel Holtmann <marcel@holtmann.org>2016-09-01 10:46:23 -0400
committerMarcel Holtmann <marcel@holtmann.org>2016-09-19 14:19:34 -0400
commit321c6feed2519a2691f65e41c4d62332d6ee3d52 (patch)
tree3dca0037c195c455f52205d2a4f2035f9f11b61a /net/bluetooth
parent418678b01aca849b4f86224e609610ce87a9bdc4 (diff)
Bluetooth: Add framework for Extended Controller Information
This command is used to retrieve the current state and basic information of a controller. It is typically used right after getting the response to the Read Controller Index List command or an Index Added event (or its extended counterparts). When any of the values in the EIR_Data field changes, the event Extended Controller Information Changed will be used to inform clients about the updated information. Signed-off-by: Marcel Holtmann <marcel@holtmann.org> Signed-off-by: MichaƂ Narajowski <michal.narajowski@codecoup.pl>
Diffstat (limited to 'net/bluetooth')
-rw-r--r--net/bluetooth/mgmt.c62
1 files changed, 60 insertions, 2 deletions
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 47efdb4a669a..69001f415efa 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -104,6 +104,7 @@ static const u16 mgmt_commands[] = {
104 MGMT_OP_REMOVE_ADVERTISING, 104 MGMT_OP_REMOVE_ADVERTISING,
105 MGMT_OP_GET_ADV_SIZE_INFO, 105 MGMT_OP_GET_ADV_SIZE_INFO,
106 MGMT_OP_START_LIMITED_DISCOVERY, 106 MGMT_OP_START_LIMITED_DISCOVERY,
107 MGMT_OP_READ_EXT_INFO,
107}; 108};
108 109
109static const u16 mgmt_events[] = { 110static const u16 mgmt_events[] = {
@@ -141,6 +142,7 @@ static const u16 mgmt_events[] = {
141 MGMT_EV_LOCAL_OOB_DATA_UPDATED, 142 MGMT_EV_LOCAL_OOB_DATA_UPDATED,
142 MGMT_EV_ADVERTISING_ADDED, 143 MGMT_EV_ADVERTISING_ADDED,
143 MGMT_EV_ADVERTISING_REMOVED, 144 MGMT_EV_ADVERTISING_REMOVED,
145 MGMT_EV_EXT_INFO_CHANGED,
144}; 146};
145 147
146static const u16 mgmt_untrusted_commands[] = { 148static const u16 mgmt_untrusted_commands[] = {
@@ -149,6 +151,7 @@ static const u16 mgmt_untrusted_commands[] = {
149 MGMT_OP_READ_UNCONF_INDEX_LIST, 151 MGMT_OP_READ_UNCONF_INDEX_LIST,
150 MGMT_OP_READ_CONFIG_INFO, 152 MGMT_OP_READ_CONFIG_INFO,
151 MGMT_OP_READ_EXT_INDEX_LIST, 153 MGMT_OP_READ_EXT_INDEX_LIST,
154 MGMT_OP_READ_EXT_INFO,
152}; 155};
153 156
154static const u16 mgmt_untrusted_events[] = { 157static const u16 mgmt_untrusted_events[] = {
@@ -162,6 +165,7 @@ static const u16 mgmt_untrusted_events[] = {
162 MGMT_EV_NEW_CONFIG_OPTIONS, 165 MGMT_EV_NEW_CONFIG_OPTIONS,
163 MGMT_EV_EXT_INDEX_ADDED, 166 MGMT_EV_EXT_INDEX_ADDED,
164 MGMT_EV_EXT_INDEX_REMOVED, 167 MGMT_EV_EXT_INDEX_REMOVED,
168 MGMT_EV_EXT_INFO_CHANGED,
165}; 169};
166 170
167#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000) 171#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
@@ -862,6 +866,52 @@ static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
862 sizeof(rp)); 866 sizeof(rp));
863} 867}
864 868
869static int read_ext_controller_info(struct sock *sk, struct hci_dev *hdev,
870 void *data, u16 data_len)
871{
872 struct mgmt_rp_read_ext_info rp;
873
874 BT_DBG("sock %p %s", sk, hdev->name);
875
876 hci_dev_lock(hdev);
877
878 memset(&rp, 0, sizeof(rp));
879
880 bacpy(&rp.bdaddr, &hdev->bdaddr);
881
882 rp.version = hdev->hci_ver;
883 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
884
885 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
886 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
887
888 rp.eir_len = cpu_to_le16(0);
889
890 hci_dev_unlock(hdev);
891
892 /* If this command is called at least once, then the events
893 * for class of device and local name changes are disabled
894 * and only the new extended controller information event
895 * is used.
896 */
897 hci_sock_set_flag(sk, HCI_MGMT_EXT_INFO_EVENTS);
898 hci_sock_clear_flag(sk, HCI_MGMT_DEV_CLASS_EVENTS);
899 hci_sock_clear_flag(sk, HCI_MGMT_LOCAL_NAME_EVENTS);
900
901 return mgmt_cmd_complete(sk, hdev->id, MGMT_OP_READ_EXT_INFO, 0, &rp,
902 sizeof(rp));
903}
904
905static int ext_info_changed(struct hci_dev *hdev, struct sock *skip)
906{
907 struct mgmt_ev_ext_info_changed ev;
908
909 ev.eir_len = cpu_to_le16(0);
910
911 return mgmt_limited_event(MGMT_EV_EXT_INFO_CHANGED, hdev, &ev,
912 sizeof(ev), HCI_MGMT_EXT_INFO_EVENTS, skip);
913}
914
865static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev) 915static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
866{ 916{
867 __le32 settings = cpu_to_le32(get_current_settings(hdev)); 917 __le32 settings = cpu_to_le32(get_current_settings(hdev));
@@ -2995,6 +3045,7 @@ static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
2995 3045
2996 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, 3046 err = mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data,
2997 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk); 3047 len, HCI_MGMT_LOCAL_NAME_EVENTS, sk);
3048 ext_info_changed(hdev, sk);
2998 3049
2999 goto failed; 3050 goto failed;
3000 } 3051 }
@@ -6356,6 +6407,8 @@ static const struct hci_mgmt_handler mgmt_handlers[] = {
6356 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE }, 6407 { remove_advertising, MGMT_REMOVE_ADVERTISING_SIZE },
6357 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE }, 6408 { get_adv_size_info, MGMT_GET_ADV_SIZE_INFO_SIZE },
6358 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE }, 6409 { start_limited_discovery, MGMT_START_DISCOVERY_SIZE },
6410 { read_ext_controller_info,MGMT_READ_EXT_INFO_SIZE,
6411 HCI_MGMT_UNTRUSTED },
6359}; 6412};
6360 6413
6361void mgmt_index_added(struct hci_dev *hdev) 6414void mgmt_index_added(struct hci_dev *hdev)
@@ -6494,10 +6547,12 @@ void __mgmt_power_off(struct hci_dev *hdev)
6494 6547
6495 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status); 6548 mgmt_pending_foreach(0, hdev, cmd_complete_rsp, &status);
6496 6549
6497 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) 6550 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0) {
6498 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, 6551 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
6499 zero_cod, sizeof(zero_cod), 6552 zero_cod, sizeof(zero_cod),
6500 HCI_MGMT_DEV_CLASS_EVENTS, NULL); 6553 HCI_MGMT_DEV_CLASS_EVENTS, NULL);
6554 ext_info_changed(hdev, NULL);
6555 }
6501 6556
6502 new_settings(hdev, match.sk); 6557 new_settings(hdev, match.sk);
6503 6558
@@ -7093,9 +7148,11 @@ void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
7093 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match); 7148 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
7094 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match); 7149 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
7095 7150
7096 if (!status) 7151 if (!status) {
7097 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 7152 mgmt_limited_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
7098 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL); 7153 3, HCI_MGMT_DEV_CLASS_EVENTS, NULL);
7154 ext_info_changed(hdev, NULL);
7155 }
7099 7156
7100 if (match.sk) 7157 if (match.sk)
7101 sock_put(match.sk); 7158 sock_put(match.sk);
@@ -7126,6 +7183,7 @@ void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
7126 7183
7127 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev), 7184 mgmt_limited_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
7128 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL); 7185 HCI_MGMT_LOCAL_NAME_EVENTS, cmd ? cmd->sk : NULL);
7186 ext_info_changed(hdev, cmd ? cmd->sk : NULL);
7129} 7187}
7130 7188
7131static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16]) 7189static inline bool has_uuid(u8 *uuid, u16 uuid_count, u8 (*uuids)[16])