1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) 2021 Intel Corporation
4  */
5 
6 #include <net/bluetooth/bluetooth.h>
7 #include <net/bluetooth/hci_core.h>
8 
9 #include "aosp.h"
10 
11 /* Command complete parameters of LE_Get_Vendor_Capabilities_Command
12  * The parameters grow over time. The base version that declares the
13  * version_supported field is v0.95. Refer to
14  * https://cs.android.com/android/platform/superproject/+/master:system/
15  *         bt/gd/hci/controller.cc;l=452?q=le_get_vendor_capabilities_handler
16  */
17 struct aosp_rp_le_get_vendor_capa {
18 	/* v0.95: 15 octets */
19 	__u8	status;
20 	__u8	max_advt_instances;
21 	__u8	offloaded_resolution_of_private_address;
22 	__le16	total_scan_results_storage;
23 	__u8	max_irk_list_sz;
24 	__u8	filtering_support;
25 	__u8	max_filter;
26 	__u8	activity_energy_info_support;
27 	__le16	version_supported;
28 	__le16	total_num_of_advt_tracked;
29 	__u8	extended_scan_support;
30 	__u8	debug_logging_supported;
31 	/* v0.96: 16 octets */
32 	__u8	le_address_generation_offloading_support;
33 	/* v0.98: 21 octets */
34 	__le32	a2dp_source_offload_capability_mask;
35 	__u8	bluetooth_quality_report_support;
36 	/* v1.00: 25 octets */
37 	__le32	dynamic_audio_buffer_support;
38 } __packed;
39 
40 #define VENDOR_CAPA_BASE_SIZE		15
41 #define VENDOR_CAPA_0_98_SIZE		21
42 
aosp_do_open(struct hci_dev * hdev)43 void aosp_do_open(struct hci_dev *hdev)
44 {
45 	struct sk_buff *skb;
46 	struct aosp_rp_le_get_vendor_capa *rp;
47 	u16 version_supported;
48 
49 	if (!hdev->aosp_capable)
50 		return;
51 
52 	bt_dev_dbg(hdev, "Initialize AOSP extension");
53 
54 	/* LE Get Vendor Capabilities Command */
55 	skb = __hci_cmd_sync(hdev, hci_opcode_pack(0x3f, 0x153), 0, NULL,
56 			     HCI_CMD_TIMEOUT);
57 	if (IS_ERR_OR_NULL(skb)) {
58 		if (!skb)
59 			skb = ERR_PTR(-EIO);
60 
61 		bt_dev_err(hdev, "AOSP get vendor capabilities (%ld)",
62 			   PTR_ERR(skb));
63 		return;
64 	}
65 
66 	/* A basic length check */
67 	if (skb->len < VENDOR_CAPA_BASE_SIZE)
68 		goto length_error;
69 
70 	rp = (struct aosp_rp_le_get_vendor_capa *)skb->data;
71 
72 	version_supported = le16_to_cpu(rp->version_supported);
73 	/* AOSP displays the verion number like v0.98, v1.00, etc. */
74 	bt_dev_info(hdev, "AOSP extensions version v%u.%02u",
75 		    version_supported >> 8, version_supported & 0xff);
76 
77 	/* Do not support very old versions. */
78 	if (version_supported < 95) {
79 		bt_dev_warn(hdev, "AOSP capabilities version %u too old",
80 			    version_supported);
81 		goto done;
82 	}
83 
84 	if (version_supported < 98) {
85 		bt_dev_warn(hdev, "AOSP quality report is not supported");
86 		goto done;
87 	}
88 
89 	if (skb->len < VENDOR_CAPA_0_98_SIZE)
90 		goto length_error;
91 
92 	/* The bluetooth_quality_report_support is defined at version
93 	 * v0.98. Refer to
94 	 * https://cs.android.com/android/platform/superproject/+/
95 	 *         master:system/bt/gd/hci/controller.cc;l=477
96 	 */
97 	if (rp->bluetooth_quality_report_support) {
98 		hdev->aosp_quality_report = true;
99 		bt_dev_info(hdev, "AOSP quality report is supported");
100 	}
101 
102 	goto done;
103 
104 length_error:
105 	bt_dev_err(hdev, "AOSP capabilities length %d too short", skb->len);
106 
107 done:
108 	kfree_skb(skb);
109 }
110 
aosp_do_close(struct hci_dev * hdev)111 void aosp_do_close(struct hci_dev *hdev)
112 {
113 	if (!hdev->aosp_capable)
114 		return;
115 
116 	bt_dev_dbg(hdev, "Cleanup of AOSP extension");
117 }
118 
119 /* BQR command */
120 #define BQR_OPCODE			hci_opcode_pack(0x3f, 0x015e)
121 
122 /* BQR report action */
123 #define REPORT_ACTION_ADD		0x00
124 #define REPORT_ACTION_DELETE		0x01
125 #define REPORT_ACTION_CLEAR		0x02
126 
127 /* BQR event masks */
128 #define QUALITY_MONITORING		BIT(0)
129 #define APPRAOCHING_LSTO		BIT(1)
130 #define A2DP_AUDIO_CHOPPY		BIT(2)
131 #define SCO_VOICE_CHOPPY		BIT(3)
132 
133 #define DEFAULT_BQR_EVENT_MASK	(QUALITY_MONITORING | APPRAOCHING_LSTO | \
134 				 A2DP_AUDIO_CHOPPY | SCO_VOICE_CHOPPY)
135 
136 /* Reporting at milliseconds so as not to stress the controller too much.
137  * Range: 0 ~ 65535 ms
138  */
139 #define DEFALUT_REPORT_INTERVAL_MS	5000
140 
141 struct aosp_bqr_cp {
142 	__u8	report_action;
143 	__u32	event_mask;
144 	__u16	min_report_interval;
145 } __packed;
146 
enable_quality_report(struct hci_dev * hdev)147 static int enable_quality_report(struct hci_dev *hdev)
148 {
149 	struct sk_buff *skb;
150 	struct aosp_bqr_cp cp;
151 
152 	cp.report_action = REPORT_ACTION_ADD;
153 	cp.event_mask = DEFAULT_BQR_EVENT_MASK;
154 	cp.min_report_interval = DEFALUT_REPORT_INTERVAL_MS;
155 
156 	skb = __hci_cmd_sync(hdev, BQR_OPCODE, sizeof(cp), &cp,
157 			     HCI_CMD_TIMEOUT);
158 	if (IS_ERR_OR_NULL(skb)) {
159 		if (!skb)
160 			skb = ERR_PTR(-EIO);
161 
162 		bt_dev_err(hdev, "Enabling Android BQR failed (%ld)",
163 			   PTR_ERR(skb));
164 		return PTR_ERR(skb);
165 	}
166 
167 	kfree_skb(skb);
168 	return 0;
169 }
170 
disable_quality_report(struct hci_dev * hdev)171 static int disable_quality_report(struct hci_dev *hdev)
172 {
173 	struct sk_buff *skb;
174 	struct aosp_bqr_cp cp = { 0 };
175 
176 	cp.report_action = REPORT_ACTION_CLEAR;
177 
178 	skb = __hci_cmd_sync(hdev, BQR_OPCODE, sizeof(cp), &cp,
179 			     HCI_CMD_TIMEOUT);
180 	if (IS_ERR_OR_NULL(skb)) {
181 		if (!skb)
182 			skb = ERR_PTR(-EIO);
183 
184 		bt_dev_err(hdev, "Disabling Android BQR failed (%ld)",
185 			   PTR_ERR(skb));
186 		return PTR_ERR(skb);
187 	}
188 
189 	kfree_skb(skb);
190 	return 0;
191 }
192 
aosp_has_quality_report(struct hci_dev * hdev)193 bool aosp_has_quality_report(struct hci_dev *hdev)
194 {
195 	return hdev->aosp_quality_report;
196 }
197 
aosp_set_quality_report(struct hci_dev * hdev,bool enable)198 int aosp_set_quality_report(struct hci_dev *hdev, bool enable)
199 {
200 	if (!aosp_has_quality_report(hdev))
201 		return -EOPNOTSUPP;
202 
203 	bt_dev_dbg(hdev, "quality report enable %d", enable);
204 
205 	/* Enable or disable the quality report feature. */
206 	if (enable)
207 		return enable_quality_report(hdev);
208 	else
209 		return disable_quality_report(hdev);
210 }
211