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 #pragma once
16 #include <lib/fit/function.h>
17 #include <lib/fit/result.h>
18 
19 #include <memory>
20 #include <vector>
21 
22 #include "pw_bluetooth_sapphire/internal/host/att/att.h"
23 #include "pw_bluetooth_sapphire/internal/host/common/assert.h"
24 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
25 #include "pw_bluetooth_sapphire/internal/host/common/identifier.h"
26 #include "pw_bluetooth_sapphire/internal/host/common/macros.h"
27 #include "pw_bluetooth_sapphire/internal/host/common/uuid.h"
28 #include "pw_bluetooth_sapphire/internal/host/sm/smp.h"
29 
30 namespace bt::att {
31 
32 // Defines the read or write access permissions for an attribute.
33 class AccessRequirements final {
34  public:
35   // The default access permission prevents the attribute from being accessed.
36   AccessRequirements();
37 
38   // Enables access permission with the given requirements.
39   // |min_enc_key_size| is the required minimum size of the key encrypting the
40   // connection in order to access an attribute where |encryption| is true.
41   //
42   // The default value of |min_enc_key_size| enforces maximum security, but
43   // could prevent devices that don't support |kMaxEncryptionKeySize| from
44   // accessing attributes that require encryption. In practice, it seems that
45   // most devices that access such attributes support |kMaxEncryptionKeySize|.
46   AccessRequirements(bool encryption,
47                      bool authentication,
48                      bool authorization,
49                      uint8_t min_enc_key_size = sm::kMaxEncryptionKeySize);
50 
51   // Returns true if this attribute can be accessed at all.
allowed()52   inline bool allowed() const {
53     return value_ & kAttributePermissionBitAllowed;
54   }
55 
56   // Returns true if no security is required.
allowed_without_security()57   inline bool allowed_without_security() const {
58     return value_ == kAttributePermissionBitAllowed;
59   }
60 
61   // The following getters return the security requirements of this attribute:
62 
encryption_required()63   inline bool encryption_required() const {
64     return value_ & kAttributePermissionBitEncryptionRequired;
65   }
66 
authentication_required()67   inline bool authentication_required() const {
68     return value_ & kAttributePermissionBitAuthenticationRequired;
69   }
70 
authorization_required()71   inline bool authorization_required() const {
72     return value_ & kAttributePermissionBitAuthorizationRequired;
73   }
74 
min_enc_key_size()75   inline uint8_t min_enc_key_size() const { return min_enc_key_size_; }
76 
77   inline bool operator==(const AccessRequirements& other) const {
78     return value_ == other.value_ &&
79            min_enc_key_size_ == other.min_enc_key_size_;
80   }
81 
82  private:
83   uint8_t value_;
84   uint8_t min_enc_key_size_;
85 };
86 
87 class AttributeGrouping;
88 
89 // Represents an attribute. Each attribute is assigned a handle (unique within
90 // the scope of an Adapter) and a UUID that identifies its type. The type of an
91 // attribute dictates how to interpret the attribute value.
92 //
93 // Each attribute has a value of up to 512 octets. An Attribute can be
94 // configured to have a static value. In such a case the value can be directly
95 // obtained by calling |value()|. Such attributes cannot be written to.
96 //
97 // Otherwise, an Attribute is considered dynamic and its value must be accessed
98 // asynchronously by calling ReadAsync()/WriteAsync().
99 //
100 // Instances cannot be constructed directly and must be obtained from an
101 // AttributeGrouping.
102 //
103 // THREAD-SAFETY:
104 //
105 // This class is not thread-safe. The constructor/destructor and all public
106 // methods must be called on the same thread.
107 class Attribute final {
108  public:
109   // Allow move construction and assignment.
110   Attribute(Attribute&& other) = default;
111   Attribute& operator=(Attribute&& other) = default;
112 
is_initialized()113   bool is_initialized() const { return handle_ != kInvalidHandle; }
114 
handle()115   Handle handle() const { return handle_; }
type()116   const UUID& type() const { return type_; }
117 
118   // The grouping that this attribute belongs to.
group()119   const AttributeGrouping& group() const { return *group_; }
120 
121   // Returns the current attribute value. Returns nullptr if the attribute has a
122   // dynamic value.
value()123   const ByteBuffer* value() const { return value_.size() ? &value_ : nullptr; }
124 
125   // The read/write permissions of this attribute.
read_reqs()126   const AccessRequirements& read_reqs() const { return read_reqs_; }
write_reqs()127   const AccessRequirements& write_reqs() const { return write_reqs_; }
128 
129   // Sets |value| as the static attribute value. Once a value is assigned it
130   // cannot be overwritten. A static value cannot be assigned to an attribute
131   // that permits writes as attribute writes need to propagate to the service
132   // layer.
133   void SetValue(const ByteBuffer& value);
134 
135   // Handlers for reading and writing and attribute value asynchronously. A
136   // handler must call the provided the |result_callback| to signal the end of
137   // the operation.
138   using ReadResultCallback = fit::callback<void(fit::result<ErrorCode> status,
139                                                 const ByteBuffer& value)>;
140   using ReadHandler = fit::function<void(PeerId peer_id,
141                                          Handle handle,
142                                          uint16_t offset,
143                                          ReadResultCallback result_callback)>;
set_read_handler(ReadHandler read_handler)144   void set_read_handler(ReadHandler read_handler) {
145     read_handler_ = std::move(read_handler);
146   }
147 
148   // An "ATT Write Command" will trigger WriteHandler with
149   // a null |result_callback|
150   using WriteResultCallback =
151       fit::callback<void(fit::result<ErrorCode> status)>;
152   using WriteHandler = fit::function<void(PeerId peer_id,
153                                           Handle handle,
154                                           uint16_t offset,
155                                           const ByteBuffer& value,
156                                           WriteResultCallback result_callback)>;
set_write_handler(WriteHandler write_handler)157   void set_write_handler(WriteHandler write_handler) {
158     write_handler_ = std::move(write_handler);
159   }
160 
161   // Initiates an asynchronous read of the attribute value. Returns false if
162   // this attribute is not dynamic.
163   bool ReadAsync(PeerId peer_id,
164                  uint16_t offset,
165                  ReadResultCallback result_callback) const;
166 
167   // Initiates an asynchronous write of the attribute value. Returns false if
168   // this attribute is not dynamic.
169   bool WriteAsync(PeerId peer_id,
170                   uint16_t offset,
171                   const ByteBuffer& value,
172                   WriteResultCallback result_callback) const;
173 
174  private:
175   // Only an AttributeGrouping can construct this.
176   friend class AttributeGrouping;
177 
178   // The default constructor will construct this attribute as uninitialized.
179   // This is intended for STL containers.
180   Attribute();
181   Attribute(AttributeGrouping* group,
182             Handle handle,
183             const UUID& type,
184             const AccessRequirements& read_reqs,
185             const AccessRequirements& write_reqs);
186 
187   AttributeGrouping* group_;  // The group that owns this Attribute.
188   Handle handle_;
189   UUID type_;
190   AccessRequirements read_reqs_;
191   AccessRequirements write_reqs_;
192 
193   ReadHandler read_handler_;
194   WriteHandler write_handler_;
195 
196   DynamicByteBuffer value_;
197 
198   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(Attribute);
199 };
200 
201 // Represents a grouping of attributes (see Vol 3, Part F, 3.2.3). Each grouping
202 // contains at least one leading attribute that contains the group declaration.
203 // The type of this attribute dictates the type of the grouping.
204 //
205 // Each grouping covers a contiguous range of handle numbers. The size of the
206 // range is determined by the |attr_count| constructor argument which defines
207 // the number of attributes in the grouping following the declaration attribute.
208 // Once constructed, a grouping is not considered complete until available
209 // handles within the range have been populated.
210 class AttributeGrouping final {
211  public:
212   // Initializes this attribute grouping with a group declaration attribute and
213   // enough storage for |attr_count| additional attributes. |decl_value| is
214   // assigned as the read-only value of the declaration attribute.
215   //
216   // Note: |attr_count| should not cause the group end handle to exceed
217   // att::kHandleMax.
218   AttributeGrouping(const UUID& group_type,
219                     Handle start_handle,
220                     size_t attr_count,
221                     const ByteBuffer& decl_value);
222 
223   // Inserts a new attribute into this grouping using the given parameters and
224   // returns a pointer to it. Returns nullptr if the grouping is out of handles
225   // to allocate.
226   //
227   // The caller should not hold on to the returned pointer as the Attribute
228   // object is owned and managed by this AttributeGrouping.
229   Attribute* AddAttribute(
230       const UUID& type,
231       const AccessRequirements& read_reqs = AccessRequirements(),
232       const AccessRequirements& write_reqs = AccessRequirements());
233 
234   // Returns true if all attributes of this grouping have been populated.
complete()235   bool complete() const {
236     return attributes_.size() == (end_handle_ - start_handle_ + 1);
237   }
238 
group_type()239   const UUID& group_type() const {
240     PW_DCHECK(!attributes_.empty());
241     return attributes_[0].type();
242   }
243 
244   // Value of the group declaration attribute.
decl_value()245   BufferView decl_value() const {
246     PW_DCHECK(!attributes_.empty());
247     PW_DCHECK(attributes_[0].value());
248     return attributes_[0].value()->view();
249   }
250 
251   // The start and end handles of this grouping (inclusive).
start_handle()252   Handle start_handle() const { return start_handle_; }
end_handle()253   Handle end_handle() const { return end_handle_; }
254 
active()255   bool active() const { return active_; }
set_active(bool active)256   void set_active(bool active) {
257     PW_DCHECK(complete(), "set_active() called on incomplete grouping!");
258     active_ = active;
259   }
260 
attributes()261   const std::vector<Attribute>& attributes() const { return attributes_; }
262 
263  private:
264   Handle start_handle_;
265   Handle end_handle_;
266 
267   // Only groupings that are active are considered when responding to ATT
268   // requests.
269   bool active_;
270 
271   // The Attributes in this grouping, including the declaration attribute. Space
272   // is reserved for all attributes upon construction. The number of elements in
273   // |attributes_| reflects how many of the attributes have been initialized.
274   std::vector<Attribute> attributes_;
275 
276   BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(AttributeGrouping);
277 };
278 
279 }  // namespace bt::att
280