blob: cfc394c341865900186b584de38639c8a0cfac13 [file] [log] [blame]
Arman Uguray0f2d4892015-09-22 14:20:42 -07001//
Jakub Pawlowski5b790fe2017-09-18 09:00:20 -07002// Copyright 2015 Google, Inc.
Arman Uguray0f2d4892015-09-22 14:20:42 -07003//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#define LOG_TAG "bt_gatts"
18
19#include "gatt_server_old.h"
20
21#include <stdio.h>
22#include <stdlib.h>
23#include <unistd.h>
24
Jakub Pawlowskia8d73ef2016-10-31 11:15:20 -070025#include <base/bind.h>
Jakub Pawlowski67f5f372018-07-23 10:00:25 -070026#include <base/bind_helpers.h>
27#include <base/callback.h>
Arman Uguray0f2d4892015-09-22 14:20:42 -070028#include <algorithm>
29#include <array>
30#include <condition_variable>
31#include <map>
32#include <memory>
33#include <mutex>
34#include <set>
35#include <string>
36#include <unordered_map>
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -070037#include <unordered_set>
Arman Uguray0f2d4892015-09-22 14:20:42 -070038#include <vector>
39
40#include <hardware/bluetooth.h>
41#include <hardware/bt_gatt.h>
42
43#include "service/hal/bluetooth_interface.h"
44#include "service/logging_helpers.h"
Arman Uguray0f2d4892015-09-22 14:20:42 -070045
Arman Uguray0f2d4892015-09-22 14:20:42 -070046#include "osi/include/log.h"
47#include "osi/include/osi.h"
Arman Uguray0f2d4892015-09-22 14:20:42 -070048
49namespace {
50
51const size_t kMaxGattAttributeSize = 512;
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -070052std::vector<btgatt_db_element_t> pending_svc_decl;
53std::unordered_set<int> blob_index;
Arman Uguray0f2d4892015-09-22 14:20:42 -070054
55// TODO(icoolidge): Support multiple instances
56// TODO(armansito): Remove this variable. No point of having this if
57// each bluetooth::gatt::Server instance already keeps a pointer to the
58// ServerInternals that is associated with it (which is much cleaner). It looks
59// like this variable exists because the btif callbacks don't allow the
60// upper-layer to pass user data to them. We could:
61//
62// 1. Fix the btif callbacks so that some sort of continuation can be
63// attached to a callback. This might be a long shot since the callback
64// interface doesn't allow more than one caller to register its own callbacks
65// (which might be what we want though, since this would make the API more
66// flexible).
67//
68// 2. Allow creation of Server objects using a factory method that returns
69// the result asynchronously in a base::Callback. The RegisterServerCallback
70// provides an |app_uuid|, which can be used to store callback structures in
71// a map and lazily instantiate the Server and invoke the correct callback.
72// This is a general pattern that we should use throughout the daemon, since
73// all operations can timeout or fail and this is best reported in an
74// asynchronous base::Callback.
75//
Myles Watson911d1ae2016-11-28 16:44:40 -080076static bluetooth::gatt::ServerInternals* g_internal = nullptr;
Arman Uguray0f2d4892015-09-22 14:20:42 -070077
78enum { kPipeReadEnd = 0, kPipeWriteEnd = 1, kPipeNumEnds = 2 };
79
80} // namespace
81
82namespace bluetooth {
83namespace gatt {
84
85struct Characteristic {
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -070086 Uuid uuid;
Arman Uguray0f2d4892015-09-22 14:20:42 -070087 int blob_section;
88 std::vector<uint8_t> blob;
89
90 // Support synchronized blob updates by latching under mutex.
91 std::vector<uint8_t> next_blob;
92 bool next_blob_pending;
93 bool notify;
94};
95
96struct ServerInternals {
97 ServerInternals();
98 ~ServerInternals();
99 int Initialize();
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700100 bt_status_t AddCharacteristic(const Uuid& uuid, uint8_t properties,
Myles Watson911d1ae2016-11-28 16:44:40 -0800101 uint16_t permissions);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700102
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700103 // This maps API attribute Uuids to BlueDroid handles.
104 std::map<Uuid, int> uuid_to_attribute;
Arman Uguray0f2d4892015-09-22 14:20:42 -0700105
106 // The attribute cache, indexed by BlueDroid handles.
107 std::unordered_map<int, Characteristic> characteristics;
108
109 // Associate a control attribute with its value attribute.
110 std::unordered_map<int, int> controlled_blobs;
111
112 ScanResults scan_results;
113
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700114 Uuid last_write;
Myles Watson911d1ae2016-11-28 16:44:40 -0800115 const btgatt_interface_t* gatt;
Arman Uguray0f2d4892015-09-22 14:20:42 -0700116 int server_if;
117 int client_if;
118 int service_handle;
Arman Uguray0f2d4892015-09-22 14:20:42 -0700119 std::set<int> connections;
120
121 std::mutex lock;
122 std::condition_variable api_synchronize;
123 int pipefd[kPipeNumEnds];
124};
125
126} // namespace gatt
127} // namespace bluetooth
128
129namespace {
130
131/** Callback invoked in response to register_server */
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700132void RegisterServerCallback(int status, int server_if,
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700133 const bluetooth::Uuid& app_uuid) {
Arman Uguray0f2d4892015-09-22 14:20:42 -0700134 LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d app_uuid:%p", __func__, status,
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700135 server_if, &app_uuid);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700136
137 g_internal->server_if = server_if;
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700138
Nick Desaulniers7ee58352019-10-09 11:06:55 -0700139 pending_svc_decl.push_back({
140 .uuid = app_uuid,
141 .type = BTGATT_DB_PRIMARY_SERVICE,
142 });
Arman Uguray0f2d4892015-09-22 14:20:42 -0700143}
144
Myles Watson911d1ae2016-11-28 16:44:40 -0800145void ServiceAddedCallback(int status, int server_if,
Pavlin Radoslavovb324a8d2016-12-09 17:50:59 -0800146 std::vector<btgatt_db_element_t> service) {
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700147 LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d count:%zu svc_handle:%d",
Myles Watson911d1ae2016-11-28 16:44:40 -0800148 __func__, status, server_if, service.size(),
149 service[0].attribute_handle);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700150
151 std::lock_guard<std::mutex> lock(g_internal->lock);
152 g_internal->server_if = server_if;
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700153
154 g_internal->service_handle = service[0].attribute_handle;
155
156 uint16_t prev_char_handle = 0;
157 uint16_t prev_char_properties = 0;
Myles Watson911d1ae2016-11-28 16:44:40 -0800158 for (size_t i = 1; i < service.size(); i++) {
159 const btgatt_db_element_t& el = service[i];
Jakub Pawlowskiaeafd392016-09-19 10:38:20 -0700160 if (el.type == BTGATT_DB_DESCRIPTOR) {
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700161 LOG_INFO(LOG_TAG, "%s: descr_handle:%d", __func__, el.attribute_handle);
162 } else if (el.type == BTGATT_DB_CHARACTERISTIC) {
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700163 bluetooth::Uuid id(el.uuid);
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700164 uint16_t char_handle = el.attribute_handle;
165
166 LOG_INFO(LOG_TAG, "%s: char_handle:%d", __func__, char_handle);
167
168 g_internal->uuid_to_attribute[id] = char_handle;
169 g_internal->characteristics[char_handle].uuid = id;
170 g_internal->characteristics[char_handle].blob_section = 0;
171
172 // If the added characteristic is blob
173 if (blob_index.find(i) != blob_index.end()) {
174 // Finally, associate the control attribute with the value attribute.
175 // Also, initialize the control attribute to a readable zero.
176 const uint16_t control_attribute = char_handle;
177 const uint16_t blob_attribute = prev_char_handle;
178 g_internal->controlled_blobs[control_attribute] = blob_attribute;
179 g_internal->characteristics[blob_attribute].notify =
180 prev_char_properties & bluetooth::gatt::kPropertyNotify;
181
Myles Watson911d1ae2016-11-28 16:44:40 -0800182 bluetooth::gatt::Characteristic& ctrl =
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700183 g_internal->characteristics[control_attribute];
184 ctrl.next_blob.clear();
185 ctrl.next_blob.push_back(0);
186 ctrl.next_blob_pending = true;
187 ctrl.blob_section = 0;
188 ctrl.notify = false;
189 }
190 prev_char_handle = char_handle;
191 prev_char_properties = el.properties;
192 }
193 }
194
195 pending_svc_decl.clear();
196 blob_index.clear();
197
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700198 // The Uuid provided here is unimportant, and is only used to satisfy
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700199 // BlueDroid.
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700200 // It must be different than any other registered Uuid.
201 bluetooth::Uuid client_id = bluetooth::Uuid::GetRandom();
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700202
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700203 bt_status_t btstat = g_internal->gatt->client->register_client(client_id);
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700204 if (btstat != BT_STATUS_SUCCESS) {
205 LOG_ERROR(LOG_TAG, "%s: Failed to register client", __func__);
206 }
Arman Uguray0f2d4892015-09-22 14:20:42 -0700207}
208
Jakub Pawlowskia484a882017-06-24 17:30:18 -0700209void RequestReadCallback(int conn_id, int trans_id, const RawAddress& bda,
Arman Uguray0f2d4892015-09-22 14:20:42 -0700210 int attr_handle, int attribute_offset_octets,
211 bool is_long) {
212 std::lock_guard<std::mutex> lock(g_internal->lock);
213
Myles Watson911d1ae2016-11-28 16:44:40 -0800214 bluetooth::gatt::Characteristic& ch =
215 g_internal->characteristics[attr_handle];
Arman Uguray0f2d4892015-09-22 14:20:42 -0700216
217 // Latch next_blob to blob on a 'fresh' read.
218 if (ch.next_blob_pending && attribute_offset_octets == 0 &&
219 ch.blob_section == 0) {
220 std::swap(ch.blob, ch.next_blob);
221 ch.next_blob_pending = false;
222 }
223
224 const size_t blob_offset_octets =
225 std::min(ch.blob.size(), ch.blob_section * kMaxGattAttributeSize);
226 const size_t blob_remaining = ch.blob.size() - blob_offset_octets;
227 const size_t attribute_size = std::min(kMaxGattAttributeSize, blob_remaining);
228
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700229 std::string addr(BtAddrString(&bda));
Arman Uguray0f2d4892015-09-22 14:20:42 -0700230 LOG_INFO(LOG_TAG,
Myles Watson911d1ae2016-11-28 16:44:40 -0800231 "%s: connection:%d (%s) reading attr:%d attribute_offset_octets:%d "
232 "blob_section:%u (is_long:%u)",
233 __func__, conn_id, addr.c_str(), attr_handle,
234 attribute_offset_octets, ch.blob_section, is_long);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700235
236 btgatt_response_t response;
237 response.attr_value.len = 0;
238
239 if (attribute_offset_octets < static_cast<int>(attribute_size)) {
240 std::copy(ch.blob.begin() + blob_offset_octets + attribute_offset_octets,
241 ch.blob.begin() + blob_offset_octets + attribute_size,
242 response.attr_value.value);
243 response.attr_value.len = attribute_size - attribute_offset_octets;
244 }
245
246 response.attr_value.handle = attr_handle;
247 response.attr_value.offset = attribute_offset_octets;
248 response.attr_value.auth_req = 0;
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700249 g_internal->gatt->server->send_response(conn_id, trans_id, 0, response);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700250}
251
Jakub Pawlowskia484a882017-06-24 17:30:18 -0700252void RequestWriteCallback(int conn_id, int trans_id, const RawAddress& bda,
Myles Watson911d1ae2016-11-28 16:44:40 -0800253 int attr_handle, int attribute_offset, bool need_rsp,
Pavlin Radoslavovb324a8d2016-12-09 17:50:59 -0800254 bool is_prep, std::vector<uint8_t> value) {
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700255 std::string addr(BtAddrString(&bda));
Arman Uguray0f2d4892015-09-22 14:20:42 -0700256 LOG_INFO(LOG_TAG,
Myles Watson911d1ae2016-11-28 16:44:40 -0800257 "%s: connection:%d (%s:trans:%d) write attr:%d attribute_offset:%d "
258 "length:%zu "
259 "need_resp:%u is_prep:%u",
260 __func__, conn_id, addr.c_str(), trans_id, attr_handle,
261 attribute_offset, value.size(), need_rsp, is_prep);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700262
263 std::lock_guard<std::mutex> lock(g_internal->lock);
264
Myles Watson911d1ae2016-11-28 16:44:40 -0800265 bluetooth::gatt::Characteristic& ch =
Arman Uguray0f2d4892015-09-22 14:20:42 -0700266 g_internal->characteristics[attr_handle];
267
Jakub Pawlowski16102de2016-05-31 13:14:13 -0700268 ch.blob.resize(attribute_offset + value.size());
Arman Uguray0f2d4892015-09-22 14:20:42 -0700269
Jakub Pawlowski16102de2016-05-31 13:14:13 -0700270 std::copy(value.begin(), value.end(), ch.blob.begin() + attribute_offset);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700271
272 auto target_blob = g_internal->controlled_blobs.find(attr_handle);
273 // If this is a control attribute, adjust offset of the target blob.
274 if (target_blob != g_internal->controlled_blobs.end() &&
275 ch.blob.size() == 1u) {
276 g_internal->characteristics[target_blob->second].blob_section = ch.blob[0];
277 LOG_INFO(LOG_TAG, "%s: updating attribute %d blob_section to %u", __func__,
Myles Watson911d1ae2016-11-28 16:44:40 -0800278 target_blob->second, ch.blob[0]);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700279 } else if (!is_prep) {
280 // This is a single frame characteristic write.
281 // Notify upwards because we're done now.
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700282 const bluetooth::Uuid::UUID128Bit& attr_uuid = ch.uuid.To128BitBE();
Pavlin Radoslavovd6121a32016-05-12 11:36:44 -0700283 ssize_t status;
284 OSI_NO_INTR(status = write(g_internal->pipefd[kPipeWriteEnd],
285 attr_uuid.data(), attr_uuid.size()));
Arman Uguray0f2d4892015-09-22 14:20:42 -0700286 if (-1 == status)
287 LOG_ERROR(LOG_TAG, "%s: write failed: %s", __func__, strerror(errno));
288 } else {
289 // This is a multi-frame characteristic write.
290 // Wait for an 'RequestExecWriteCallback' to notify completion.
291 g_internal->last_write = ch.uuid;
292 }
293
294 // Respond only if needed.
295 if (!need_rsp) return;
296
297 btgatt_response_t response;
298 response.attr_value.handle = attr_handle;
299 response.attr_value.offset = attribute_offset;
Jakub Pawlowski16102de2016-05-31 13:14:13 -0700300 response.attr_value.len = value.size();
Arman Uguray0f2d4892015-09-22 14:20:42 -0700301 response.attr_value.auth_req = 0;
302 // Provide written data back to sender for the response.
303 // Remote stacks use this to validate the success of the write.
Jakub Pawlowski16102de2016-05-31 13:14:13 -0700304 std::copy(value.begin(), value.end(), response.attr_value.value);
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700305 g_internal->gatt->server->send_response(conn_id, trans_id, 0, response);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700306}
307
Jakub Pawlowskia484a882017-06-24 17:30:18 -0700308void RequestExecWriteCallback(int conn_id, int trans_id, const RawAddress& bda,
Arman Uguray0f2d4892015-09-22 14:20:42 -0700309 int exec_write) {
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700310 std::string addr(BtAddrString(&bda));
Arman Uguray0f2d4892015-09-22 14:20:42 -0700311 LOG_INFO(LOG_TAG, "%s: connection:%d (%s:trans:%d) exec_write:%d", __func__,
Myles Watson911d1ae2016-11-28 16:44:40 -0800312 conn_id, addr.c_str(), trans_id, exec_write);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700313
314 // This 'response' data is unused for ExecWriteResponses.
315 // It is only used to pass BlueDroid argument validation.
316 btgatt_response_t response = {};
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700317 g_internal->gatt->server->send_response(conn_id, trans_id, 0, response);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700318
Myles Watson911d1ae2016-11-28 16:44:40 -0800319 if (!exec_write) return;
Arman Uguray0f2d4892015-09-22 14:20:42 -0700320
321 std::lock_guard<std::mutex> lock(g_internal->lock);
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700322 // Communicate the attribute Uuid as notification of a write update.
323 const bluetooth::Uuid::UUID128Bit uuid = g_internal->last_write.To128BitBE();
Pavlin Radoslavovd6121a32016-05-12 11:36:44 -0700324 ssize_t status;
325 OSI_NO_INTR(status = write(g_internal->pipefd[kPipeWriteEnd], uuid.data(),
326 uuid.size()));
Arman Uguray0f2d4892015-09-22 14:20:42 -0700327 if (-1 == status)
328 LOG_ERROR(LOG_TAG, "%s: write failed: %s", __func__, strerror(errno));
329}
330
331void ConnectionCallback(int conn_id, int server_if, int connected,
Jakub Pawlowskia484a882017-06-24 17:30:18 -0700332 const RawAddress& bda) {
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700333 std::string addr(BtAddrString(&bda));
Arman Uguray0f2d4892015-09-22 14:20:42 -0700334 LOG_INFO(LOG_TAG, "%s: connection:%d server_if:%d connected:%d addr:%s",
Myles Watson911d1ae2016-11-28 16:44:40 -0800335 __func__, conn_id, server_if, connected, addr.c_str());
Arman Uguray0f2d4892015-09-22 14:20:42 -0700336 if (connected == 1) {
337 g_internal->connections.insert(conn_id);
338 } else if (connected == 0) {
339 g_internal->connections.erase(conn_id);
340 }
341}
342
Jakub Pawlowskia8d73ef2016-10-31 11:15:20 -0700343void EnableAdvertisingCallback(uint8_t status) {
344 LOG_INFO(LOG_TAG, "%s: status:%d", __func__, status);
345 // This terminates a Start call.
346 std::lock_guard<std::mutex> lock(g_internal->lock);
347 g_internal->api_synchronize.notify_one();
348}
349
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700350void RegisterClientCallback(int status, int client_if,
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700351 const bluetooth::Uuid& app_uuid) {
352 LOG_INFO(LOG_TAG, "%s: status:%d client_if:%d uuid[0]:%s", __func__, status,
353 client_if, app_uuid.ToString().c_str());
Arman Uguray0f2d4892015-09-22 14:20:42 -0700354 g_internal->client_if = client_if;
355
356 // Setup our advertisement. This has no callback.
Jakub Pawlowskid964cf92016-11-03 15:41:50 -0700357 g_internal->gatt->advertiser->SetData(0 /* std_inst */, false,
358 {/*TODO: put inverval 2,2 here*/},
Jakub Pawlowski67f5f372018-07-23 10:00:25 -0700359 base::DoNothing());
Arman Uguray0f2d4892015-09-22 14:20:42 -0700360
Jakub Pawlowskid964cf92016-11-03 15:41:50 -0700361 g_internal->gatt->advertiser->Enable(
362 0 /* std_inst */, true, base::Bind(&EnableAdvertisingCallback),
Jakub Pawlowski67f5f372018-07-23 10:00:25 -0700363 0 /* no duration */, 0 /* no maxExtAdvEvent*/, base::DoNothing());
Arman Uguray0f2d4892015-09-22 14:20:42 -0700364}
365
Arman Uguray0f2d4892015-09-22 14:20:42 -0700366void ServiceStoppedCallback(int status, int server_if, int srvc_handle) {
367 LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d srvc_handle:%d", __func__,
Myles Watson911d1ae2016-11-28 16:44:40 -0800368 status, server_if, srvc_handle);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700369 // This terminates a Stop call.
370 // TODO(icoolidge): make this symmetric with start
371 std::lock_guard<std::mutex> lock(g_internal->lock);
372 g_internal->api_synchronize.notify_one();
373}
374
Jakub Pawlowski7de0f9b2017-01-27 08:06:20 -0800375void ScanResultCallback(uint16_t ble_evt_type, uint8_t addr_type,
Jakub Pawlowskia484a882017-06-24 17:30:18 -0700376 RawAddress* bda, uint8_t ble_primary_phy,
Jakub Pawlowski7de0f9b2017-01-27 08:06:20 -0800377 uint8_t ble_secondary_phy, uint8_t ble_advertising_sid,
378 int8_t ble_tx_power, int8_t rssi,
379 uint16_t ble_periodic_adv_int,
Pavlin Radoslavovb324a8d2016-12-09 17:50:59 -0800380 std::vector<uint8_t> adv_data) {
Arman Uguray0f2d4892015-09-22 14:20:42 -0700381 std::string addr(BtAddrString(bda));
Arman Uguray0f2d4892015-09-22 14:20:42 -0700382 std::lock_guard<std::mutex> lock(g_internal->lock);
383 g_internal->scan_results[addr] = rssi;
384}
385
386void ClientConnectCallback(int conn_id, int status, int client_if,
Jakub Pawlowskia484a882017-06-24 17:30:18 -0700387 const RawAddress& bda) {
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700388 std::string addr(BtAddrString(&bda));
Arman Uguray0f2d4892015-09-22 14:20:42 -0700389 LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__,
Myles Watson911d1ae2016-11-28 16:44:40 -0800390 conn_id, status, client_if, addr.c_str());
Arman Uguray0f2d4892015-09-22 14:20:42 -0700391}
392
393void ClientDisconnectCallback(int conn_id, int status, int client_if,
Jakub Pawlowskia484a882017-06-24 17:30:18 -0700394 const RawAddress& bda) {
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700395 std::string addr(BtAddrString(&bda));
Arman Uguray0f2d4892015-09-22 14:20:42 -0700396 LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__,
Myles Watson911d1ae2016-11-28 16:44:40 -0800397 conn_id, status, client_if, addr.c_str());
Arman Uguray0f2d4892015-09-22 14:20:42 -0700398}
399
Myles Watson911d1ae2016-11-28 16:44:40 -0800400void IndicationSentCallback(UNUSED_ATTR int conn_id, UNUSED_ATTR int status) {
Arman Uguray0f2d4892015-09-22 14:20:42 -0700401 // TODO(icoolidge): what to do
402}
403
404void ResponseConfirmationCallback(UNUSED_ATTR int status,
405 UNUSED_ATTR int handle) {
406 // TODO(icoolidge): what to do
407}
408
409const btgatt_server_callbacks_t gatt_server_callbacks = {
410 RegisterServerCallback,
411 ConnectionCallback,
412 ServiceAddedCallback,
Arman Uguray0f2d4892015-09-22 14:20:42 -0700413 ServiceStoppedCallback,
414 nullptr, /* service_deleted_cb */
415 RequestReadCallback,
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700416 RequestReadCallback,
417 RequestWriteCallback,
Arman Uguray0f2d4892015-09-22 14:20:42 -0700418 RequestWriteCallback,
419 RequestExecWriteCallback,
420 ResponseConfirmationCallback,
421 IndicationSentCallback,
422 nullptr, /* congestion_cb*/
423 nullptr, /* mtu_changed_cb */
Jakub Pawlowskieafd45d2017-03-22 19:00:47 -0700424 nullptr, /* phy_update_cb */
Jakub Pawlowskib5ba4fd2017-03-23 18:11:04 -0700425 nullptr, /* conn_update_cb */
Arman Uguray0f2d4892015-09-22 14:20:42 -0700426};
427
428// TODO(eisenbach): Refactor GATT interface to not require servers
429// to refer to the client interface.
430const btgatt_client_callbacks_t gatt_client_callbacks = {
431 RegisterClientCallback,
Arman Uguray0f2d4892015-09-22 14:20:42 -0700432 ClientConnectCallback,
433 ClientDisconnectCallback,
434 nullptr, /* search_complete_cb; */
Arman Uguray0f2d4892015-09-22 14:20:42 -0700435 nullptr, /* register_for_notification_cb; */
436 nullptr, /* notify_cb; */
437 nullptr, /* read_characteristic_cb; */
438 nullptr, /* write_characteristic_cb; */
439 nullptr, /* read_descriptor_cb; */
440 nullptr, /* write_descriptor_cb; */
441 nullptr, /* execute_write_cb; */
442 nullptr, /* read_remote_rssi_cb; */
Arman Uguray0f2d4892015-09-22 14:20:42 -0700443 nullptr, /* configure_mtu_cb; */
Arman Uguray0f2d4892015-09-22 14:20:42 -0700444 nullptr, /* congestion_cb; */
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700445 nullptr, /* get_gatt_db_cb; */
446 nullptr, /* services_removed_cb */
447 nullptr, /* services_added_cb */
Jakub Pawlowskieafd45d2017-03-22 19:00:47 -0700448 nullptr, /* phy_update_cb */
Jakub Pawlowskib5ba4fd2017-03-23 18:11:04 -0700449 nullptr, /* conn_update_cb */
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700450};
451
452const btgatt_scanner_callbacks_t gatt_scanner_callbacks = {
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700453 ScanResultCallback,
Arman Uguray0f2d4892015-09-22 14:20:42 -0700454 nullptr, /* batchscan_reports_cb; */
455 nullptr, /* batchscan_threshold_cb; */
456 nullptr, /* track_adv_event_cb; */
Arman Uguray0f2d4892015-09-22 14:20:42 -0700457};
458
459const btgatt_callbacks_t gatt_callbacks = {
460 /** Set to sizeof(btgatt_callbacks_t) */
461 sizeof(btgatt_callbacks_t),
462
463 /** GATT Client callbacks */
464 &gatt_client_callbacks,
465
466 /** GATT Server callbacks */
Jakub Pawlowski67d5a252016-07-13 11:55:16 -0700467 &gatt_server_callbacks,
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700468
469 /** GATT Server callbacks */
470 &gatt_scanner_callbacks,
Jakub Pawlowski67d5a252016-07-13 11:55:16 -0700471};
Arman Uguray0f2d4892015-09-22 14:20:42 -0700472
473} // namespace
474
475namespace bluetooth {
476namespace gatt {
477
478int ServerInternals::Initialize() {
479 // Get the interface to the GATT profile.
480 const bt_interface_t* bt_iface =
481 hal::BluetoothInterface::Get()->GetHALInterface();
Myles Watson911d1ae2016-11-28 16:44:40 -0800482 gatt = reinterpret_cast<const btgatt_interface_t*>(
Arman Uguray0f2d4892015-09-22 14:20:42 -0700483 bt_iface->get_profile_interface(BT_PROFILE_GATT_ID));
484 if (!gatt) {
485 LOG_ERROR(LOG_TAG, "Error getting GATT interface");
486 return -1;
487 }
488
489 bt_status_t btstat = gatt->init(&gatt_callbacks);
490 if (btstat != BT_STATUS_SUCCESS) {
491 LOG_ERROR(LOG_TAG, "Failed to initialize gatt interface");
492 return -1;
493 }
494
495 int status = pipe(pipefd);
496 if (status == -1) {
497 LOG_ERROR(LOG_TAG, "pipe creation failed: %s", strerror(errno));
498 return -1;
499 }
500
501 return 0;
502}
503
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700504bt_status_t ServerInternals::AddCharacteristic(const Uuid& uuid,
Myles Watson911d1ae2016-11-28 16:44:40 -0800505 uint8_t properties,
506 uint16_t permissions) {
Nick Desaulniers7ee58352019-10-09 11:06:55 -0700507 pending_svc_decl.push_back({.uuid = uuid,
508 .type = BTGATT_DB_CHARACTERISTIC,
Myles Watson911d1ae2016-11-28 16:44:40 -0800509 .properties = properties,
510 .permissions = permissions});
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700511 return BT_STATUS_SUCCESS;
Arman Uguray0f2d4892015-09-22 14:20:42 -0700512}
513
514ServerInternals::ServerInternals()
515 : gatt(nullptr),
516 server_if(0),
517 client_if(0),
518 service_handle(0),
519 pipefd{INVALID_FD, INVALID_FD} {}
520
521ServerInternals::~ServerInternals() {
Myles Watson911d1ae2016-11-28 16:44:40 -0800522 if (pipefd[0] != INVALID_FD) close(pipefd[0]);
523 if (pipefd[1] != INVALID_FD) close(pipefd[1]);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700524
525 gatt->server->delete_service(server_if, service_handle);
526 gatt->server->unregister_server(server_if);
527 gatt->client->unregister_client(client_if);
528}
529
530Server::Server() : internal_(nullptr) {}
531
532Server::~Server() {}
533
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700534bool Server::Initialize(const Uuid& service_id, int* gatt_pipe) {
Arman Uguray0f2d4892015-09-22 14:20:42 -0700535 internal_.reset(new ServerInternals);
536 if (!internal_) {
537 LOG_ERROR(LOG_TAG, "Error creating internals");
538 return false;
539 }
540 g_internal = internal_.get();
541
542 std::unique_lock<std::mutex> lock(internal_->lock);
543 int status = internal_->Initialize();
544 if (status) {
545 LOG_ERROR(LOG_TAG, "Error initializing internals");
546 return false;
547 }
548
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700549 bt_status_t btstat = internal_->gatt->server->register_server(service_id);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700550 if (btstat != BT_STATUS_SUCCESS) {
551 LOG_ERROR(LOG_TAG, "Failed to register server");
552 return false;
553 }
554
555 internal_->api_synchronize.wait(lock);
556 // TODO(icoolidge): Better error handling.
557 if (internal_->server_if == 0) {
558 LOG_ERROR(LOG_TAG, "Initialization of server failed");
559 return false;
560 }
561
562 *gatt_pipe = internal_->pipefd[kPipeReadEnd];
563 LOG_INFO(LOG_TAG, "Server Initialize succeeded");
564 return true;
565}
566
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700567bool Server::SetAdvertisement(const std::vector<Uuid>& ids,
Arman Uguray0f2d4892015-09-22 14:20:42 -0700568 const std::vector<uint8_t>& service_data,
569 const std::vector<uint8_t>& manufacturer_data,
570 bool transmit_name) {
Jakub Pawlowski0ecddf32016-10-19 14:46:09 -0700571 // std::vector<uint8_t> id_data;
572 // const auto& mutable_manufacturer_data = manufacturer_data;
573 // const auto& mutable_service_data = service_data;
Arman Uguray0f2d4892015-09-22 14:20:42 -0700574
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700575 // for (const Uuid &id : ids) {
576 // const auto le_id = id.To128BitLE();
Jakub Pawlowski0ecddf32016-10-19 14:46:09 -0700577 // id_data.insert(id_data.end(), le_id.begin(), le_id.end());
578 // }
Arman Uguray0f2d4892015-09-22 14:20:42 -0700579
580 std::lock_guard<std::mutex> lock(internal_->lock);
581
582 // Setup our advertisement. This has no callback.
Myles Watson911d1ae2016-11-28 16:44:40 -0800583 internal_->gatt->advertiser->SetData(0, false, /* beacon, not scan response */
Jakub Pawlowski67f5f372018-07-23 10:00:25 -0700584 {}, base::DoNothing());
Myles Watson911d1ae2016-11-28 16:44:40 -0800585 // transmit_name, /* name */
586 // 2, 2, interval
587 // mutable_manufacturer_data,
588 // mutable_service_data,
589 // id_data);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700590 return true;
591}
592
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700593bool Server::SetScanResponse(const std::vector<Uuid>& ids,
Arman Uguray0f2d4892015-09-22 14:20:42 -0700594 const std::vector<uint8_t>& service_data,
595 const std::vector<uint8_t>& manufacturer_data,
596 bool transmit_name) {
Jakub Pawlowski0ecddf32016-10-19 14:46:09 -0700597 // std::vector<uint8_t> id_data;
598 // const auto& mutable_manufacturer_data = manufacturer_data;
599 // const auto& mutable_service_data = service_data;
Arman Uguray0f2d4892015-09-22 14:20:42 -0700600
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700601 // for (const Uuid &id : ids) {
602 // const auto le_id = id.To128BitLE();
Jakub Pawlowski0ecddf32016-10-19 14:46:09 -0700603 // id_data.insert(id_data.end(), le_id.begin(), le_id.end());
604 // }
Arman Uguray0f2d4892015-09-22 14:20:42 -0700605
606 std::lock_guard<std::mutex> lock(internal_->lock);
607
608 // Setup our advertisement. This has no callback.
Myles Watson911d1ae2016-11-28 16:44:40 -0800609 internal_->gatt->advertiser->SetData(0, true, /* scan response */
Jakub Pawlowski67f5f372018-07-23 10:00:25 -0700610 {}, base::DoNothing());
Myles Watson911d1ae2016-11-28 16:44:40 -0800611 // transmit_name, /* name */
612 // false, /* no txpower */
613 // 2, 2, interval
614 // 0, /* appearance */
615 // mutable_manufacturer_data,
616 // mutable_service_data,
617 // id_data);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700618 return true;
619}
620
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700621bool Server::AddCharacteristic(const Uuid& id, int properties,
Myles Watson911d1ae2016-11-28 16:44:40 -0800622 int permissions) {
Arman Uguray0f2d4892015-09-22 14:20:42 -0700623 std::unique_lock<std::mutex> lock(internal_->lock);
Myles Watson911d1ae2016-11-28 16:44:40 -0800624 bt_status_t btstat =
625 internal_->AddCharacteristic(id, properties, permissions);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700626 if (btstat != BT_STATUS_SUCCESS) {
627 LOG_ERROR(LOG_TAG, "Failed to add characteristic to service: 0x%04x",
628 internal_->service_handle);
629 return false;
630 }
631 internal_->api_synchronize.wait(lock);
632 const int handle = internal_->uuid_to_attribute[id];
633 internal_->characteristics[handle].notify = properties & kPropertyNotify;
634 return true;
635}
636
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700637bool Server::AddBlob(const Uuid& id, const Uuid& control_id, int properties,
Myles Watson911d1ae2016-11-28 16:44:40 -0800638 int permissions) {
Arman Uguray0f2d4892015-09-22 14:20:42 -0700639 std::unique_lock<std::mutex> lock(internal_->lock);
640
641 // First, add the primary attribute (characteristic value)
Myles Watson911d1ae2016-11-28 16:44:40 -0800642 bt_status_t btstat =
643 internal_->AddCharacteristic(id, properties, permissions);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700644 if (btstat != BT_STATUS_SUCCESS) {
645 LOG_ERROR(LOG_TAG, "Failed to set scan response data");
646 return false;
647 }
648
Arman Uguray0f2d4892015-09-22 14:20:42 -0700649 // Next, add the secondary attribute (blob control).
650 // Control attributes have fixed permissions/properties.
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700651 // Remember position at which blob was added.
652 blob_index.insert(pending_svc_decl.size());
Myles Watson911d1ae2016-11-28 16:44:40 -0800653 btstat =
654 internal_->AddCharacteristic(control_id, kPropertyRead | kPropertyWrite,
655 kPermissionRead | kPermissionWrite);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700656
Arman Uguray0f2d4892015-09-22 14:20:42 -0700657 return true;
658}
659
660bool Server::Start() {
661 std::unique_lock<std::mutex> lock(internal_->lock);
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700662 bt_status_t btstat = internal_->gatt->server->add_service(
663 internal_->server_if, pending_svc_decl);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700664 if (btstat != BT_STATUS_SUCCESS) {
665 LOG_ERROR(LOG_TAG, "Failed to start service with handle: 0x%04x",
666 internal_->service_handle);
667 return false;
668 }
669 internal_->api_synchronize.wait(lock);
670 return true;
671}
672
673bool Server::Stop() {
674 std::unique_lock<std::mutex> lock(internal_->lock);
675 bt_status_t btstat = internal_->gatt->server->stop_service(
676 internal_->server_if, internal_->service_handle);
677 if (btstat != BT_STATUS_SUCCESS) {
678 LOG_ERROR(LOG_TAG, "Failed to stop service with handle: 0x%04x",
679 internal_->service_handle);
680 return false;
681 }
682 internal_->api_synchronize.wait(lock);
683 return true;
684}
685
686bool Server::ScanEnable() {
Jakub Pawlowski83f1d962016-12-14 09:49:38 -0800687 internal_->gatt->scanner->Scan(true);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700688 return true;
689}
690
691bool Server::ScanDisable() {
Jakub Pawlowski83f1d962016-12-14 09:49:38 -0800692 internal_->gatt->scanner->Scan(false);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700693 return true;
694}
695
Myles Watson911d1ae2016-11-28 16:44:40 -0800696bool Server::GetScanResults(ScanResults* results) {
Arman Uguray0f2d4892015-09-22 14:20:42 -0700697 std::lock_guard<std::mutex> lock(internal_->lock);
698 *results = internal_->scan_results;
699 return true;
700}
701
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700702bool Server::SetCharacteristicValue(const Uuid& id,
Myles Watson911d1ae2016-11-28 16:44:40 -0800703 const std::vector<uint8_t>& value) {
Arman Uguray0f2d4892015-09-22 14:20:42 -0700704 std::lock_guard<std::mutex> lock(internal_->lock);
705 const int attribute_id = internal_->uuid_to_attribute[id];
Myles Watson911d1ae2016-11-28 16:44:40 -0800706 Characteristic& ch = internal_->characteristics[attribute_id];
Arman Uguray0f2d4892015-09-22 14:20:42 -0700707 ch.next_blob = value;
708 ch.next_blob_pending = true;
709
Myles Watson911d1ae2016-11-28 16:44:40 -0800710 if (!ch.notify) return true;
Arman Uguray0f2d4892015-09-22 14:20:42 -0700711
712 for (auto connection : internal_->connections) {
Myles Watson911d1ae2016-11-28 16:44:40 -0800713 internal_->gatt->server->send_indication(internal_->server_if, attribute_id,
714 connection, true, {0});
Arman Uguray0f2d4892015-09-22 14:20:42 -0700715 }
716 return true;
717}
718
Jakub Pawlowski819e2ec2017-07-10 09:56:09 -0700719bool Server::GetCharacteristicValue(const Uuid& id,
Myles Watson911d1ae2016-11-28 16:44:40 -0800720 std::vector<uint8_t>* value) {
Arman Uguray0f2d4892015-09-22 14:20:42 -0700721 std::lock_guard<std::mutex> lock(internal_->lock);
722 const int attribute_id = internal_->uuid_to_attribute[id];
723 *value = internal_->characteristics[attribute_id].blob;
724 return true;
725}
726
727} // namespace gatt
728} // namespace bluetooth