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