1 /*
2  * Copyright 2020 HIMSA II K/S - www.himsa.com.
3  * Represented by EHIMA - www.ehima.com
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <bluetooth/log.h>
19 
20 #include <map>
21 #include <vector>
22 
23 #include "bta_gatt_api.h"
24 #include "bta_gatt_queue.h"
25 #include "devices.h"
26 #include "gatt_api.h"
27 #include "internal_include/bt_trace.h"
28 #include "os/log.h"
29 #include "os/logging/log_adapter.h"
30 #include "stack/btm/btm_sec.h"
31 #include "stack/include/bt_types.h"
32 #include "types/bluetooth/uuid.h"
33 
34 using namespace bluetooth::vc::internal;
35 
DeregisterNotifications(tGATT_IF gatt_if)36 void VolumeControlDevice::DeregisterNotifications(tGATT_IF gatt_if) {
37   if (volume_state_handle != 0)
38     BTA_GATTC_DeregisterForNotifications(gatt_if, address, volume_state_handle);
39 
40   if (volume_flags_handle != 0)
41     BTA_GATTC_DeregisterForNotifications(gatt_if, address, volume_flags_handle);
42 
43   for (const VolumeOffset& of : audio_offsets.volume_offsets) {
44     BTA_GATTC_DeregisterForNotifications(gatt_if, address,
45                                          of.audio_descr_handle);
46     BTA_GATTC_DeregisterForNotifications(gatt_if, address,
47                                          of.audio_location_handle);
48     BTA_GATTC_DeregisterForNotifications(gatt_if, address, of.state_handle);
49   }
50 }
51 
Disconnect(tGATT_IF gatt_if)52 void VolumeControlDevice::Disconnect(tGATT_IF gatt_if) {
53   log::info("{}", address);
54 
55   if (IsConnected()) {
56     DeregisterNotifications(gatt_if);
57     BtaGattQueue::Clean(connection_id);
58     BTA_GATTC_Close(connection_id);
59     connection_id = GATT_INVALID_CONN_ID;
60   }
61 
62   device_ready = false;
63   handles_pending.clear();
64 }
65 
66 /*
67  * Find the handle for the client characteristics configuration of a given
68  * characteristics
69  */
find_ccc_handle(uint16_t chrc_handle)70 uint16_t VolumeControlDevice::find_ccc_handle(uint16_t chrc_handle) {
71   const gatt::Characteristic* p_char =
72       BTA_GATTC_GetCharacteristic(connection_id, chrc_handle);
73   if (!p_char) {
74     log::warn("no such handle=0x{:x}", chrc_handle);
75     return 0;
76   }
77 
78   for (const gatt::Descriptor& desc : p_char->descriptors) {
79     if (desc.uuid == Uuid::From16Bit(GATT_UUID_CHAR_CLIENT_CONFIG))
80       return desc.handle;
81   }
82 
83   return 0;
84 }
85 
set_volume_control_service_handles(const gatt::Service & service)86 bool VolumeControlDevice::set_volume_control_service_handles(
87     const gatt::Service& service) {
88   uint16_t state_handle = 0, state_ccc_handle = 0, control_point_handle = 0,
89            flags_handle = 0, flags_ccc_handle = 0;
90 
91   for (const gatt::Characteristic& chrc : service.characteristics) {
92     if (chrc.uuid == kVolumeControlStateUuid) {
93       state_handle = chrc.value_handle;
94       state_ccc_handle = find_ccc_handle(chrc.value_handle);
95     } else if (chrc.uuid == kVolumeControlPointUuid) {
96       control_point_handle = chrc.value_handle;
97     } else if (chrc.uuid == kVolumeFlagsUuid) {
98       flags_handle = chrc.value_handle;
99       flags_ccc_handle = find_ccc_handle(chrc.value_handle);
100     } else {
101       log::warn("unknown characteristic={}", chrc.uuid);
102     }
103   }
104 
105   // Validate service handles
106   if (GATT_HANDLE_IS_VALID(state_handle) &&
107       GATT_HANDLE_IS_VALID(state_ccc_handle) &&
108       GATT_HANDLE_IS_VALID(control_point_handle) &&
109       GATT_HANDLE_IS_VALID(flags_handle)
110       /* volume_flags_ccc_handle is optional */) {
111     volume_state_handle = state_handle;
112     volume_state_ccc_handle = state_ccc_handle;
113     volume_control_point_handle = control_point_handle;
114     volume_flags_handle = flags_handle;
115     volume_flags_ccc_handle = flags_ccc_handle;
116     return true;
117   }
118 
119   return false;
120 }
121 
set_volume_offset_control_service_handles(const gatt::Service & service)122 void VolumeControlDevice::set_volume_offset_control_service_handles(
123     const gatt::Service& service) {
124   VolumeOffset offset = VolumeOffset(service.handle);
125 
126   for (const gatt::Characteristic& chrc : service.characteristics) {
127     if (chrc.uuid == kVolumeOffsetStateUuid) {
128       offset.state_handle = chrc.value_handle;
129       offset.state_ccc_handle = find_ccc_handle(chrc.value_handle);
130 
131     } else if (chrc.uuid == kVolumeOffsetLocationUuid) {
132       offset.audio_location_handle = chrc.value_handle;
133       offset.audio_location_ccc_handle = find_ccc_handle(chrc.value_handle);
134       offset.audio_location_writable =
135           chrc.properties & GATT_CHAR_PROP_BIT_WRITE_NR;
136 
137     } else if (chrc.uuid == kVolumeOffsetControlPointUuid) {
138       offset.control_point_handle = chrc.value_handle;
139 
140     } else if (chrc.uuid == kVolumeOffsetOutputDescriptionUuid) {
141       offset.audio_descr_handle = chrc.value_handle;
142       offset.audio_descr_ccc_handle = find_ccc_handle(chrc.value_handle);
143       offset.audio_descr_writable =
144           chrc.properties & GATT_CHAR_PROP_BIT_WRITE_NR;
145 
146     } else {
147       log::warn("unknown characteristic={}", chrc.uuid);
148     }
149   }
150 
151   // Check if all mandatory attributes are present
152   if (GATT_HANDLE_IS_VALID(offset.state_handle) &&
153       GATT_HANDLE_IS_VALID(offset.state_ccc_handle) &&
154       GATT_HANDLE_IS_VALID(offset.audio_location_handle) &&
155       /* audio_location_ccc_handle is optional */
156       GATT_HANDLE_IS_VALID(offset.control_point_handle) &&
157       GATT_HANDLE_IS_VALID(offset.audio_descr_handle)
158       /* audio_descr_ccc_handle is optional */) {
159     audio_offsets.Add(offset);
160     log::info("Offset added id=0x{:x}", offset.id);
161   } else {
162     log::warn("Ignoring offset handle=0x{:x}", service.handle);
163   }
164 }
165 
UpdateHandles(void)166 bool VolumeControlDevice::UpdateHandles(void) {
167   ResetHandles();
168 
169   bool vcs_found = false;
170   const std::list<gatt::Service>* services =
171       BTA_GATTC_GetServices(connection_id);
172   if (services == nullptr) {
173     log::error("No services found");
174     return false;
175   }
176 
177   for (auto const& service : *services) {
178     if (service.uuid == kVolumeControlUuid) {
179       log::info("Found VCS, handle=0x{:x}", service.handle);
180       vcs_found = set_volume_control_service_handles(service);
181       if (!vcs_found) break;
182 
183       known_service_handles_ = true;
184       for (auto const& included : service.included_services) {
185         const gatt::Service* service =
186             BTA_GATTC_GetOwningService(connection_id, included.start_handle);
187         if (service == nullptr) continue;
188 
189         if (included.uuid == kVolumeOffsetUuid) {
190           log::info("Found VOCS, handle=0x{:x}", service->handle);
191           set_volume_offset_control_service_handles(*service);
192 
193         } else {
194           log::warn("unknown service={}", service->uuid);
195         }
196       }
197     }
198   }
199 
200   return vcs_found;
201 }
202 
ResetHandles(void)203 void VolumeControlDevice::ResetHandles(void) {
204   known_service_handles_ = false;
205   device_ready = false;
206 
207   // the handles are not valid, so discard pending GATT operations
208   BtaGattQueue::Clean(connection_id);
209 
210   volume_state_handle = 0;
211   volume_state_ccc_handle = 0;
212   volume_control_point_handle = 0;
213   volume_flags_handle = 0;
214   volume_flags_ccc_handle = 0;
215 
216   if (audio_offsets.Size() != 0) audio_offsets.Clear();
217 }
218 
ControlPointOperation(uint8_t opcode,const std::vector<uint8_t> * arg,GATT_WRITE_OP_CB cb,void * cb_data)219 void VolumeControlDevice::ControlPointOperation(uint8_t opcode,
220                                                 const std::vector<uint8_t>* arg,
221                                                 GATT_WRITE_OP_CB cb,
222                                                 void* cb_data) {
223   std::vector<uint8_t> set_value({opcode, change_counter});
224   if (arg != nullptr)
225     set_value.insert(set_value.end(), (*arg).begin(), (*arg).end());
226 
227   BtaGattQueue::WriteCharacteristic(connection_id, volume_control_point_handle,
228                                     set_value, GATT_WRITE, cb, cb_data);
229 }
230 
subscribe_for_notifications(tGATT_IF gatt_if,uint16_t handle,uint16_t ccc_handle,GATT_WRITE_OP_CB cb)231 bool VolumeControlDevice::subscribe_for_notifications(tGATT_IF gatt_if,
232                                                       uint16_t handle,
233                                                       uint16_t ccc_handle,
234                                                       GATT_WRITE_OP_CB cb) {
235   tGATT_STATUS status =
236       BTA_GATTC_RegisterForNotifications(gatt_if, address, handle);
237   if (status != GATT_SUCCESS) {
238     log::error("failed, status=0x{:x}", status);
239     return false;
240   }
241 
242   std::vector<uint8_t> value(2);
243   uint8_t* ptr = value.data();
244   UINT16_TO_STREAM(ptr, GATT_CHAR_CLIENT_CONFIG_NOTIFICATION);
245   BtaGattQueue::WriteDescriptor(connection_id, ccc_handle, std::move(value),
246                                 GATT_WRITE, cb, nullptr);
247 
248   return true;
249 }
250 
251 /**
252  * Enqueue GATT requests that are required by the Volume Control to be
253  * functional. This includes State characteristics read and subscription.
254  * Those characteristics contain the change counter needed to send any request
255  * via Control Point. Once completed successfully, the device can be stored
256  * and reported as connected. In each case we subscribe first to be sure we do
257  * not miss any value change.
258  */
EnqueueInitialRequests(tGATT_IF gatt_if,GATT_READ_OP_CB chrc_read_cb,GATT_WRITE_OP_CB cccd_write_cb)259 bool VolumeControlDevice::EnqueueInitialRequests(
260     tGATT_IF gatt_if, GATT_READ_OP_CB chrc_read_cb,
261     GATT_WRITE_OP_CB cccd_write_cb) {
262   handles_pending.clear();
263   handles_pending.insert(volume_state_handle);
264   handles_pending.insert(volume_state_ccc_handle);
265   if (!subscribe_for_notifications(gatt_if, volume_state_handle,
266                                    volume_state_ccc_handle, cccd_write_cb)) {
267     return false;
268   }
269 
270   for (auto const& offset : audio_offsets.volume_offsets) {
271     handles_pending.insert(offset.state_handle);
272     handles_pending.insert(offset.state_ccc_handle);
273     if (!subscribe_for_notifications(gatt_if, offset.state_handle,
274                                      offset.state_ccc_handle, cccd_write_cb)) {
275       return false;
276     }
277 
278     BtaGattQueue::ReadCharacteristic(connection_id, offset.state_handle,
279                                      chrc_read_cb, nullptr);
280   }
281 
282   BtaGattQueue::ReadCharacteristic(connection_id, volume_state_handle,
283                                    chrc_read_cb, nullptr);
284 
285   return true;
286 }
287 
288 /**
289  * Enqueue the remaining requests. Those are not so crucial and can be done
290  * once Volume Control instance indicates it's readiness to profile.
291  * This includes characteristics read and subscription.
292  * In each case we subscribe first to be sure we do not miss any value change.
293  */
EnqueueRemainingRequests(tGATT_IF gatt_if,GATT_READ_OP_CB chrc_read_cb,GATT_WRITE_OP_CB cccd_write_cb)294 void VolumeControlDevice::EnqueueRemainingRequests(
295     tGATT_IF gatt_if, GATT_READ_OP_CB chrc_read_cb,
296     GATT_WRITE_OP_CB cccd_write_cb) {
297   std::map<uint16_t, uint16_t> handle_pairs{
298       {volume_flags_handle, volume_flags_ccc_handle},
299   };
300 
301   for (auto const& offset : audio_offsets.volume_offsets) {
302     handle_pairs[offset.audio_location_handle] =
303         offset.audio_location_ccc_handle;
304     handle_pairs[offset.audio_descr_handle] = offset.audio_descr_ccc_handle;
305   }
306 
307   for (auto const& handles : handle_pairs) {
308     if (GATT_HANDLE_IS_VALID(handles.second)) {
309       subscribe_for_notifications(gatt_if, handles.first, handles.second,
310                                   cccd_write_cb);
311     }
312 
313     BtaGattQueue::ReadCharacteristic(connection_id, handles.first, chrc_read_cb,
314                                      nullptr);
315   }
316 }
317 
VerifyReady(uint16_t handle)318 bool VolumeControlDevice::VerifyReady(uint16_t handle) {
319   handles_pending.erase(handle);
320   device_ready = handles_pending.size() == 0;
321   return device_ready;
322 }
323 
GetExtAudioOutVolumeOffset(uint8_t ext_output_id,GATT_READ_OP_CB cb,void * cb_data)324 void VolumeControlDevice::GetExtAudioOutVolumeOffset(uint8_t ext_output_id,
325                                                      GATT_READ_OP_CB cb,
326                                                      void* cb_data) {
327   VolumeOffset* offset = audio_offsets.FindById(ext_output_id);
328   if (!offset) {
329     log::error("no such offset!");
330     return;
331   }
332 
333   BtaGattQueue::ReadCharacteristic(connection_id, offset->state_handle, cb,
334                                    cb_data);
335 }
336 
GetExtAudioOutLocation(uint8_t ext_output_id,GATT_READ_OP_CB cb,void * cb_data)337 void VolumeControlDevice::GetExtAudioOutLocation(uint8_t ext_output_id,
338                                                  GATT_READ_OP_CB cb,
339                                                  void* cb_data) {
340   VolumeOffset* offset = audio_offsets.FindById(ext_output_id);
341   if (!offset) {
342     log::error("no such offset!");
343     return;
344   }
345 
346   BtaGattQueue::ReadCharacteristic(connection_id, offset->audio_location_handle,
347                                    cb, cb_data);
348 }
349 
SetExtAudioOutLocation(uint8_t ext_output_id,uint32_t location)350 void VolumeControlDevice::SetExtAudioOutLocation(uint8_t ext_output_id,
351                                                  uint32_t location) {
352   VolumeOffset* offset = audio_offsets.FindById(ext_output_id);
353   if (!offset) {
354     log::error("no such offset!");
355     return;
356   }
357 
358   if (!offset->audio_location_writable) {
359     log::warn("not writable");
360     return;
361   }
362 
363   std::vector<uint8_t> value(4);
364   uint8_t* ptr = value.data();
365   UINT32_TO_STREAM(ptr, location);
366   BtaGattQueue::WriteCharacteristic(connection_id,
367                                     offset->audio_location_handle, value,
368                                     GATT_WRITE_NO_RSP, nullptr, nullptr);
369 }
370 
GetExtAudioOutDescription(uint8_t ext_output_id,GATT_READ_OP_CB cb,void * cb_data)371 void VolumeControlDevice::GetExtAudioOutDescription(uint8_t ext_output_id,
372                                                     GATT_READ_OP_CB cb,
373                                                     void* cb_data) {
374   VolumeOffset* offset = audio_offsets.FindById(ext_output_id);
375   if (!offset) {
376     log::error("no such offset!");
377     return;
378   }
379 
380   BtaGattQueue::ReadCharacteristic(connection_id, offset->audio_descr_handle,
381                                    cb, cb_data);
382 }
383 
SetExtAudioOutDescription(uint8_t ext_output_id,std::string & descr)384 void VolumeControlDevice::SetExtAudioOutDescription(uint8_t ext_output_id,
385                                                     std::string& descr) {
386   VolumeOffset* offset = audio_offsets.FindById(ext_output_id);
387   if (!offset) {
388     log::error("no such offset!");
389     return;
390   }
391 
392   if (!offset->audio_descr_writable) {
393     log::warn("not writable");
394     return;
395   }
396 
397   std::vector<uint8_t> value(descr.begin(), descr.end());
398   BtaGattQueue::WriteCharacteristic(connection_id, offset->audio_descr_handle,
399                                     value, GATT_WRITE_NO_RSP, nullptr, nullptr);
400 }
401 
ExtAudioOutControlPointOperation(uint8_t ext_output_id,uint8_t opcode,const std::vector<uint8_t> * arg,GATT_WRITE_OP_CB cb,void * cb_data)402 void VolumeControlDevice::ExtAudioOutControlPointOperation(
403     uint8_t ext_output_id, uint8_t opcode, const std::vector<uint8_t>* arg,
404     GATT_WRITE_OP_CB cb, void* cb_data) {
405   VolumeOffset* offset = audio_offsets.FindById(ext_output_id);
406   if (!offset) {
407     log::error("no such offset!");
408     return;
409   }
410 
411   std::vector<uint8_t> set_value({opcode, offset->change_counter});
412   if (arg != nullptr)
413     set_value.insert(set_value.end(), (*arg).begin(), (*arg).end());
414 
415   BtaGattQueue::WriteCharacteristic(connection_id, offset->control_point_handle,
416                                     set_value, GATT_WRITE, cb, cb_data);
417 }
418 
IsEncryptionEnabled()419 bool VolumeControlDevice::IsEncryptionEnabled() {
420   return BTM_IsEncrypted(address, BT_TRANSPORT_LE);
421 }
422 
EnableEncryption()423 bool VolumeControlDevice::EnableEncryption() {
424   int result = BTM_SetEncryption(address, BT_TRANSPORT_LE, nullptr, nullptr,
425                                  BTM_BLE_SEC_ENCRYPT);
426   log::info("{}: result=0x{:02x}", address, result);
427 
428   return result != BTM_ERR_KEY_MISSING;
429 }
430