xref: /aosp_15_r20/external/pigweed/pw_bluetooth_sapphire/host/gatt/server.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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