blob: f6099ef265a1310432ef52d5af9e2ba80e1160df [file] [log] [blame]
Arman Uguray0f2d4892015-09-22 14:20:42 -07001//
2// Copyright (C) 2015 Google, Inc.
3//
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>
Arman Uguray0f2d4892015-09-22 14:20:42 -070026#include <algorithm>
27#include <array>
28#include <condition_variable>
29#include <map>
30#include <memory>
31#include <mutex>
32#include <set>
33#include <string>
34#include <unordered_map>
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -070035#include <unordered_set>
Arman Uguray0f2d4892015-09-22 14:20:42 -070036#include <vector>
37
38#include <hardware/bluetooth.h>
39#include <hardware/bt_gatt.h>
40
41#include "service/hal/bluetooth_interface.h"
42#include "service/logging_helpers.h"
Arman Uguray0f2d4892015-09-22 14:20:42 -070043
Arman Uguray0f2d4892015-09-22 14:20:42 -070044#include "osi/include/log.h"
45#include "osi/include/osi.h"
Arman Uguray0f2d4892015-09-22 14:20:42 -070046
47namespace {
48
49const size_t kMaxGattAttributeSize = 512;
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -070050std::vector<btgatt_db_element_t> pending_svc_decl;
51std::unordered_set<int> blob_index;
Arman Uguray0f2d4892015-09-22 14:20:42 -070052
53// TODO(icoolidge): Support multiple instances
54// TODO(armansito): Remove this variable. No point of having this if
55// each bluetooth::gatt::Server instance already keeps a pointer to the
56// ServerInternals that is associated with it (which is much cleaner). It looks
57// like this variable exists because the btif callbacks don't allow the
58// upper-layer to pass user data to them. We could:
59//
60// 1. Fix the btif callbacks so that some sort of continuation can be
61// attached to a callback. This might be a long shot since the callback
62// interface doesn't allow more than one caller to register its own callbacks
63// (which might be what we want though, since this would make the API more
64// flexible).
65//
66// 2. Allow creation of Server objects using a factory method that returns
67// the result asynchronously in a base::Callback. The RegisterServerCallback
68// provides an |app_uuid|, which can be used to store callback structures in
69// a map and lazily instantiate the Server and invoke the correct callback.
70// This is a general pattern that we should use throughout the daemon, since
71// all operations can timeout or fail and this is best reported in an
72// asynchronous base::Callback.
73//
Myles Watson911d1ae2016-11-28 16:44:40 -080074static bluetooth::gatt::ServerInternals* g_internal = nullptr;
Arman Uguray0f2d4892015-09-22 14:20:42 -070075
76enum { kPipeReadEnd = 0, kPipeWriteEnd = 1, kPipeNumEnds = 2 };
77
78} // namespace
79
Jakub Pawlowskid964cf92016-11-03 15:41:50 -070080void DoNothing(uint8_t p) {}
81
Arman Uguray0f2d4892015-09-22 14:20:42 -070082namespace bluetooth {
83namespace gatt {
84
85struct Characteristic {
86 UUID uuid;
87 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();
Myles Watson911d1ae2016-11-28 16:44:40 -0800100 bt_status_t AddCharacteristic(const UUID& uuid, uint8_t properties,
101 uint16_t permissions);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700102
103 // This maps API attribute UUIDs to BlueDroid handles.
104 std::map<UUID, int> uuid_to_attribute;
105
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
114 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,
133 const bt_uuid_t& 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;
Myles Watson911d1ae2016-11-28 16:44:40 -0800138 pending_svc_decl.push_back(
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700139 {.type = BTGATT_DB_PRIMARY_SERVICE, .uuid = app_uuid});
Arman Uguray0f2d4892015-09-22 14:20:42 -0700140}
141
Myles Watson911d1ae2016-11-28 16:44:40 -0800142void ServiceAddedCallback(int status, int server_if,
Pavlin Radoslavovb324a8d2016-12-09 17:50:59 -0800143 std::vector<btgatt_db_element_t> service) {
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700144 LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d count:%zu svc_handle:%d",
Myles Watson911d1ae2016-11-28 16:44:40 -0800145 __func__, status, server_if, service.size(),
146 service[0].attribute_handle);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700147
148 std::lock_guard<std::mutex> lock(g_internal->lock);
149 g_internal->server_if = server_if;
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700150
151 g_internal->service_handle = service[0].attribute_handle;
152
153 uint16_t prev_char_handle = 0;
154 uint16_t prev_char_properties = 0;
Myles Watson911d1ae2016-11-28 16:44:40 -0800155 for (size_t i = 1; i < service.size(); i++) {
156 const btgatt_db_element_t& el = service[i];
Jakub Pawlowskiaeafd392016-09-19 10:38:20 -0700157 if (el.type == BTGATT_DB_DESCRIPTOR) {
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700158 LOG_INFO(LOG_TAG, "%s: descr_handle:%d", __func__, el.attribute_handle);
159 } else if (el.type == BTGATT_DB_CHARACTERISTIC) {
160 bluetooth::UUID id(el.uuid);
161 uint16_t char_handle = el.attribute_handle;
162
163 LOG_INFO(LOG_TAG, "%s: char_handle:%d", __func__, char_handle);
164
165 g_internal->uuid_to_attribute[id] = char_handle;
166 g_internal->characteristics[char_handle].uuid = id;
167 g_internal->characteristics[char_handle].blob_section = 0;
168
169 // If the added characteristic is blob
170 if (blob_index.find(i) != blob_index.end()) {
171 // Finally, associate the control attribute with the value attribute.
172 // Also, initialize the control attribute to a readable zero.
173 const uint16_t control_attribute = char_handle;
174 const uint16_t blob_attribute = prev_char_handle;
175 g_internal->controlled_blobs[control_attribute] = blob_attribute;
176 g_internal->characteristics[blob_attribute].notify =
177 prev_char_properties & bluetooth::gatt::kPropertyNotify;
178
Myles Watson911d1ae2016-11-28 16:44:40 -0800179 bluetooth::gatt::Characteristic& ctrl =
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700180 g_internal->characteristics[control_attribute];
181 ctrl.next_blob.clear();
182 ctrl.next_blob.push_back(0);
183 ctrl.next_blob_pending = true;
184 ctrl.blob_section = 0;
185 ctrl.notify = false;
186 }
187 prev_char_handle = char_handle;
188 prev_char_properties = el.properties;
189 }
190 }
191
192 pending_svc_decl.clear();
193 blob_index.clear();
194
195 // The UUID provided here is unimportant, and is only used to satisfy
196 // BlueDroid.
197 // It must be different than any other registered UUID.
198 bt_uuid_t client_id = service[0].uuid;
199 ++client_id.uu[15];
200
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700201 bt_status_t btstat = g_internal->gatt->client->register_client(client_id);
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700202 if (btstat != BT_STATUS_SUCCESS) {
203 LOG_ERROR(LOG_TAG, "%s: Failed to register client", __func__);
204 }
Arman Uguray0f2d4892015-09-22 14:20:42 -0700205}
206
Jakub Pawlowskia484a882017-06-24 17:30:18 -0700207void RequestReadCallback(int conn_id, int trans_id, const RawAddress& bda,
Arman Uguray0f2d4892015-09-22 14:20:42 -0700208 int attr_handle, int attribute_offset_octets,
209 bool is_long) {
210 std::lock_guard<std::mutex> lock(g_internal->lock);
211
Myles Watson911d1ae2016-11-28 16:44:40 -0800212 bluetooth::gatt::Characteristic& ch =
213 g_internal->characteristics[attr_handle];
Arman Uguray0f2d4892015-09-22 14:20:42 -0700214
215 // Latch next_blob to blob on a 'fresh' read.
216 if (ch.next_blob_pending && attribute_offset_octets == 0 &&
217 ch.blob_section == 0) {
218 std::swap(ch.blob, ch.next_blob);
219 ch.next_blob_pending = false;
220 }
221
222 const size_t blob_offset_octets =
223 std::min(ch.blob.size(), ch.blob_section * kMaxGattAttributeSize);
224 const size_t blob_remaining = ch.blob.size() - blob_offset_octets;
225 const size_t attribute_size = std::min(kMaxGattAttributeSize, blob_remaining);
226
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700227 std::string addr(BtAddrString(&bda));
Arman Uguray0f2d4892015-09-22 14:20:42 -0700228 LOG_INFO(LOG_TAG,
Myles Watson911d1ae2016-11-28 16:44:40 -0800229 "%s: connection:%d (%s) reading attr:%d attribute_offset_octets:%d "
230 "blob_section:%u (is_long:%u)",
231 __func__, conn_id, addr.c_str(), attr_handle,
232 attribute_offset_octets, ch.blob_section, is_long);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700233
234 btgatt_response_t response;
235 response.attr_value.len = 0;
236
237 if (attribute_offset_octets < static_cast<int>(attribute_size)) {
238 std::copy(ch.blob.begin() + blob_offset_octets + attribute_offset_octets,
239 ch.blob.begin() + blob_offset_octets + attribute_size,
240 response.attr_value.value);
241 response.attr_value.len = attribute_size - attribute_offset_octets;
242 }
243
244 response.attr_value.handle = attr_handle;
245 response.attr_value.offset = attribute_offset_octets;
246 response.attr_value.auth_req = 0;
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700247 g_internal->gatt->server->send_response(conn_id, trans_id, 0, response);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700248}
249
Jakub Pawlowskia484a882017-06-24 17:30:18 -0700250void RequestWriteCallback(int conn_id, int trans_id, const RawAddress& bda,
Myles Watson911d1ae2016-11-28 16:44:40 -0800251 int attr_handle, int attribute_offset, bool need_rsp,
Pavlin Radoslavovb324a8d2016-12-09 17:50:59 -0800252 bool is_prep, std::vector<uint8_t> value) {
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700253 std::string addr(BtAddrString(&bda));
Arman Uguray0f2d4892015-09-22 14:20:42 -0700254 LOG_INFO(LOG_TAG,
Myles Watson911d1ae2016-11-28 16:44:40 -0800255 "%s: connection:%d (%s:trans:%d) write attr:%d attribute_offset:%d "
256 "length:%zu "
257 "need_resp:%u is_prep:%u",
258 __func__, conn_id, addr.c_str(), trans_id, attr_handle,
259 attribute_offset, value.size(), need_rsp, is_prep);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700260
261 std::lock_guard<std::mutex> lock(g_internal->lock);
262
Myles Watson911d1ae2016-11-28 16:44:40 -0800263 bluetooth::gatt::Characteristic& ch =
Arman Uguray0f2d4892015-09-22 14:20:42 -0700264 g_internal->characteristics[attr_handle];
265
Jakub Pawlowski16102de2016-05-31 13:14:13 -0700266 ch.blob.resize(attribute_offset + value.size());
Arman Uguray0f2d4892015-09-22 14:20:42 -0700267
Jakub Pawlowski16102de2016-05-31 13:14:13 -0700268 std::copy(value.begin(), value.end(), ch.blob.begin() + attribute_offset);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700269
270 auto target_blob = g_internal->controlled_blobs.find(attr_handle);
271 // If this is a control attribute, adjust offset of the target blob.
272 if (target_blob != g_internal->controlled_blobs.end() &&
273 ch.blob.size() == 1u) {
274 g_internal->characteristics[target_blob->second].blob_section = ch.blob[0];
275 LOG_INFO(LOG_TAG, "%s: updating attribute %d blob_section to %u", __func__,
Myles Watson911d1ae2016-11-28 16:44:40 -0800276 target_blob->second, ch.blob[0]);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700277 } else if (!is_prep) {
278 // This is a single frame characteristic write.
279 // Notify upwards because we're done now.
Myles Watson911d1ae2016-11-28 16:44:40 -0800280 const bluetooth::UUID::UUID128Bit& attr_uuid = ch.uuid.GetFullBigEndian();
Pavlin Radoslavovd6121a32016-05-12 11:36:44 -0700281 ssize_t status;
282 OSI_NO_INTR(status = write(g_internal->pipefd[kPipeWriteEnd],
283 attr_uuid.data(), attr_uuid.size()));
Arman Uguray0f2d4892015-09-22 14:20:42 -0700284 if (-1 == status)
285 LOG_ERROR(LOG_TAG, "%s: write failed: %s", __func__, strerror(errno));
286 } else {
287 // This is a multi-frame characteristic write.
288 // Wait for an 'RequestExecWriteCallback' to notify completion.
289 g_internal->last_write = ch.uuid;
290 }
291
292 // Respond only if needed.
293 if (!need_rsp) return;
294
295 btgatt_response_t response;
296 response.attr_value.handle = attr_handle;
297 response.attr_value.offset = attribute_offset;
Jakub Pawlowski16102de2016-05-31 13:14:13 -0700298 response.attr_value.len = value.size();
Arman Uguray0f2d4892015-09-22 14:20:42 -0700299 response.attr_value.auth_req = 0;
300 // Provide written data back to sender for the response.
301 // Remote stacks use this to validate the success of the write.
Jakub Pawlowski16102de2016-05-31 13:14:13 -0700302 std::copy(value.begin(), value.end(), response.attr_value.value);
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700303 g_internal->gatt->server->send_response(conn_id, trans_id, 0, response);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700304}
305
Jakub Pawlowskia484a882017-06-24 17:30:18 -0700306void RequestExecWriteCallback(int conn_id, int trans_id, const RawAddress& bda,
Arman Uguray0f2d4892015-09-22 14:20:42 -0700307 int exec_write) {
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700308 std::string addr(BtAddrString(&bda));
Arman Uguray0f2d4892015-09-22 14:20:42 -0700309 LOG_INFO(LOG_TAG, "%s: connection:%d (%s:trans:%d) exec_write:%d", __func__,
Myles Watson911d1ae2016-11-28 16:44:40 -0800310 conn_id, addr.c_str(), trans_id, exec_write);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700311
312 // This 'response' data is unused for ExecWriteResponses.
313 // It is only used to pass BlueDroid argument validation.
314 btgatt_response_t response = {};
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700315 g_internal->gatt->server->send_response(conn_id, trans_id, 0, response);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700316
Myles Watson911d1ae2016-11-28 16:44:40 -0800317 if (!exec_write) return;
Arman Uguray0f2d4892015-09-22 14:20:42 -0700318
319 std::lock_guard<std::mutex> lock(g_internal->lock);
320 // Communicate the attribute UUID as notification of a write update.
321 const bluetooth::UUID::UUID128Bit uuid =
322 g_internal->last_write.GetFullBigEndian();
Pavlin Radoslavovd6121a32016-05-12 11:36:44 -0700323 ssize_t status;
324 OSI_NO_INTR(status = write(g_internal->pipefd[kPipeWriteEnd], uuid.data(),
325 uuid.size()));
Arman Uguray0f2d4892015-09-22 14:20:42 -0700326 if (-1 == status)
327 LOG_ERROR(LOG_TAG, "%s: write failed: %s", __func__, strerror(errno));
328}
329
330void ConnectionCallback(int conn_id, int server_if, int connected,
Jakub Pawlowskia484a882017-06-24 17:30:18 -0700331 const RawAddress& bda) {
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700332 std::string addr(BtAddrString(&bda));
Arman Uguray0f2d4892015-09-22 14:20:42 -0700333 LOG_INFO(LOG_TAG, "%s: connection:%d server_if:%d connected:%d addr:%s",
Myles Watson911d1ae2016-11-28 16:44:40 -0800334 __func__, conn_id, server_if, connected, addr.c_str());
Arman Uguray0f2d4892015-09-22 14:20:42 -0700335 if (connected == 1) {
336 g_internal->connections.insert(conn_id);
337 } else if (connected == 0) {
338 g_internal->connections.erase(conn_id);
339 }
340}
341
Jakub Pawlowskia8d73ef2016-10-31 11:15:20 -0700342void EnableAdvertisingCallback(uint8_t status) {
343 LOG_INFO(LOG_TAG, "%s: status:%d", __func__, status);
344 // This terminates a Start call.
345 std::lock_guard<std::mutex> lock(g_internal->lock);
346 g_internal->api_synchronize.notify_one();
347}
348
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700349void RegisterClientCallback(int status, int client_if,
350 const bt_uuid_t& app_uuid) {
Arman Uguray0f2d4892015-09-22 14:20:42 -0700351 LOG_INFO(LOG_TAG, "%s: status:%d client_if:%d uuid[0]:%u", __func__, status,
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700352 client_if, app_uuid.uu[0]);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700353 g_internal->client_if = client_if;
354
355 // Setup our advertisement. This has no callback.
Jakub Pawlowskid964cf92016-11-03 15:41:50 -0700356 g_internal->gatt->advertiser->SetData(0 /* std_inst */, false,
357 {/*TODO: put inverval 2,2 here*/},
358 base::Bind(&DoNothing));
Arman Uguray0f2d4892015-09-22 14:20:42 -0700359
Jakub Pawlowskid964cf92016-11-03 15:41:50 -0700360 g_internal->gatt->advertiser->Enable(
361 0 /* std_inst */, true, base::Bind(&EnableAdvertisingCallback),
Jakub Pawlowski5204c622017-03-30 20:41:02 -0700362 0 /* no duration */, 0 /* no maxExtAdvEvent*/, base::Bind(&DoNothing));
Arman Uguray0f2d4892015-09-22 14:20:42 -0700363}
364
Arman Uguray0f2d4892015-09-22 14:20:42 -0700365void ServiceStoppedCallback(int status, int server_if, int srvc_handle) {
366 LOG_INFO(LOG_TAG, "%s: status:%d server_if:%d srvc_handle:%d", __func__,
Myles Watson911d1ae2016-11-28 16:44:40 -0800367 status, server_if, srvc_handle);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700368 // This terminates a Stop call.
369 // TODO(icoolidge): make this symmetric with start
370 std::lock_guard<std::mutex> lock(g_internal->lock);
371 g_internal->api_synchronize.notify_one();
372}
373
Jakub Pawlowski7de0f9b2017-01-27 08:06:20 -0800374void ScanResultCallback(uint16_t ble_evt_type, uint8_t addr_type,
Jakub Pawlowskia484a882017-06-24 17:30:18 -0700375 RawAddress* bda, uint8_t ble_primary_phy,
Jakub Pawlowski7de0f9b2017-01-27 08:06:20 -0800376 uint8_t ble_secondary_phy, uint8_t ble_advertising_sid,
377 int8_t ble_tx_power, int8_t rssi,
378 uint16_t ble_periodic_adv_int,
Pavlin Radoslavovb324a8d2016-12-09 17:50:59 -0800379 std::vector<uint8_t> adv_data) {
Arman Uguray0f2d4892015-09-22 14:20:42 -0700380 std::string addr(BtAddrString(bda));
Arman Uguray0f2d4892015-09-22 14:20:42 -0700381 std::lock_guard<std::mutex> lock(g_internal->lock);
382 g_internal->scan_results[addr] = rssi;
383}
384
385void ClientConnectCallback(int conn_id, int status, int client_if,
Jakub Pawlowskia484a882017-06-24 17:30:18 -0700386 const RawAddress& bda) {
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700387 std::string addr(BtAddrString(&bda));
Arman Uguray0f2d4892015-09-22 14:20:42 -0700388 LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__,
Myles Watson911d1ae2016-11-28 16:44:40 -0800389 conn_id, status, client_if, addr.c_str());
Arman Uguray0f2d4892015-09-22 14:20:42 -0700390}
391
392void ClientDisconnectCallback(int conn_id, int status, int client_if,
Jakub Pawlowskia484a882017-06-24 17:30:18 -0700393 const RawAddress& bda) {
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700394 std::string addr(BtAddrString(&bda));
Arman Uguray0f2d4892015-09-22 14:20:42 -0700395 LOG_INFO(LOG_TAG, "%s: conn_id:%d status:%d client_if:%d %s", __func__,
Myles Watson911d1ae2016-11-28 16:44:40 -0800396 conn_id, status, client_if, addr.c_str());
Arman Uguray0f2d4892015-09-22 14:20:42 -0700397}
398
Myles Watson911d1ae2016-11-28 16:44:40 -0800399void IndicationSentCallback(UNUSED_ATTR int conn_id, UNUSED_ATTR int status) {
Arman Uguray0f2d4892015-09-22 14:20:42 -0700400 // TODO(icoolidge): what to do
401}
402
403void ResponseConfirmationCallback(UNUSED_ATTR int status,
404 UNUSED_ATTR int handle) {
405 // TODO(icoolidge): what to do
406}
407
408const btgatt_server_callbacks_t gatt_server_callbacks = {
409 RegisterServerCallback,
410 ConnectionCallback,
411 ServiceAddedCallback,
Arman Uguray0f2d4892015-09-22 14:20:42 -0700412 ServiceStoppedCallback,
413 nullptr, /* service_deleted_cb */
414 RequestReadCallback,
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700415 RequestReadCallback,
416 RequestWriteCallback,
Arman Uguray0f2d4892015-09-22 14:20:42 -0700417 RequestWriteCallback,
418 RequestExecWriteCallback,
419 ResponseConfirmationCallback,
420 IndicationSentCallback,
421 nullptr, /* congestion_cb*/
422 nullptr, /* mtu_changed_cb */
Jakub Pawlowskieafd45d2017-03-22 19:00:47 -0700423 nullptr, /* phy_update_cb */
Jakub Pawlowskib5ba4fd2017-03-23 18:11:04 -0700424 nullptr, /* conn_update_cb */
Arman Uguray0f2d4892015-09-22 14:20:42 -0700425};
426
427// TODO(eisenbach): Refactor GATT interface to not require servers
428// to refer to the client interface.
429const btgatt_client_callbacks_t gatt_client_callbacks = {
430 RegisterClientCallback,
Arman Uguray0f2d4892015-09-22 14:20:42 -0700431 ClientConnectCallback,
432 ClientDisconnectCallback,
433 nullptr, /* search_complete_cb; */
Arman Uguray0f2d4892015-09-22 14:20:42 -0700434 nullptr, /* register_for_notification_cb; */
435 nullptr, /* notify_cb; */
436 nullptr, /* read_characteristic_cb; */
437 nullptr, /* write_characteristic_cb; */
438 nullptr, /* read_descriptor_cb; */
439 nullptr, /* write_descriptor_cb; */
440 nullptr, /* execute_write_cb; */
441 nullptr, /* read_remote_rssi_cb; */
Arman Uguray0f2d4892015-09-22 14:20:42 -0700442 nullptr, /* configure_mtu_cb; */
Arman Uguray0f2d4892015-09-22 14:20:42 -0700443 nullptr, /* congestion_cb; */
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700444 nullptr, /* get_gatt_db_cb; */
445 nullptr, /* services_removed_cb */
446 nullptr, /* services_added_cb */
Jakub Pawlowskieafd45d2017-03-22 19:00:47 -0700447 nullptr, /* phy_update_cb */
Jakub Pawlowskib5ba4fd2017-03-23 18:11:04 -0700448 nullptr, /* conn_update_cb */
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700449};
450
451const btgatt_scanner_callbacks_t gatt_scanner_callbacks = {
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700452 ScanResultCallback,
Arman Uguray0f2d4892015-09-22 14:20:42 -0700453 nullptr, /* batchscan_reports_cb; */
454 nullptr, /* batchscan_threshold_cb; */
455 nullptr, /* track_adv_event_cb; */
Arman Uguray0f2d4892015-09-22 14:20:42 -0700456};
457
458const btgatt_callbacks_t gatt_callbacks = {
459 /** Set to sizeof(btgatt_callbacks_t) */
460 sizeof(btgatt_callbacks_t),
461
462 /** GATT Client callbacks */
463 &gatt_client_callbacks,
464
465 /** GATT Server callbacks */
Jakub Pawlowski67d5a252016-07-13 11:55:16 -0700466 &gatt_server_callbacks,
Jakub Pawlowskic3f6a512016-10-27 11:49:40 -0700467
468 /** GATT Server callbacks */
469 &gatt_scanner_callbacks,
Jakub Pawlowski67d5a252016-07-13 11:55:16 -0700470};
Arman Uguray0f2d4892015-09-22 14:20:42 -0700471
472} // namespace
473
474namespace bluetooth {
475namespace gatt {
476
477int ServerInternals::Initialize() {
478 // Get the interface to the GATT profile.
479 const bt_interface_t* bt_iface =
480 hal::BluetoothInterface::Get()->GetHALInterface();
Myles Watson911d1ae2016-11-28 16:44:40 -0800481 gatt = reinterpret_cast<const btgatt_interface_t*>(
Arman Uguray0f2d4892015-09-22 14:20:42 -0700482 bt_iface->get_profile_interface(BT_PROFILE_GATT_ID));
483 if (!gatt) {
484 LOG_ERROR(LOG_TAG, "Error getting GATT interface");
485 return -1;
486 }
487
488 bt_status_t btstat = gatt->init(&gatt_callbacks);
489 if (btstat != BT_STATUS_SUCCESS) {
490 LOG_ERROR(LOG_TAG, "Failed to initialize gatt interface");
491 return -1;
492 }
493
494 int status = pipe(pipefd);
495 if (status == -1) {
496 LOG_ERROR(LOG_TAG, "pipe creation failed: %s", strerror(errno));
497 return -1;
498 }
499
500 return 0;
501}
502
Myles Watson911d1ae2016-11-28 16:44:40 -0800503bt_status_t ServerInternals::AddCharacteristic(const UUID& uuid,
504 uint8_t properties,
505 uint16_t permissions) {
Arman Uguray0f2d4892015-09-22 14:20:42 -0700506 bt_uuid_t c_uuid = uuid.GetBlueDroid();
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700507
Myles Watson911d1ae2016-11-28 16:44:40 -0800508 pending_svc_decl.push_back({.type = BTGATT_DB_CHARACTERISTIC,
509 .uuid = c_uuid,
510 .properties = properties,
511 .permissions = permissions});
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700512 return BT_STATUS_SUCCESS;
Arman Uguray0f2d4892015-09-22 14:20:42 -0700513}
514
515ServerInternals::ServerInternals()
516 : gatt(nullptr),
517 server_if(0),
518 client_if(0),
519 service_handle(0),
520 pipefd{INVALID_FD, INVALID_FD} {}
521
522ServerInternals::~ServerInternals() {
Myles Watson911d1ae2016-11-28 16:44:40 -0800523 if (pipefd[0] != INVALID_FD) close(pipefd[0]);
524 if (pipefd[1] != INVALID_FD) close(pipefd[1]);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700525
526 gatt->server->delete_service(server_if, service_handle);
527 gatt->server->unregister_server(server_if);
528 gatt->client->unregister_client(client_if);
529}
530
531Server::Server() : internal_(nullptr) {}
532
533Server::~Server() {}
534
535bool Server::Initialize(const UUID& service_id, int* gatt_pipe) {
536 internal_.reset(new ServerInternals);
537 if (!internal_) {
538 LOG_ERROR(LOG_TAG, "Error creating internals");
539 return false;
540 }
541 g_internal = internal_.get();
542
543 std::unique_lock<std::mutex> lock(internal_->lock);
544 int status = internal_->Initialize();
545 if (status) {
546 LOG_ERROR(LOG_TAG, "Error initializing internals");
547 return false;
548 }
549
550 bt_uuid_t uuid = service_id.GetBlueDroid();
551
Jakub Pawlowski96ac0a32017-06-21 00:00:18 -0700552 bt_status_t btstat = internal_->gatt->server->register_server(uuid);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700553 if (btstat != BT_STATUS_SUCCESS) {
554 LOG_ERROR(LOG_TAG, "Failed to register server");
555 return false;
556 }
557
558 internal_->api_synchronize.wait(lock);
559 // TODO(icoolidge): Better error handling.
560 if (internal_->server_if == 0) {
561 LOG_ERROR(LOG_TAG, "Initialization of server failed");
562 return false;
563 }
564
565 *gatt_pipe = internal_->pipefd[kPipeReadEnd];
566 LOG_INFO(LOG_TAG, "Server Initialize succeeded");
567 return true;
568}
569
570bool Server::SetAdvertisement(const std::vector<UUID>& ids,
571 const std::vector<uint8_t>& service_data,
572 const std::vector<uint8_t>& manufacturer_data,
573 bool transmit_name) {
Jakub Pawlowski0ecddf32016-10-19 14:46:09 -0700574 // std::vector<uint8_t> id_data;
575 // const auto& mutable_manufacturer_data = manufacturer_data;
576 // const auto& mutable_service_data = service_data;
Arman Uguray0f2d4892015-09-22 14:20:42 -0700577
Jakub Pawlowski0ecddf32016-10-19 14:46:09 -0700578 // for (const UUID &id : ids) {
579 // const auto le_id = id.GetFullLittleEndian();
580 // id_data.insert(id_data.end(), le_id.begin(), le_id.end());
581 // }
Arman Uguray0f2d4892015-09-22 14:20:42 -0700582
583 std::lock_guard<std::mutex> lock(internal_->lock);
584
585 // Setup our advertisement. This has no callback.
Myles Watson911d1ae2016-11-28 16:44:40 -0800586 internal_->gatt->advertiser->SetData(0, false, /* beacon, not scan response */
587 {}, base::Bind(&DoNothing));
588 // transmit_name, /* name */
589 // 2, 2, interval
590 // mutable_manufacturer_data,
591 // mutable_service_data,
592 // id_data);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700593 return true;
594}
595
596bool Server::SetScanResponse(const std::vector<UUID>& ids,
597 const std::vector<uint8_t>& service_data,
598 const std::vector<uint8_t>& manufacturer_data,
599 bool transmit_name) {
Jakub Pawlowski0ecddf32016-10-19 14:46:09 -0700600 // std::vector<uint8_t> id_data;
601 // const auto& mutable_manufacturer_data = manufacturer_data;
602 // const auto& mutable_service_data = service_data;
Arman Uguray0f2d4892015-09-22 14:20:42 -0700603
Jakub Pawlowski0ecddf32016-10-19 14:46:09 -0700604 // for (const UUID &id : ids) {
605 // const auto le_id = id.GetFullLittleEndian();
606 // id_data.insert(id_data.end(), le_id.begin(), le_id.end());
607 // }
Arman Uguray0f2d4892015-09-22 14:20:42 -0700608
609 std::lock_guard<std::mutex> lock(internal_->lock);
610
611 // Setup our advertisement. This has no callback.
Myles Watson911d1ae2016-11-28 16:44:40 -0800612 internal_->gatt->advertiser->SetData(0, true, /* scan response */
613 {}, base::Bind(&DoNothing));
614 // transmit_name, /* name */
615 // false, /* no txpower */
616 // 2, 2, interval
617 // 0, /* appearance */
618 // mutable_manufacturer_data,
619 // mutable_service_data,
620 // id_data);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700621 return true;
622}
623
Myles Watson911d1ae2016-11-28 16:44:40 -0800624bool Server::AddCharacteristic(const UUID& id, int properties,
625 int permissions) {
Arman Uguray0f2d4892015-09-22 14:20:42 -0700626 std::unique_lock<std::mutex> lock(internal_->lock);
Myles Watson911d1ae2016-11-28 16:44:40 -0800627 bt_status_t btstat =
628 internal_->AddCharacteristic(id, properties, permissions);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700629 if (btstat != BT_STATUS_SUCCESS) {
630 LOG_ERROR(LOG_TAG, "Failed to add characteristic to service: 0x%04x",
631 internal_->service_handle);
632 return false;
633 }
634 internal_->api_synchronize.wait(lock);
635 const int handle = internal_->uuid_to_attribute[id];
636 internal_->characteristics[handle].notify = properties & kPropertyNotify;
637 return true;
638}
639
Myles Watson911d1ae2016-11-28 16:44:40 -0800640bool Server::AddBlob(const UUID& id, const UUID& control_id, int properties,
641 int permissions) {
Arman Uguray0f2d4892015-09-22 14:20:42 -0700642 std::unique_lock<std::mutex> lock(internal_->lock);
643
644 // First, add the primary attribute (characteristic value)
Myles Watson911d1ae2016-11-28 16:44:40 -0800645 bt_status_t btstat =
646 internal_->AddCharacteristic(id, properties, permissions);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700647 if (btstat != BT_STATUS_SUCCESS) {
648 LOG_ERROR(LOG_TAG, "Failed to set scan response data");
649 return false;
650 }
651
Arman Uguray0f2d4892015-09-22 14:20:42 -0700652 // Next, add the secondary attribute (blob control).
653 // Control attributes have fixed permissions/properties.
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700654 // Remember position at which blob was added.
655 blob_index.insert(pending_svc_decl.size());
Myles Watson911d1ae2016-11-28 16:44:40 -0800656 btstat =
657 internal_->AddCharacteristic(control_id, kPropertyRead | kPropertyWrite,
658 kPermissionRead | kPermissionWrite);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700659
Arman Uguray0f2d4892015-09-22 14:20:42 -0700660 return true;
661}
662
663bool Server::Start() {
664 std::unique_lock<std::mutex> lock(internal_->lock);
Jakub Pawlowskia641b6f2016-03-26 00:47:23 -0700665 bt_status_t btstat = internal_->gatt->server->add_service(
666 internal_->server_if, pending_svc_decl);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700667 if (btstat != BT_STATUS_SUCCESS) {
668 LOG_ERROR(LOG_TAG, "Failed to start service with handle: 0x%04x",
669 internal_->service_handle);
670 return false;
671 }
672 internal_->api_synchronize.wait(lock);
673 return true;
674}
675
676bool Server::Stop() {
677 std::unique_lock<std::mutex> lock(internal_->lock);
678 bt_status_t btstat = internal_->gatt->server->stop_service(
679 internal_->server_if, internal_->service_handle);
680 if (btstat != BT_STATUS_SUCCESS) {
681 LOG_ERROR(LOG_TAG, "Failed to stop service with handle: 0x%04x",
682 internal_->service_handle);
683 return false;
684 }
685 internal_->api_synchronize.wait(lock);
686 return true;
687}
688
689bool Server::ScanEnable() {
Jakub Pawlowski83f1d962016-12-14 09:49:38 -0800690 internal_->gatt->scanner->Scan(true);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700691 return true;
692}
693
694bool Server::ScanDisable() {
Jakub Pawlowski83f1d962016-12-14 09:49:38 -0800695 internal_->gatt->scanner->Scan(false);
Arman Uguray0f2d4892015-09-22 14:20:42 -0700696 return true;
697}
698
Myles Watson911d1ae2016-11-28 16:44:40 -0800699bool Server::GetScanResults(ScanResults* results) {
Arman Uguray0f2d4892015-09-22 14:20:42 -0700700 std::lock_guard<std::mutex> lock(internal_->lock);
701 *results = internal_->scan_results;
702 return true;
703}
704
Myles Watson911d1ae2016-11-28 16:44:40 -0800705bool Server::SetCharacteristicValue(const UUID& id,
706 const std::vector<uint8_t>& value) {
Arman Uguray0f2d4892015-09-22 14:20:42 -0700707 std::lock_guard<std::mutex> lock(internal_->lock);
708 const int attribute_id = internal_->uuid_to_attribute[id];
Myles Watson911d1ae2016-11-28 16:44:40 -0800709 Characteristic& ch = internal_->characteristics[attribute_id];
Arman Uguray0f2d4892015-09-22 14:20:42 -0700710 ch.next_blob = value;
711 ch.next_blob_pending = true;
712
Myles Watson911d1ae2016-11-28 16:44:40 -0800713 if (!ch.notify) return true;
Arman Uguray0f2d4892015-09-22 14:20:42 -0700714
715 for (auto connection : internal_->connections) {
Myles Watson911d1ae2016-11-28 16:44:40 -0800716 internal_->gatt->server->send_indication(internal_->server_if, attribute_id,
717 connection, true, {0});
Arman Uguray0f2d4892015-09-22 14:20:42 -0700718 }
719 return true;
720}
721
Myles Watson911d1ae2016-11-28 16:44:40 -0800722bool Server::GetCharacteristicValue(const UUID& id,
723 std::vector<uint8_t>* value) {
Arman Uguray0f2d4892015-09-22 14:20:42 -0700724 std::lock_guard<std::mutex> lock(internal_->lock);
725 const int attribute_id = internal_->uuid_to_attribute[id];
726 *value = internal_->characteristics[attribute_id].blob;
727 return true;
728}
729
730} // namespace gatt
731} // namespace bluetooth