1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 #include "pw_bluetooth_sapphire/internal/host/gatt/server.h"
16
17 #include <lib/fit/function.h>
18
19 #include "pw_bluetooth_sapphire/internal/host/att/att.h"
20 #include "pw_bluetooth_sapphire/internal/host/att/database.h"
21 #include "pw_bluetooth_sapphire/internal/host/att/permissions.h"
22 #include "pw_bluetooth_sapphire/internal/host/common/assert.h"
23 #include "pw_bluetooth_sapphire/internal/host/common/slab_allocator.h"
24 #include "pw_bluetooth_sapphire/internal/host/common/trace.h"
25 #include "pw_bluetooth_sapphire/internal/host/common/uuid.h"
26 #include "pw_bluetooth_sapphire/internal/host/gatt/gatt_defs.h"
27
28 namespace bt::gatt {
29
30 class AttBasedServer final : public Server {
31 public:
AttBasedServer(PeerId peer_id,LocalServiceManager::WeakPtr local_services,att::Bearer::WeakPtr bearer)32 AttBasedServer(PeerId peer_id,
33 LocalServiceManager::WeakPtr local_services,
34 att::Bearer::WeakPtr bearer)
35 : peer_id_(peer_id),
36 local_services_(std::move(local_services)),
37 att_(std::move(bearer)),
38 weak_self_(this) {
39 BT_ASSERT(local_services_.is_alive());
40 BT_DEBUG_ASSERT(att_.is_alive());
41
42 exchange_mtu_id_ = att_->RegisterHandler(
43 att::kExchangeMTURequest,
44 fit::bind_member<&AttBasedServer::OnExchangeMTU>(this));
45 find_information_id_ = att_->RegisterHandler(
46 att::kFindInformationRequest,
47 fit::bind_member<&AttBasedServer::OnFindInformation>(this));
48 read_by_group_type_id_ = att_->RegisterHandler(
49 att::kReadByGroupTypeRequest,
50 fit::bind_member<&AttBasedServer::OnReadByGroupType>(this));
51 read_by_type_id_ = att_->RegisterHandler(
52 att::kReadByTypeRequest,
53 fit::bind_member<&AttBasedServer::OnReadByType>(this));
54 read_req_id_ = att_->RegisterHandler(
55 att::kReadRequest,
56 fit::bind_member<&AttBasedServer::OnReadRequest>(this));
57 write_req_id_ = att_->RegisterHandler(
58 att::kWriteRequest,
59 fit::bind_member<&AttBasedServer::OnWriteRequest>(this));
60 write_cmd_id_ = att_->RegisterHandler(
61 att::kWriteCommand,
62 fit::bind_member<&AttBasedServer::OnWriteCommand>(this));
63 read_blob_req_id_ = att_->RegisterHandler(
64 att::kReadBlobRequest,
65 fit::bind_member<&AttBasedServer::OnReadBlobRequest>(this));
66 find_by_type_value_id_ = att_->RegisterHandler(
67 att::kFindByTypeValueRequest,
68 fit::bind_member<&AttBasedServer::OnFindByTypeValueRequest>(this));
69 prepare_write_id_ = att_->RegisterHandler(
70 att::kPrepareWriteRequest,
71 fit::bind_member<&AttBasedServer::OnPrepareWriteRequest>(this));
72 exec_write_id_ = att_->RegisterHandler(
73 att::kExecuteWriteRequest,
74 fit::bind_member<&AttBasedServer::OnExecuteWriteRequest>(this));
75 }
76
~AttBasedServer()77 ~AttBasedServer() override {
78 att_->UnregisterHandler(exec_write_id_);
79 att_->UnregisterHandler(prepare_write_id_);
80 att_->UnregisterHandler(find_by_type_value_id_);
81 att_->UnregisterHandler(read_blob_req_id_);
82 att_->UnregisterHandler(write_cmd_id_);
83 att_->UnregisterHandler(write_req_id_);
84 att_->UnregisterHandler(read_req_id_);
85 att_->UnregisterHandler(read_by_type_id_);
86 att_->UnregisterHandler(read_by_group_type_id_);
87 att_->UnregisterHandler(find_information_id_);
88 att_->UnregisterHandler(exchange_mtu_id_);
89 }
90
91 private:
92 // Convenience "alias"
db()93 inline att::Database::WeakPtr db() { return local_services_->database(); }
94
95 // Server overrides:
SendUpdate(IdType service_id,IdType chrc_id,BufferView value,IndicationCallback indicate_cb)96 void SendUpdate(IdType service_id,
97 IdType chrc_id,
98 BufferView value,
99 IndicationCallback indicate_cb) override {
100 auto buffer =
101 NewBuffer(sizeof(att::Header) + sizeof(att::Handle) + value.size());
102 BT_ASSERT(buffer);
103
104 LocalServiceManager::ClientCharacteristicConfig config;
105 if (!local_services_->GetCharacteristicConfig(
106 service_id, chrc_id, peer_id_, &config)) {
107 bt_log(TRACE,
108 "gatt",
109 "peer has not configured characteristic: %s",
110 bt_str(peer_id_));
111 if (indicate_cb) {
112 indicate_cb(ToResult(HostError::kNotSupported));
113 }
114 return;
115 }
116
117 // Make sure that the client has subscribed to the requested protocol
118 // method.
119 if ((indicate_cb && !config.indicate) || (!indicate_cb && !config.notify)) {
120 bt_log(TRACE,
121 "gatt",
122 "peer has not enabled (%s): %s",
123 (indicate_cb ? "indications" : "notifications"),
124 bt_str(peer_id_));
125 if (indicate_cb) {
126 indicate_cb(ToResult(HostError::kNotSupported));
127 }
128 return;
129 }
130
131 att::PacketWriter writer(
132 indicate_cb ? att::kIndication : att::kNotification, buffer.get());
133 auto rsp_params = writer.mutable_payload<att::AttributeData>();
134 rsp_params->handle = htole16(config.handle);
135 writer.mutable_payload_data().Write(value, sizeof(att::AttributeData));
136
137 if (!indicate_cb) {
138 [[maybe_unused]] bool _ = att_->SendWithoutResponse(std::move(buffer));
139 return;
140 }
141 auto transaction_cb = [indicate_cb = std::move(indicate_cb)](
142 att::Bearer::TransactionResult result) mutable {
143 if (result.is_ok()) {
144 bt_log(DEBUG, "gatt", "got indication ACK");
145 indicate_cb(fit::ok());
146 } else {
147 const auto& [error, handle] = result.error_value();
148 bt_log(WARN,
149 "gatt",
150 "indication failed (error %s, handle: %#.4x)",
151 bt_str(error),
152 handle);
153 indicate_cb(fit::error(error));
154 }
155 };
156 att_->StartTransaction(std::move(buffer), std::move(transaction_cb));
157 }
158
ShutDown()159 void ShutDown() override { att_->ShutDown(); }
160
161 // ATT protocol request handlers:
OnExchangeMTU(att::Bearer::TransactionId tid,const att::PacketReader & packet)162 void OnExchangeMTU(att::Bearer::TransactionId tid,
163 const att::PacketReader& packet) {
164 BT_DEBUG_ASSERT(packet.opcode() == att::kExchangeMTURequest);
165
166 if (packet.payload_size() != sizeof(att::ExchangeMTURequestParams)) {
167 att_->ReplyWithError(
168 tid, att::kInvalidHandle, att::ErrorCode::kInvalidPDU);
169 return;
170 }
171
172 const auto& params = packet.payload<att::ExchangeMTURequestParams>();
173 uint16_t client_mtu = le16toh(params.client_rx_mtu);
174 uint16_t server_mtu = att_->preferred_mtu();
175
176 auto buffer =
177 NewBuffer(sizeof(att::Header) + sizeof(att::ExchangeMTUResponseParams));
178 BT_ASSERT(buffer);
179
180 att::PacketWriter writer(att::kExchangeMTUResponse, buffer.get());
181 auto rsp_params = writer.mutable_payload<att::ExchangeMTUResponseParams>();
182 rsp_params->server_rx_mtu = htole16(server_mtu);
183
184 att_->Reply(tid, std::move(buffer));
185
186 // If the minimum value is less than the default MTU, then go with the
187 // default MTU (Vol 3, Part F, 3.4.2.2).
188 // TODO(armansito): This needs to use on kBREDRMinATTMTU for BR/EDR. Make
189 // the default MTU configurable.
190 att_->set_mtu(std::max(att::kLEMinMTU, std::min(client_mtu, server_mtu)));
191 }
192
OnFindInformation(att::Bearer::TransactionId tid,const att::PacketReader & packet)193 void OnFindInformation(att::Bearer::TransactionId tid,
194 const att::PacketReader& packet) {
195 BT_DEBUG_ASSERT(packet.opcode() == att::kFindInformationRequest);
196 TRACE_DURATION("bluetooth", "gatt::Server::OnFindInformation");
197
198 if (packet.payload_size() != sizeof(att::FindInformationRequestParams)) {
199 att_->ReplyWithError(
200 tid, att::kInvalidHandle, att::ErrorCode::kInvalidPDU);
201 return;
202 }
203
204 const auto& params = packet.payload<att::FindInformationRequestParams>();
205 att::Handle start = le16toh(params.start_handle);
206 att::Handle end = le16toh(params.end_handle);
207
208 constexpr size_t kRspStructSize =
209 sizeof(att::FindInformationResponseParams);
210 constexpr size_t kHeaderSize = sizeof(att::Header) + kRspStructSize;
211 BT_DEBUG_ASSERT(kHeaderSize <= att_->mtu());
212
213 if (start == att::kInvalidHandle || start > end) {
214 att_->ReplyWithError(tid, start, att::ErrorCode::kInvalidHandle);
215 return;
216 }
217
218 // Find all attributes within range with the same compact UUID size that can
219 // fit within the current MTU.
220 size_t max_payload_size = att_->mtu() - kHeaderSize;
221 size_t uuid_size;
222 size_t entry_size;
223 std::list<const att::Attribute*> results;
224 for (auto it = db()->GetIterator(start, end); !it.AtEnd(); it.Advance()) {
225 const auto* attr = it.get();
226 BT_DEBUG_ASSERT(attr);
227
228 // GATT does not allow 32-bit UUIDs
229 size_t compact_size = attr->type().CompactSize(/*allow_32bit=*/false);
230 if (results.empty()) {
231 // |uuid_size| is determined by the first attribute.
232 uuid_size = compact_size;
233 entry_size =
234 std::min(uuid_size + sizeof(att::Handle), max_payload_size);
235 } else if (compact_size != uuid_size || entry_size > max_payload_size) {
236 break;
237 }
238
239 results.push_back(attr);
240 max_payload_size -= entry_size;
241 }
242
243 if (results.empty()) {
244 att_->ReplyWithError(tid, start, att::ErrorCode::kAttributeNotFound);
245 return;
246 }
247
248 BT_DEBUG_ASSERT(!results.empty());
249
250 size_t pdu_size = kHeaderSize + entry_size * results.size();
251
252 auto buffer = NewBuffer(pdu_size);
253 BT_ASSERT(buffer);
254
255 att::PacketWriter writer(att::kFindInformationResponse, buffer.get());
256 auto rsp_params =
257 writer.mutable_payload<att::FindInformationResponseParams>();
258 rsp_params->format =
259 (entry_size == 4) ? att::UUIDType::k16Bit : att::UUIDType::k128Bit;
260
261 // |out_entries| initially references |params->information_data|. The loop
262 // below modifies it as entries are written into the list.
263 auto out_entries =
264 writer.mutable_payload_data().mutable_view(kRspStructSize);
265 for (const auto& attr : results) {
266 *reinterpret_cast<att::Handle*>(out_entries.mutable_data()) =
267 htole16(attr->handle());
268 auto uuid_view = out_entries.mutable_view(sizeof(att::Handle));
269 attr->type().ToBytes(&uuid_view, /*allow_32bit=*/false);
270
271 // advance
272 out_entries = out_entries.mutable_view(entry_size);
273 }
274
275 att_->Reply(tid, std::move(buffer));
276 }
277
OnFindByTypeValueRequest(att::Bearer::TransactionId tid,const att::PacketReader & packet)278 void OnFindByTypeValueRequest(att::Bearer::TransactionId tid,
279 const att::PacketReader& packet) {
280 BT_DEBUG_ASSERT(packet.opcode() == att::kFindByTypeValueRequest);
281
282 if (packet.payload_size() < sizeof(att::FindByTypeValueRequestParams)) {
283 att_->ReplyWithError(
284 tid, att::kInvalidHandle, att::ErrorCode::kInvalidPDU);
285 return;
286 }
287
288 const auto& params = packet.payload<att::FindByTypeValueRequestParams>();
289 att::Handle start = le16toh(params.start_handle);
290 att::Handle end = le16toh(params.end_handle);
291 UUID type(params.type);
292 constexpr size_t kParamsSize = sizeof(att::FindByTypeValueRequestParams);
293
294 BufferView value = packet.payload_data().view(
295 kParamsSize, packet.payload_size() - kParamsSize);
296
297 if (start == att::kInvalidHandle || start > end) {
298 att_->ReplyWithError(
299 tid, att::kInvalidHandle, att::ErrorCode::kInvalidHandle);
300 return;
301 }
302
303 auto iter = db()->GetIterator(start, end, &type, /*groups_only=*/false);
304 if (iter.AtEnd()) {
305 att_->ReplyWithError(
306 tid, att::kInvalidHandle, att::ErrorCode::kAttributeNotFound);
307 return;
308 }
309
310 std::list<const att::Attribute*> results;
311
312 // Filter for identical values
313 for (; !iter.AtEnd(); iter.Advance()) {
314 const auto* attr = iter.get();
315 BT_DEBUG_ASSERT(attr);
316
317 // Only support static values for this Request type
318 if (attr->value()) {
319 if (*attr->value() == value) {
320 results.push_back(attr);
321 }
322 }
323 }
324
325 // No attributes match the value
326 if (results.size() == 0) {
327 att_->ReplyWithError(
328 tid, att::kInvalidHandle, att::ErrorCode::kAttributeNotFound);
329 return;
330 }
331
332 constexpr size_t kRspStructSize = sizeof(att::HandlesInformationList);
333 size_t pdu_size = sizeof(att::Header) + kRspStructSize * results.size();
334 auto buffer = NewBuffer(pdu_size);
335 BT_ASSERT(buffer);
336
337 att::PacketWriter writer(att::kFindByTypeValueResponse, buffer.get());
338
339 // Points to the next entry in the target PDU.
340 auto next_entry = writer.mutable_payload_data();
341 for (const auto& attr : results) {
342 auto* entry = reinterpret_cast<att::HandlesInformationList*>(
343 next_entry.mutable_data());
344 entry->handle = htole16(attr->handle());
345 if (attr->group().active()) {
346 entry->group_end_handle = htole16(attr->group().end_handle());
347 } else {
348 entry->group_end_handle = htole16(attr->handle());
349 }
350 next_entry = next_entry.mutable_view(kRspStructSize);
351 }
352
353 att_->Reply(tid, std::move(buffer));
354 }
355
OnReadByGroupType(att::Bearer::TransactionId tid,const att::PacketReader & packet)356 void OnReadByGroupType(att::Bearer::TransactionId tid,
357 const att::PacketReader& packet) {
358 BT_DEBUG_ASSERT(packet.opcode() == att::kReadByGroupTypeRequest);
359 TRACE_DURATION("bluetooth", "gatt::Server::OnReadByGroupType");
360
361 att::Handle start, end;
362 UUID group_type;
363
364 // The group type is represented as either a 16-bit or 128-bit UUID.
365 if (packet.payload_size() == sizeof(att::ReadByTypeRequestParams16)) {
366 const auto& params = packet.payload<att::ReadByTypeRequestParams16>();
367 start = le16toh(params.start_handle);
368 end = le16toh(params.end_handle);
369 group_type = UUID(le16toh(params.type));
370 } else if (packet.payload_size() ==
371 sizeof(att::ReadByTypeRequestParams128)) {
372 const auto& params = packet.payload<att::ReadByTypeRequestParams128>();
373 start = le16toh(params.start_handle);
374 end = le16toh(params.end_handle);
375 group_type = UUID(params.type);
376 } else {
377 att_->ReplyWithError(
378 tid, att::kInvalidHandle, att::ErrorCode::kInvalidPDU);
379 return;
380 }
381
382 if (group_type != types::kPrimaryService &&
383 group_type != types::kSecondaryService) {
384 att_->ReplyWithError(tid, start, att::ErrorCode::kUnsupportedGroupType);
385 return;
386 }
387
388 constexpr size_t kRspStructSize =
389 sizeof(att::ReadByGroupTypeResponseParams);
390 constexpr size_t kHeaderSize = sizeof(att::Header) + kRspStructSize;
391 BT_DEBUG_ASSERT(kHeaderSize <= att_->mtu());
392
393 size_t value_size;
394 std::list<const att::Attribute*> results;
395 fit::result<att::ErrorCode> status =
396 ReadByTypeHelper(start,
397 end,
398 group_type,
399 /*group_type=*/true,
400 att_->mtu() - kHeaderSize,
401 att::kMaxReadByGroupTypeValueLength,
402 sizeof(att::AttributeGroupDataEntry),
403 &value_size,
404 &results);
405 if (status.is_error()) {
406 att_->ReplyWithError(tid, start, status.error_value());
407 return;
408 }
409
410 BT_DEBUG_ASSERT(!results.empty());
411
412 size_t entry_size = value_size + sizeof(att::AttributeGroupDataEntry);
413 size_t pdu_size = kHeaderSize + entry_size * results.size();
414 BT_DEBUG_ASSERT(pdu_size <= att_->mtu());
415
416 auto buffer = NewBuffer(pdu_size);
417 BT_ASSERT(buffer);
418
419 att::PacketWriter writer(att::kReadByGroupTypeResponse, buffer.get());
420 auto params = writer.mutable_payload<att::ReadByGroupTypeResponseParams>();
421
422 BT_DEBUG_ASSERT(entry_size <= std::numeric_limits<uint8_t>::max());
423 params->length = static_cast<uint8_t>(entry_size);
424
425 // Points to the next entry in the target PDU.
426 auto next_entry =
427 writer.mutable_payload_data().mutable_view(kRspStructSize);
428 for (const auto& attr : results) {
429 auto* entry = reinterpret_cast<att::AttributeGroupDataEntry*>(
430 next_entry.mutable_data());
431 entry->start_handle = htole16(attr->group().start_handle());
432 entry->group_end_handle = htole16(attr->group().end_handle());
433 next_entry.Write(attr->group().decl_value().view(0, value_size),
434 sizeof(att::AttributeGroupDataEntry));
435
436 next_entry = next_entry.mutable_view(entry_size);
437 }
438
439 att_->Reply(tid, std::move(buffer));
440 }
441
OnReadByType(att::Bearer::TransactionId tid,const att::PacketReader & packet)442 void OnReadByType(att::Bearer::TransactionId tid,
443 const att::PacketReader& packet) {
444 BT_DEBUG_ASSERT(packet.opcode() == att::kReadByTypeRequest);
445 TRACE_DURATION("bluetooth", "gatt::Server::OnReadByType");
446
447 att::Handle start, end;
448 UUID type;
449
450 // The attribute type is represented as either a 16-bit or 128-bit UUID.
451 if (packet.payload_size() == sizeof(att::ReadByTypeRequestParams16)) {
452 const auto& params = packet.payload<att::ReadByTypeRequestParams16>();
453 start = le16toh(params.start_handle);
454 end = le16toh(params.end_handle);
455 type = UUID(le16toh(params.type));
456 } else if (packet.payload_size() ==
457 sizeof(att::ReadByTypeRequestParams128)) {
458 const auto& params = packet.payload<att::ReadByTypeRequestParams128>();
459 start = le16toh(params.start_handle);
460 end = le16toh(params.end_handle);
461 type = UUID(params.type);
462 } else {
463 att_->ReplyWithError(
464 tid, att::kInvalidHandle, att::ErrorCode::kInvalidPDU);
465 return;
466 }
467
468 constexpr size_t kRspStructSize = sizeof(att::ReadByTypeResponseParams);
469 constexpr size_t kHeaderSize = sizeof(att::Header) + kRspStructSize;
470 BT_DEBUG_ASSERT(kHeaderSize <= att_->mtu());
471
472 size_t value_size;
473 std::list<const att::Attribute*> results;
474 fit::result<att::ErrorCode> status =
475 ReadByTypeHelper(start,
476 end,
477 type,
478 /*group_type=*/false,
479 att_->mtu() - kHeaderSize,
480 att::kMaxReadByTypeValueLength,
481 sizeof(att::AttributeData),
482 &value_size,
483 &results);
484 if (status.is_error()) {
485 att_->ReplyWithError(tid, start, status.error_value());
486 return;
487 }
488
489 BT_DEBUG_ASSERT(!results.empty());
490
491 // If the value is dynamic, then delegate the read to any registered
492 // handler.
493 if (!results.front()->value()) {
494 BT_DEBUG_ASSERT(results.size() == 1u);
495
496 const size_t kMaxValueSize =
497 std::min(att_->mtu() - kHeaderSize - sizeof(att::AttributeData),
498 static_cast<size_t>(att::kMaxReadByTypeValueLength));
499
500 att::Handle handle = results.front()->handle();
501 auto self = weak_self_.GetWeakPtr();
502 auto result_cb = [self, tid, handle, kMaxValueSize](
503 fit::result<att::ErrorCode> status,
504 const auto& value) {
505 if (!self.is_alive())
506 return;
507
508 if (status.is_error()) {
509 self->att_->ReplyWithError(tid, handle, status.error_value());
510 return;
511 }
512
513 // Respond with just a single entry.
514 size_t value_size = std::min(value.size(), kMaxValueSize);
515 size_t entry_size = value_size + sizeof(att::AttributeData);
516 auto buffer = NewBuffer(entry_size + kHeaderSize);
517 att::PacketWriter writer(att::kReadByTypeResponse, buffer.get());
518
519 auto params = writer.mutable_payload<att::ReadByTypeResponseParams>();
520 params->length = static_cast<uint8_t>(entry_size);
521 params->attribute_data_list->handle = htole16(handle);
522 writer.mutable_payload_data().Write(
523 value.data(), value_size, sizeof(params->length) + sizeof(handle));
524
525 self->att_->Reply(tid, std::move(buffer));
526 };
527
528 // Respond with an error if no read handler was registered.
529 if (!results.front()->ReadAsync(peer_id_, 0, result_cb)) {
530 att_->ReplyWithError(tid, handle, att::ErrorCode::kReadNotPermitted);
531 }
532 return;
533 }
534
535 size_t entry_size = sizeof(att::AttributeData) + value_size;
536 BT_DEBUG_ASSERT(entry_size <= std::numeric_limits<uint8_t>::max());
537
538 size_t pdu_size = kHeaderSize + entry_size * results.size();
539 BT_DEBUG_ASSERT(pdu_size <= att_->mtu());
540
541 auto buffer = NewBuffer(pdu_size);
542 BT_ASSERT(buffer);
543
544 att::PacketWriter writer(att::kReadByTypeResponse, buffer.get());
545 auto params = writer.mutable_payload<att::ReadByTypeResponseParams>();
546 params->length = static_cast<uint8_t>(entry_size);
547
548 // Points to the next entry in the target PDU.
549 auto next_entry =
550 writer.mutable_payload_data().mutable_view(kRspStructSize);
551 for (const auto& attr : results) {
552 auto* entry =
553 reinterpret_cast<att::AttributeData*>(next_entry.mutable_data());
554 entry->handle = htole16(attr->handle());
555 next_entry.Write(attr->value()->view(0, value_size),
556 sizeof(entry->handle));
557
558 next_entry = next_entry.mutable_view(entry_size);
559 }
560
561 att_->Reply(tid, std::move(buffer));
562 }
563
OnReadBlobRequest(att::Bearer::TransactionId tid,const att::PacketReader & packet)564 void OnReadBlobRequest(att::Bearer::TransactionId tid,
565 const att::PacketReader& packet) {
566 BT_DEBUG_ASSERT(packet.opcode() == att::kReadBlobRequest);
567
568 if (packet.payload_size() != sizeof(att::ReadBlobRequestParams)) {
569 att_->ReplyWithError(
570 tid, att::kInvalidHandle, att::ErrorCode::kInvalidPDU);
571 return;
572 }
573
574 const auto& params = packet.payload<att::ReadBlobRequestParams>();
575 att::Handle handle = le16toh(params.handle);
576 uint16_t offset = le16toh(params.offset);
577
578 const auto* attr = db()->FindAttribute(handle);
579 if (!attr) {
580 att_->ReplyWithError(tid, handle, att::ErrorCode::kInvalidHandle);
581 return;
582 }
583
584 fit::result<att::ErrorCode> status =
585 att::CheckReadPermissions(attr->read_reqs(), att_->security());
586 if (status.is_error()) {
587 att_->ReplyWithError(tid, handle, status.error_value());
588 return;
589 }
590
591 constexpr size_t kHeaderSize = sizeof(att::Header);
592
593 auto self = weak_self_.GetWeakPtr();
594 auto callback = [self, tid, handle](fit::result<att::ErrorCode> status,
595 const auto& value) {
596 if (!self.is_alive())
597 return;
598
599 if (status.is_error()) {
600 self->att_->ReplyWithError(tid, handle, status.error_value());
601 return;
602 }
603
604 size_t value_size =
605 std::min(value.size(), self->att_->mtu() - kHeaderSize);
606 auto buffer = NewBuffer(value_size + kHeaderSize);
607 BT_ASSERT(buffer);
608
609 att::PacketWriter writer(att::kReadBlobResponse, buffer.get());
610 writer.mutable_payload_data().Write(value.view(0, value_size));
611
612 self->att_->Reply(tid, std::move(buffer));
613 };
614
615 // Use the cached value if there is one.
616 if (attr->value()) {
617 if (offset >= attr->value()->size()) {
618 att_->ReplyWithError(tid, handle, att::ErrorCode::kInvalidOffset);
619 return;
620 }
621 size_t value_size =
622 std::min(attr->value()->size(), self->att_->mtu() - kHeaderSize);
623 callback(fit::ok(), attr->value()->view(offset, value_size));
624 return;
625 }
626
627 // TODO(fxbug.dev/42142121): Add a timeout to this
628 if (!attr->ReadAsync(peer_id_, offset, callback)) {
629 att_->ReplyWithError(tid, handle, att::ErrorCode::kReadNotPermitted);
630 }
631 }
632
OnReadRequest(att::Bearer::TransactionId tid,const att::PacketReader & packet)633 void OnReadRequest(att::Bearer::TransactionId tid,
634 const att::PacketReader& packet) {
635 BT_DEBUG_ASSERT(packet.opcode() == att::kReadRequest);
636
637 if (packet.payload_size() != sizeof(att::ReadRequestParams)) {
638 att_->ReplyWithError(
639 tid, att::kInvalidHandle, att::ErrorCode::kInvalidPDU);
640 return;
641 }
642
643 const auto& params = packet.payload<att::WriteRequestParams>();
644 att::Handle handle = le16toh(params.handle);
645
646 const auto* attr = db()->FindAttribute(handle);
647 if (!attr) {
648 att_->ReplyWithError(tid, handle, att::ErrorCode::kInvalidHandle);
649 return;
650 }
651
652 fit::result<att::ErrorCode> status =
653 att::CheckReadPermissions(attr->read_reqs(), att_->security());
654 if (status.is_error()) {
655 att_->ReplyWithError(tid, handle, status.error_value());
656 return;
657 }
658
659 constexpr size_t kHeaderSize = sizeof(att::Header);
660
661 auto self = weak_self_.GetWeakPtr();
662 auto callback = [self, tid, handle](fit::result<att::ErrorCode> status,
663 const auto& value) {
664 if (!self.is_alive())
665 return;
666
667 if (status.is_error()) {
668 self->att_->ReplyWithError(tid, handle, status.error_value());
669 return;
670 }
671
672 size_t value_size =
673 std::min(value.size(), self->att_->mtu() - kHeaderSize);
674 auto buffer = NewBuffer(value_size + kHeaderSize);
675 BT_ASSERT(buffer);
676
677 att::PacketWriter writer(att::kReadResponse, buffer.get());
678 writer.mutable_payload_data().Write(value.view(0, value_size));
679
680 self->att_->Reply(tid, std::move(buffer));
681 };
682
683 // Use the cached value if there is one.
684 if (attr->value()) {
685 callback(fit::ok(), *attr->value());
686 return;
687 }
688
689 if (!attr->ReadAsync(peer_id_, 0, callback)) {
690 att_->ReplyWithError(tid, handle, att::ErrorCode::kReadNotPermitted);
691 }
692 }
693
OnWriteCommand(att::Bearer::TransactionId tid,const att::PacketReader & packet)694 void OnWriteCommand(att::Bearer::TransactionId tid,
695 const att::PacketReader& packet) {
696 BT_DEBUG_ASSERT(packet.opcode() == att::kWriteCommand);
697
698 if (packet.payload_size() < sizeof(att::WriteRequestParams)) {
699 // Ignore if wrong size, no response allowed
700 return;
701 }
702
703 const auto& params = packet.payload<att::WriteRequestParams>();
704 att::Handle handle = le16toh(params.handle);
705 const auto* attr = db()->FindAttribute(handle);
706
707 // Attributes can be invalid if the handle is invalid
708 if (!attr) {
709 return;
710 }
711
712 fit::result<att::ErrorCode> status =
713 att::CheckWritePermissions(attr->write_reqs(), att_->security());
714 if (status.is_error()) {
715 return;
716 }
717
718 // Attributes with a static value cannot be written.
719 if (attr->value()) {
720 return;
721 }
722
723 auto value_view = packet.payload_data().view(sizeof(params.handle));
724 if (value_view.size() > att::kMaxAttributeValueLength) {
725 return;
726 }
727
728 // No response allowed for commands, ignore the cb
729 attr->WriteAsync(peer_id_, 0, value_view, nullptr);
730 }
731
OnWriteRequest(att::Bearer::TransactionId tid,const att::PacketReader & packet)732 void OnWriteRequest(att::Bearer::TransactionId tid,
733 const att::PacketReader& packet) {
734 BT_DEBUG_ASSERT(packet.opcode() == att::kWriteRequest);
735
736 if (packet.payload_size() < sizeof(att::WriteRequestParams)) {
737 att_->ReplyWithError(
738 tid, att::kInvalidHandle, att::ErrorCode::kInvalidPDU);
739 return;
740 }
741
742 const auto& params = packet.payload<att::WriteRequestParams>();
743 att::Handle handle = le16toh(params.handle);
744
745 const auto* attr = db()->FindAttribute(handle);
746 if (!attr) {
747 att_->ReplyWithError(tid, handle, att::ErrorCode::kInvalidHandle);
748 return;
749 }
750
751 fit::result<att::ErrorCode> status =
752 att::CheckWritePermissions(attr->write_reqs(), att_->security());
753 if (status.is_error()) {
754 att_->ReplyWithError(tid, handle, status.error_value());
755 return;
756 }
757
758 // Attributes with a static value cannot be written.
759 if (attr->value()) {
760 att_->ReplyWithError(tid, handle, att::ErrorCode::kWriteNotPermitted);
761 return;
762 }
763
764 auto value_view = packet.payload_data().view(sizeof(params.handle));
765 if (value_view.size() > att::kMaxAttributeValueLength) {
766 att_->ReplyWithError(
767 tid, handle, att::ErrorCode::kInvalidAttributeValueLength);
768 return;
769 }
770
771 auto self = weak_self_.GetWeakPtr();
772 auto result_cb = [self, tid, handle](fit::result<att::ErrorCode> status) {
773 if (!self.is_alive())
774 return;
775
776 if (status.is_error()) {
777 self->att_->ReplyWithError(tid, handle, status.error_value());
778 return;
779 }
780
781 auto buffer = NewBuffer(1);
782 (*buffer)[0] = att::kWriteResponse;
783 self->att_->Reply(tid, std::move(buffer));
784 };
785
786 if (!attr->WriteAsync(peer_id_, 0, value_view, result_cb)) {
787 att_->ReplyWithError(tid, handle, att::ErrorCode::kWriteNotPermitted);
788 }
789 }
790
OnPrepareWriteRequest(att::Bearer::TransactionId tid,const att::PacketReader & packet)791 void OnPrepareWriteRequest(att::Bearer::TransactionId tid,
792 const att::PacketReader& packet) {
793 BT_DEBUG_ASSERT(packet.opcode() == att::kPrepareWriteRequest);
794
795 if (packet.payload_size() < sizeof(att::PrepareWriteRequestParams)) {
796 att_->ReplyWithError(
797 tid, att::kInvalidHandle, att::ErrorCode::kInvalidPDU);
798 return;
799 }
800
801 const auto& params = packet.payload<att::PrepareWriteRequestParams>();
802 att::Handle handle = le16toh(params.handle);
803 uint16_t offset = le16toh(params.offset);
804 auto value_view = packet.payload_data().view(sizeof(params.handle) +
805 sizeof(params.offset));
806
807 if (prepare_queue_.size() >= att::kPrepareQueueMaxCapacity) {
808 att_->ReplyWithError(tid, handle, att::ErrorCode::kPrepareQueueFull);
809 return;
810 }
811
812 // Validate attribute handle and perform security checks (see Vol 3, Part F,
813 // 3.4.6.1 for required checks)
814 const auto* attr = db()->FindAttribute(handle);
815 if (!attr) {
816 att_->ReplyWithError(tid, handle, att::ErrorCode::kInvalidHandle);
817 return;
818 }
819
820 fit::result<att::ErrorCode> status =
821 att::CheckWritePermissions(attr->write_reqs(), att_->security());
822 if (status.is_error()) {
823 att_->ReplyWithError(tid, handle, status.error_value());
824 return;
825 }
826
827 prepare_queue_.push(att::QueuedWrite(handle, offset, value_view));
828
829 // Reply back with the request payload.
830 auto buffer = std::make_unique<DynamicByteBuffer>(packet.size());
831 att::PacketWriter writer(att::kPrepareWriteResponse, buffer.get());
832 writer.mutable_payload_data().Write(packet.payload_data());
833
834 att_->Reply(tid, std::move(buffer));
835 }
836
OnExecuteWriteRequest(att::Bearer::TransactionId tid,const att::PacketReader & packet)837 void OnExecuteWriteRequest(att::Bearer::TransactionId tid,
838 const att::PacketReader& packet) {
839 BT_DEBUG_ASSERT(packet.opcode() == att::kExecuteWriteRequest);
840
841 if (packet.payload_size() != sizeof(att::ExecuteWriteRequestParams)) {
842 att_->ReplyWithError(
843 tid, att::kInvalidHandle, att::ErrorCode::kInvalidPDU);
844 return;
845 }
846
847 const auto& params = packet.payload<att::ExecuteWriteRequestParams>();
848 if (params.flags == att::ExecuteWriteFlag::kCancelAll) {
849 prepare_queue_ = {};
850
851 auto buffer = std::make_unique<DynamicByteBuffer>(1);
852 att::PacketWriter writer(att::kExecuteWriteResponse, buffer.get());
853 att_->Reply(tid, std::move(buffer));
854 return;
855 }
856
857 if (params.flags != att::ExecuteWriteFlag::kWritePending) {
858 att_->ReplyWithError(
859 tid, att::kInvalidHandle, att::ErrorCode::kInvalidPDU);
860 return;
861 }
862
863 auto self = weak_self_.GetWeakPtr();
864 auto result_cb = [self,
865 tid](fit::result<std::tuple<att::Handle, att::ErrorCode>>
866 result) mutable {
867 if (!self.is_alive())
868 return;
869
870 if (result.is_error()) {
871 auto [handle, ecode] = result.error_value();
872 self->att_->ReplyWithError(tid, handle, ecode);
873 return;
874 }
875
876 auto rsp = std::make_unique<DynamicByteBuffer>(1);
877 att::PacketWriter writer(att::kExecuteWriteResponse, rsp.get());
878 self->att_->Reply(tid, std::move(rsp));
879 };
880 db()->ExecuteWriteQueue(peer_id_,
881 std::move(prepare_queue_),
882 att_->security(),
883 std::move(result_cb));
884 }
885
886 // Helper function to serve the Read By Type and Read By Group Type requests.
887 // This searches |db| for attributes with the given |type| and adds as many
888 // attributes as it can fit within the given |max_data_list_size|. The
889 // attribute value that should be included within each attribute data list
890 // entry is returned in |out_value_size|.
891 //
892 // If the result is a dynamic attribute, |out_results| will contain at most
893 // one entry. |out_value_size| will point to an undefined value in that case.
894 //
895 // On error, returns an error code that can be used in a ATT Error Response.
ReadByTypeHelper(att::Handle start,att::Handle end,const UUID & type,bool group_type,size_t max_data_list_size,size_t max_value_size,size_t entry_prefix_size,size_t * out_value_size,std::list<const att::Attribute * > * out_results)896 fit::result<att::ErrorCode> ReadByTypeHelper(
897 att::Handle start,
898 att::Handle end,
899 const UUID& type,
900 bool group_type,
901 size_t max_data_list_size,
902 size_t max_value_size,
903 size_t entry_prefix_size,
904 size_t* out_value_size,
905 std::list<const att::Attribute*>* out_results) {
906 BT_DEBUG_ASSERT(out_results);
907 BT_DEBUG_ASSERT(out_value_size);
908
909 if (start == att::kInvalidHandle || start > end)
910 return fit::error(att::ErrorCode::kInvalidHandle);
911
912 auto iter = db()->GetIterator(start, end, &type, group_type);
913 if (iter.AtEnd())
914 return fit::error(att::ErrorCode::kAttributeNotFound);
915
916 // |value_size| is the size of the complete attribute value for each result
917 // entry. |entry_size| = |value_size| + |entry_prefix_size|. We store these
918 // separately to avoid recalculating one every it gets checked.
919 size_t value_size;
920 size_t entry_size;
921 std::list<const att::Attribute*> results;
922
923 for (; !iter.AtEnd(); iter.Advance()) {
924 const auto* attr = iter.get();
925 BT_DEBUG_ASSERT(attr);
926
927 fit::result<att::ErrorCode> security_result =
928 att::CheckReadPermissions(attr->read_reqs(), att_->security());
929 if (security_result.is_error()) {
930 // Return error only if this is the first result that matched. We simply
931 // stop the search otherwise.
932 if (results.empty()) {
933 return security_result;
934 }
935 break;
936 }
937
938 // The first result determines |value_size| and |entry_size|.
939 if (results.empty()) {
940 if (!attr->value()) {
941 // If the first value is dynamic then this is the only attribute that
942 // this call will return. No need to calculate the value size.
943 results.push_back(attr);
944 break;
945 }
946
947 value_size = attr->value()->size(); // untruncated value size
948 entry_size =
949 std::min(std::min(value_size, max_value_size) + entry_prefix_size,
950 max_data_list_size);
951
952 // Actual value size to include in a PDU.
953 *out_value_size = entry_size - entry_prefix_size;
954
955 } else if (!attr->value() || attr->value()->size() != value_size ||
956 entry_size > max_data_list_size) {
957 // Stop the search and exclude this attribute because either:
958 // a. we ran into a dynamic value in a result that contains static
959 // values, b. the matching attribute has a different value size than the
960 // first
961 // attribute,
962 // c. there is no remaining space in the response PDU.
963 break;
964 }
965
966 results.push_back(attr);
967 max_data_list_size -= entry_size;
968 }
969
970 if (results.empty())
971 return fit::error(att::ErrorCode::kAttributeNotFound);
972
973 *out_results = std::move(results);
974 return fit::ok();
975 }
976
977 PeerId peer_id_;
978 LocalServiceManager::WeakPtr local_services_;
979 att::Bearer::WeakPtr att_;
980
981 // The queue data structure used for queued writes (see Vol 3, Part F, 3.4.6).
982 att::PrepareWriteQueue prepare_queue_;
983
984 // ATT protocol request handler IDs
985 // TODO(armansito): Storing all these IDs here feels wasteful. Provide a way
986 // to unregister GATT server callbacks collectively from an att::Bearer, given
987 // that it's server-role functionalities are uniquely handled by this class.
988 att::Bearer::HandlerId exchange_mtu_id_;
989 att::Bearer::HandlerId find_information_id_;
990 att::Bearer::HandlerId read_by_group_type_id_;
991 att::Bearer::HandlerId read_by_type_id_;
992 att::Bearer::HandlerId read_req_id_;
993 att::Bearer::HandlerId write_req_id_;
994 att::Bearer::HandlerId write_cmd_id_;
995 att::Bearer::HandlerId read_blob_req_id_;
996 att::Bearer::HandlerId find_by_type_value_id_;
997 att::Bearer::HandlerId prepare_write_id_;
998 att::Bearer::HandlerId exec_write_id_;
999
1000 WeakSelf<AttBasedServer> weak_self_;
1001
1002 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(AttBasedServer);
1003 };
1004
1005 // static
Create(PeerId peer_id,LocalServiceManager::WeakPtr local_services,att::Bearer::WeakPtr bearer)1006 std::unique_ptr<Server> Server::Create(
1007 PeerId peer_id,
1008 LocalServiceManager::WeakPtr local_services,
1009 att::Bearer::WeakPtr bearer) {
1010 return std::make_unique<AttBasedServer>(
1011 peer_id, std::move(local_services), std::move(bearer));
1012 }
1013 } // namespace bt::gatt
1014