xref: /aosp_15_r20/external/pigweed/pw_bluetooth_proxy/gatt_notify_channel.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2024 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_proxy/gatt_notify_channel.h"
16 
17 #include "pw_bluetooth/att.emb.h"
18 #include "pw_bluetooth/emboss_util.h"
19 #include "pw_bluetooth/l2cap_frames.emb.h"
20 #include "pw_log/log.h"
21 #include "pw_status/try.h"
22 
23 namespace pw::bluetooth::proxy {
Write(pw::span<const uint8_t> attribute_value)24 pw::Status GattNotifyChannel::Write(pw::span<const uint8_t> attribute_value) {
25   const uint16_t max_attribute_size =
26       MaxL2capPayloadSize() - emboss::AttHandleValueNtf::MinSizeInBytes();
27   if (attribute_value.size() > max_attribute_size) {
28     PW_LOG_ERROR("Attribute too large (%zu > %d). So will not process.",
29                  attribute_value.size(),
30                  max_attribute_size);
31     return pw::Status::InvalidArgument();
32   }
33 
34   size_t att_size =
35       emboss::AttHandleValueNtf::MinSizeInBytes() + attribute_value.size();
36   pw::Result<H4PacketWithH4> h4_result = PopulateTxL2capPacket(att_size);
37   if (!h4_result.ok()) {
38     // This can fail as a result of the L2CAP PDU not fitting in an H4 buffer
39     // or if all buffers are occupied.
40     // TODO: https://pwbug.dev/365179076 - Once we support ACL fragmentation,
41     // this function will not fail due to the L2CAP PDU size not fitting.
42     return h4_result.status();
43   }
44   H4PacketWithH4 h4_packet = std::move(*h4_result);
45 
46   // Write ATT PDU.
47   PW_TRY_ASSIGN(
48       auto acl,
49       MakeEmbossWriter<emboss::AclDataFrameWriter>(h4_packet.GetHciSpan()));
50   PW_TRY_ASSIGN(auto l2cap,
51                 MakeEmbossWriter<emboss::BFrameWriter>(
52                     acl.payload().BackingStorage().data(),
53                     acl.payload().BackingStorage().SizeInBytes()));
54   PW_TRY_ASSIGN(auto att_notify,
55                 MakeEmbossWriter<emboss::AttHandleValueNtfWriter>(
56                     attribute_value.size(),
57                     l2cap.payload().BackingStorage().data(),
58                     att_size));
59   att_notify.attribute_opcode().Write(emboss::AttOpcode::ATT_HANDLE_VALUE_NTF);
60   att_notify.attribute_handle().Write(attribute_handle_);
61   std::memcpy(att_notify.attribute_value().BackingStorage().data(),
62               attribute_value.data(),
63               attribute_value.size());
64 
65   return QueuePacket(std::move(h4_packet));
66 }
67 
Create(L2capChannelManager & l2cap_channel_manager,uint16_t connection_handle,uint16_t attribute_handle)68 pw::Result<GattNotifyChannel> GattNotifyChannel::Create(
69     L2capChannelManager& l2cap_channel_manager,
70     uint16_t connection_handle,
71     uint16_t attribute_handle) {
72   if (!L2capWriteChannel::AreValidParameters(connection_handle,
73                                              kAttributeProtocolCID)) {
74     return pw::Status::InvalidArgument();
75   }
76   if (attribute_handle == 0) {
77     PW_LOG_ERROR("Attribute handle cannot be 0.");
78     return pw::Status::InvalidArgument();
79   }
80   return GattNotifyChannel(
81       l2cap_channel_manager, connection_handle, attribute_handle);
82 }
83 
GattNotifyChannel(L2capChannelManager & l2cap_channel_manager,uint16_t connection_handle,uint16_t attribute_handle)84 GattNotifyChannel::GattNotifyChannel(L2capChannelManager& l2cap_channel_manager,
85                                      uint16_t connection_handle,
86                                      uint16_t attribute_handle)
87     : L2capWriteChannel(l2cap_channel_manager,
88                         connection_handle,
89                         AclTransportType::kLe,
90                         kAttributeProtocolCID),
91       attribute_handle_(attribute_handle) {}
92 
93 }  // namespace pw::bluetooth::proxy
94