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 <pw_assert/check.h>
18
19 #include "pw_bluetooth_sapphire/internal/host/att/att.h"
20 #include "pw_bluetooth_sapphire/internal/host/att/attribute.h"
21 #include "pw_bluetooth_sapphire/internal/host/att/database.h"
22 #include "pw_bluetooth_sapphire/internal/host/common/macros.h"
23 #include "pw_bluetooth_sapphire/internal/host/common/uuid.h"
24 #include "pw_bluetooth_sapphire/internal/host/gatt/gatt_defs.h"
25 #include "pw_bluetooth_sapphire/internal/host/gatt/local_service_manager.h"
26 #include "pw_bluetooth_sapphire/internal/host/l2cap/mock_channel_test.h"
27 #include "pw_bluetooth_sapphire/internal/host/testing/test_helpers.h"
28
29 namespace bt::gatt {
30 namespace {
31
32 constexpr UUID kTestSvcType(uint16_t{0xDEAD});
33 constexpr UUID kTestChrcType(uint16_t{0xFEED});
34 constexpr IdType kTestChrcId{0xFADE};
35 constexpr PeerId kTestPeerId(1);
36 constexpr UUID kTestType16(uint16_t{0xBEEF});
37 constexpr UUID kTestType128(
38 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15});
39
40 const StaticByteBuffer kTestValue1('f', 'o', 'o');
41 const StaticByteBuffer kTestValue2('b', 'a', 'r');
42 const StaticByteBuffer kTestValue3('b', 'a', 'z');
43 const StaticByteBuffer kTestValue4('l', 'o', 'l');
44
45 const StaticByteBuffer kTestValueLong('l', 'o', 'n', 'g');
46
AllowedNoSecurity()47 inline att::AccessRequirements AllowedNoSecurity() {
48 return att::AccessRequirements(/*encryption=*/false,
49 /*authentication=*/false,
50 /*authorization=*/false);
51 }
52
53 class ServerTest : public l2cap::testing::MockChannelTest {
54 public:
55 ServerTest() = default;
56 ~ServerTest() override = default;
57
58 protected:
SetUp()59 void SetUp() override {
60 local_services_ = std::make_unique<LocalServiceManager>();
61
62 ChannelOptions options(l2cap::kATTChannelId);
63 fake_att_chan_ = CreateFakeChannel(options);
64 att_ = att::Bearer::Create(fake_att_chan_->GetWeakPtr(), dispatcher());
65 server_ = gatt::Server::Create(
66 kTestPeerId, local_services_->GetWeakPtr(), att_->GetWeakPtr());
67 }
68
TearDown()69 void TearDown() override {
70 RunUntilIdle();
71 server_ = nullptr;
72 att_ = nullptr;
73 fake_att_chan_ = l2cap::testing::FakeChannel::WeakPtr();
74 local_services_ = nullptr;
75 }
76
77 // Registers a service with UUID |svc_type| containing a single characteristic
78 // of UUID |chrc_type| and represented by |chrc_id|. The characteristic
79 // supports the indicate and notify properties, but has not configured them
80 // via the CCC. Returns the ID of the registered service.
RegisterSvcWithSingleChrc(UUID svc_type,IdType chrc_id,UUID chrc_type)81 IdType RegisterSvcWithSingleChrc(UUID svc_type,
82 IdType chrc_id,
83 UUID chrc_type) {
84 ServicePtr svc = std::make_unique<Service>(/*primary=*/true, svc_type);
85 CharacteristicPtr chr = std::make_unique<Characteristic>(
86 chrc_id,
87 chrc_type,
88 Property::kIndicate | Property::kNotify,
89 /*extended_properties=*/0u,
90 /*read_permission=*/att::AccessRequirements(),
91 /*write_permissions=*/att::AccessRequirements(),
92 /*update_permisisons=*/AllowedNoSecurity());
93 svc->AddCharacteristic(std::move(chr));
94 return local_services_->RegisterService(
95 std::move(svc), NopReadHandler, NopWriteHandler, NopCCCallback);
96 }
97
98 struct SvcIdAndChrcHandle {
99 IdType svc_id;
100 att::Handle chrc_val_handle;
101 };
102 // RegisterSvcWithSingleChrc, but the CCC is configured to |ccc_val| for
103 // kTestPeerId. Returns the ID of the service alongside the handle of the
104 // registered characteristic value.
RegisterSvcWithConfiguredChrc(UUID svc_type,IdType chrc_id,UUID chrc_type,uint16_t ccc_val=kCCCIndicationBit|kCCCNotificationBit)105 SvcIdAndChrcHandle RegisterSvcWithConfiguredChrc(
106 UUID svc_type,
107 IdType chrc_id,
108 UUID chrc_type,
109 uint16_t ccc_val = kCCCIndicationBit | kCCCNotificationBit) {
110 IdType svc_id = RegisterSvcWithSingleChrc(svc_type, chrc_id, chrc_type);
111 std::vector<att::Handle> chrc_val_handle =
112 SetCCCs(kTestPeerId, chrc_type, ccc_val);
113 EXPECT_EQ(1u, chrc_val_handle.size());
114 return SvcIdAndChrcHandle{.svc_id = svc_id,
115 .chrc_val_handle = chrc_val_handle[0]};
116 }
server() const117 Server* server() const { return server_.get(); }
118
db() const119 att::Database::WeakPtr db() const { return local_services_->database(); }
120
121 // TODO(armansito): Consider introducing a FakeBearer for testing
122 // (fxbug.dev/42142784).
att() const123 att::Bearer* att() const { return att_.get(); }
124
125 private:
126 enum CCCSearchState {
127 kSearching,
128 kChrcDeclarationFound,
129 kCorrectChrcUuidFound,
130 };
131 // Sets |local_services_|' CCCs for |peer_id| to |ccc_val| for all
132 // characteristics of |chrc_type|, and returns the handles of the
133 // characteristic values for which the CCC was modified.
SetCCCs(PeerId peer_id,bt::UUID chrc_type,uint16_t ccc_val)134 std::vector<att::Handle> SetCCCs(PeerId peer_id,
135 bt::UUID chrc_type,
136 uint16_t ccc_val) {
137 std::vector<att::Handle> modified_attrs;
138 CCCSearchState state = kSearching;
139 for (auto& grouping : db()->groupings()) {
140 att::Handle matching_chrc_value_handle = att::kInvalidHandle;
141 for (auto& attr : grouping.attributes()) {
142 if (attr.type() == types::kCharacteristicDeclaration) {
143 EXPECT_NE(state, kChrcDeclarationFound)
144 << "unexpectedly found two consecutive characteristic "
145 "declarations";
146 state = kChrcDeclarationFound;
147 } else if (state == kChrcDeclarationFound && attr.type() == chrc_type) {
148 state = kCorrectChrcUuidFound;
149 matching_chrc_value_handle = attr.handle();
150 } else if (state == kChrcDeclarationFound) {
151 state = kSearching;
152 } else if (state == kCorrectChrcUuidFound &&
153 attr.type() == types::kClientCharacteristicConfig) {
154 PW_CHECK(matching_chrc_value_handle != att::kInvalidHandle);
155 DynamicByteBuffer new_ccc(sizeof(ccc_val));
156 new_ccc.WriteObj(ccc_val);
157 fit::result<att::ErrorCode> write_status =
158 fit::error(att::ErrorCode::kReadNotPermitted);
159 EXPECT_TRUE(attr.WriteAsync(peer_id,
160 /*offset=*/0,
161 new_ccc,
162 [&](fit::result<att::ErrorCode> status) {
163 write_status = status;
164 }));
165 // Not strictly necessary with the current WriteAsync implementation,
166 // but running the loop here makes this more future-proof.
167 RunUntilIdle();
168 EXPECT_EQ(fit::ok(), write_status);
169 modified_attrs.push_back(matching_chrc_value_handle);
170 }
171 }
172 }
173 EXPECT_NE(0u, modified_attrs.size()) << "Couldn't find CCC attribute!";
174 return modified_attrs;
175 }
176
177 std::unique_ptr<LocalServiceManager> local_services_;
178 l2cap::testing::FakeChannel::WeakPtr fake_att_chan_;
179 std::unique_ptr<att::Bearer> att_;
180 std::unique_ptr<Server> server_;
181
182 BT_DISALLOW_COPY_AND_ASSIGN_ALLOW_MOVE(ServerTest);
183 };
184
TEST_F(ServerTest,ExchangeMTURequestInvalidPDU)185 TEST_F(ServerTest, ExchangeMTURequestInvalidPDU) {
186 // Just opcode
187 // clang-format off
188 const StaticByteBuffer kInvalidPDU(0x02);
189 const StaticByteBuffer kExpected(
190 0x01, // opcode: error response
191 0x02, // request: exchange MTU
192 0x00, 0x00, // handle: 0
193 0x04 // error: Invalid PDU
194 );
195 // clang-format on
196
197 EXPECT_PACKET_OUT(kExpected);
198 fake_chan()->Receive(kInvalidPDU);
199 }
200
TEST_F(ServerTest,ExchangeMTURequestValueTooSmall)201 TEST_F(ServerTest, ExchangeMTURequestValueTooSmall) {
202 const uint16_t kServerMTU = att::kLEMaxMTU;
203 constexpr uint16_t kClientMTU = 1;
204
205 // clang-format off
206 const StaticByteBuffer kRequest(
207 0x02, // opcode: exchange MTU
208 kClientMTU, 0x00 // client rx mtu: |kClientMTU|
209 );
210
211 const StaticByteBuffer kExpected(
212 0x03, // opcode: exchange MTU response
213 0xF7, 0x00 // server rx mtu: |kServerMTU|
214 );
215 // clang-format on
216
217 ASSERT_EQ(kServerMTU, att()->preferred_mtu());
218
219 EXPECT_PACKET_OUT(kExpected);
220 fake_chan()->Receive(kRequest);
221 // Should default to kLEMinMTU since kClientMTU is too small.
222 EXPECT_EQ(att::kLEMinMTU, att()->mtu());
223 }
224
TEST_F(ServerTest,ExchangeMTURequest)225 TEST_F(ServerTest, ExchangeMTURequest) {
226 constexpr uint16_t kServerMTU = att::kLEMaxMTU;
227 constexpr uint16_t kClientMTU = 0x64;
228
229 // clang-format off
230 const StaticByteBuffer kRequest(
231 0x02, // opcode: exchange MTU
232 kClientMTU, 0x00 // client rx mtu: |kClientMTU|
233 );
234
235 const StaticByteBuffer kExpected(
236 0x03, // opcode: exchange MTU response
237 0xF7, 0x00 // server rx mtu: |kServerMTU|
238 );
239 // clang-format on
240
241 ASSERT_EQ(kServerMTU, att()->preferred_mtu());
242
243 EXPECT_PACKET_OUT(kExpected);
244 fake_chan()->Receive(kRequest);
245 EXPECT_EQ(kClientMTU, att()->mtu());
246 }
247
TEST_F(ServerTest,FindInformationInvalidPDU)248 TEST_F(ServerTest, FindInformationInvalidPDU) {
249 // Just opcode
250 // clang-format off
251 const StaticByteBuffer kInvalidPDU(0x04);
252 const StaticByteBuffer kExpected(
253 0x01, // opcode: error response
254 0x04, // request: find information
255 0x00, 0x00, // handle: 0
256 0x04 // error: Invalid PDU
257 );
258 // clang-format on
259
260 EXPECT_PACKET_OUT(kExpected);
261 fake_chan()->Receive(kInvalidPDU);
262 }
263
TEST_F(ServerTest,FindInformationInvalidHandle)264 TEST_F(ServerTest, FindInformationInvalidHandle) {
265 // Start handle is 0
266 // clang-format off
267 const StaticByteBuffer kInvalidStartHandle(
268 0x04, // opcode: find information
269 0x00, 0x00, // start: 0x0000
270 0xFF, 0xFF // end: 0xFFFF
271 );
272
273 const StaticByteBuffer kExpected1(
274 0x01, // opcode: error response
275 0x04, // request: find information
276 0x00, 0x00, // handle: 0x0000 (start handle in request)
277 0x01 // error: Invalid handle
278 );
279
280 // End handle is smaller than start handle
281 const StaticByteBuffer kInvalidEndHandle(
282 0x04, // opcode: find information
283 0x02, 0x00, // start: 0x0002
284 0x01, 0x00 // end: 0x0001
285 );
286
287 const StaticByteBuffer kExpected2(
288 0x01, // opcode: error response
289 0x04, // request: find information
290 0x02, 0x00, // handle: 0x0002 (start handle in request)
291 0x01 // error: Invalid handle
292 );
293 // clang-format on
294
295 EXPECT_PACKET_OUT(kExpected1);
296 fake_chan()->Receive(kInvalidStartHandle);
297 EXPECT_PACKET_OUT(kExpected2);
298 fake_chan()->Receive(kInvalidEndHandle);
299 }
300
TEST_F(ServerTest,FindInformationAttributeNotFound)301 TEST_F(ServerTest, FindInformationAttributeNotFound) {
302 // clang-format off
303 const StaticByteBuffer kRequest(
304 0x04, // opcode: find information request
305 0x01, 0x00, // start: 0x0001
306 0xFF, 0xFF // end: 0xFFFF
307 );
308
309 const StaticByteBuffer kExpected(
310 0x01, // opcode: error response
311 0x04, // request: find information
312 0x01, 0x00, // handle: 0x0001 (start handle in request)
313 0x0A // error: Attribute not found
314 );
315 // clang-format on
316
317 EXPECT_PACKET_OUT(kExpected);
318 fake_chan()->Receive(kRequest);
319 }
320
TEST_F(ServerTest,FindInformation16)321 TEST_F(ServerTest, FindInformation16) {
322 auto* grp = db()->NewGrouping(types::kPrimaryService, 2, kTestValue1);
323 grp->AddAttribute(kTestType16);
324 grp->AddAttribute(kTestType16);
325 grp->set_active(true);
326
327 // clang-format off
328 const StaticByteBuffer kRequest(
329 0x04, // opcode: find information request
330 0x01, 0x00, // start: 0x0001
331 0xFF, 0xFF // end: 0xFFFF
332 );
333
334 const StaticByteBuffer kExpected(
335 0x05, // opcode: find information response
336 0x01, // format: 16-bit
337 0x01, 0x00, // handle: 0x0001
338 0x00, 0x28, // uuid: primary service group type
339 0x02, 0x00, // handle: 0x0002
340 0xEF, 0xBE, // uuid: 0xBEEF
341 0x03, 0x00, // handle: 0x0003
342 0xEF, 0xBE // uuid: 0xBEEF
343 );
344 // clang-format on
345
346 EXPECT_PACKET_OUT(kExpected);
347 fake_chan()->Receive(kRequest);
348 }
349
TEST_F(ServerTest,FindInformation128)350 TEST_F(ServerTest, FindInformation128) {
351 auto* grp = db()->NewGrouping(kTestType128, 0, kTestValue1);
352 grp->set_active(true);
353
354 // clang-format off
355 const StaticByteBuffer kRequest(
356 0x04, // opcode: find information request
357 0x01, 0x00, // start: 0x0001
358 0xFF, 0xFF // end: 0xFFFF
359 );
360
361 const StaticByteBuffer kExpected(
362 0x05, // opcode: find information response
363 0x02, // format: 128-bit
364 0x01, 0x00, // handle: 0x0001
365
366 // uuid: 0F0E0D0C-0B0A-0908-0706-050403020100
367 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
368 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F);
369 // clang-format on
370
371 EXPECT_PACKET_OUT(kExpected);
372 fake_chan()->Receive(kRequest);
373 }
374
TEST_F(ServerTest,FindByTypeValueSuccess)375 TEST_F(ServerTest, FindByTypeValueSuccess) {
376 // handle: 1 (active)
377 db()->NewGrouping(types::kPrimaryService, 0, kTestValue1)->set_active(true);
378
379 // handle: 2 (active)
380 db()->NewGrouping(types::kPrimaryService, 0, kTestValue2)->set_active(true);
381
382 // handle: 3 (active)
383 db()->NewGrouping(types::kPrimaryService, 0, kTestValue1)->set_active(true);
384
385 // clang-format off
386 const StaticByteBuffer kRequest(
387 0x06, // opcode: find by type value request
388 0x01, 0x00, // start: 0x0001
389 0xFF, 0xFF, // end: 0xFFFF
390 0x00, 0x28, // uuid: primary service group type
391 'f', 'o', 'o' // value: foo
392 );
393
394 const StaticByteBuffer kExpected(
395 0x07, // opcode: find by type value response
396 0x01, 0x00, // handle: 0x0001
397 0x01, 0x00, // group handle: 0x0001
398 0x03, 0x00, // handle: 0x0003
399 0x03, 0x00 // group handle: 0x0003
400 );
401 // clang-format on
402
403 EXPECT_PACKET_OUT(kExpected);
404 fake_chan()->Receive(kRequest);
405 }
406
TEST_F(ServerTest,FindByTypeValueFail)407 TEST_F(ServerTest, FindByTypeValueFail) {
408 // handle: 1 (active)
409 db()->NewGrouping(types::kPrimaryService, 0, kTestValue1)->set_active(true);
410
411 // clang-format off
412 const StaticByteBuffer kRequest(
413 0x06, // opcode: find by type value request
414 0x01, 0x00, // start: 0x0001
415 0xFF, 0xFF, // end: 0xFFFF
416 0x00, 0x28, // uuid: primary service group type
417 'n', 'o' // value: no
418 );
419
420 const StaticByteBuffer kExpected(
421 0x01, // Error
422 0x06, // opcode: find by type value
423 0x00, 0x00, // group handle: 0x0000
424 0x0a // Attribute Not Found
425 );
426 // clang-format on
427
428 EXPECT_PACKET_OUT(kExpected);
429 fake_chan()->Receive(kRequest);
430 }
431
TEST_F(ServerTest,FindByTypeValueEmptyDB)432 TEST_F(ServerTest, FindByTypeValueEmptyDB) {
433 // clang-format off
434 const StaticByteBuffer kRequest(
435 0x06, // opcode: find by type value request
436 0x01, 0x00, // start: 0x0001
437 0xFF, 0xFF, // end: 0xFFFF
438 0x00, 0x28, // uuid: primary service group type
439 'n', 'o' // value: no
440 );
441
442 const StaticByteBuffer kExpected(
443 0x01, // Error
444 0x06, // opcode: find by type value
445 0x00, 0x00, // group handle: 0x0000
446 0x0a // Attribute Not Found
447 );
448 // clang-format on
449
450 EXPECT_PACKET_OUT(kExpected);
451 fake_chan()->Receive(kRequest);
452 }
453
TEST_F(ServerTest,FindByTypeValueInvalidHandle)454 TEST_F(ServerTest, FindByTypeValueInvalidHandle) {
455 // clang-format off
456 const StaticByteBuffer kRequest(
457 0x06, // opcode: find by type value request
458 0x02, 0x00, // start: 0x0002
459 0x01, 0x00, // end: 0x0001
460 0x00, 0x28, // uuid: primary service group type
461 'n', 'o' // value: no
462 );
463
464 const StaticByteBuffer kExpected(
465 0x01, // Error
466 0x06, // opcode: find by type value
467 0x00, 0x00, // group handle: 0x0000
468 0x01 // Invalid Handle
469 );
470 // clang-format on
471
472 EXPECT_PACKET_OUT(kExpected);
473 fake_chan()->Receive(kRequest);
474 }
475
TEST_F(ServerTest,FindByTypeValueInvalidPDUError)476 TEST_F(ServerTest, FindByTypeValueInvalidPDUError) {
477 // handle: 1 (active)
478 db()->NewGrouping(types::kPrimaryService, 0, kTestValue1)->set_active(true);
479
480 // clang-format off
481 const StaticByteBuffer kInvalidPDU(0x06);
482
483 const StaticByteBuffer kExpected(
484 0x01, // Error
485 0x06, // opcode: find by type value
486 0x00, 0x00, // group handle: 0x0000
487 0x04 // Invalid PDU
488 );
489 // clang-format on
490
491 EXPECT_PACKET_OUT(kExpected);
492 fake_chan()->Receive(kInvalidPDU);
493 }
494
TEST_F(ServerTest,FindByTypeValueZeroLengthValueError)495 TEST_F(ServerTest, FindByTypeValueZeroLengthValueError) {
496 // handle: 1 (active)
497 db()->NewGrouping(types::kPrimaryService, 0, kTestValue1)->set_active(true);
498
499 // clang-format off
500 const StaticByteBuffer kRequest(
501 0x06, // opcode: find by type value request
502 0x01, 0x00, // start: 0x0001
503 0xFF, 0xFF, // end: 0xFFFF
504 0x00, 0x28 // uuid: primary service group type
505 );
506
507 const StaticByteBuffer kExpected(
508 0x01, // Error
509 0x06, // opcode: find by type value
510 0x00, 0x00, // group handle: 0x0000
511 0x0a // Attribute Not Found
512 );
513 // clang-format on
514
515 EXPECT_PACKET_OUT(kExpected);
516 fake_chan()->Receive(kRequest);
517 }
518
TEST_F(ServerTest,FindByTypeValueOutsideRangeError)519 TEST_F(ServerTest, FindByTypeValueOutsideRangeError) {
520 // handle: 1 (active)
521 auto* grp = db()->NewGrouping(kTestType16, 2, kTestValue2);
522
523 // handle: 2 - value: "long"
524 grp->AddAttribute(kTestType16, AllowedNoSecurity())->SetValue(kTestValue2);
525
526 // handle: 3 - value: "foo"
527 grp->AddAttribute(kTestType16, AllowedNoSecurity())->SetValue(kTestValue1);
528 grp->set_active(true);
529
530 // clang-format off
531 const StaticByteBuffer kRequest(
532 0x06, // opcode: find by type value request
533 0x01, 0x00, // start: 0x0001
534 0x02, 0x00, // end: 0xFFFF
535 0x00, 0x28, // uuid: primary service group type
536 'f', 'o', 'o' // value: foo
537 );
538
539 const StaticByteBuffer kExpected(
540 0x01, // Error
541 0x06, // opcode: find by type value
542 0x00, 0x00, // group handle: 0x0000
543 0x0a // Attribute Not Found
544 );
545 // clang-format on
546
547 EXPECT_PACKET_OUT(kExpected);
548 fake_chan()->Receive(kRequest);
549 }
550
TEST_F(ServerTest,FindInfomationInactive)551 TEST_F(ServerTest, FindInfomationInactive) {
552 // handle: 1 (active)
553 db()->NewGrouping(types::kPrimaryService, 0, kTestValue1)->set_active(true);
554
555 // handle: 2, 3, 4 (inactive)
556 auto* grp = db()->NewGrouping(types::kPrimaryService, 2, kTestValue1);
557 grp->AddAttribute(kTestType16);
558 grp->AddAttribute(kTestType16);
559
560 // handle: 5 (active)
561 db()->NewGrouping(types::kPrimaryService, 0, kTestValue1)->set_active(true);
562
563 // clang-format off
564 const StaticByteBuffer kRequest(
565 0x04, // opcode: find information request
566 0x01, 0x00, // start: 0x0001
567 0xFF, 0xFF // end: 0xFFFF
568 );
569
570 const StaticByteBuffer kExpected(
571 0x05, // opcode: find information response
572 0x01, // format: 16-bit
573 0x01, 0x00, // handle: 0x0001
574 0x00, 0x28, // uuid: primary service group type
575 0x05, 0x00, // handle: 0x0005
576 0x00, 0x28 // uuid: primary service group type
577 );
578 // clang-format on
579
580 EXPECT_PACKET_OUT(kExpected);
581 fake_chan()->Receive(kRequest);
582 }
583
TEST_F(ServerTest,FindInfomationRange)584 TEST_F(ServerTest, FindInfomationRange) {
585 auto* grp = db()->NewGrouping(types::kPrimaryService, 2, kTestValue1);
586 grp->AddAttribute(kTestType16);
587 grp->AddAttribute(kTestType16);
588 grp->set_active(true);
589
590 // handle: 5 (active)
591 db()->NewGrouping(types::kPrimaryService, 0, kTestValue1)->set_active(true);
592
593 // clang-format off
594 const StaticByteBuffer kRequest(
595 0x04, // opcode: find information request
596 0x02, 0x00, // start: 0x0002
597 0x02, 0x00 // end: 0x0002
598 );
599
600 const StaticByteBuffer kExpected(
601 0x05, // opcode: find information response
602 0x01, // format: 16-bit
603 0x02, 0x00, // handle: 0x0001
604 0xEF, 0xBE // uuid: 0xBEEF
605 );
606 // clang-format on
607
608 EXPECT_PACKET_OUT(kExpected);
609 fake_chan()->Receive(kRequest);
610 }
611
TEST_F(ServerTest,ReadByGroupTypeInvalidPDU)612 TEST_F(ServerTest, ReadByGroupTypeInvalidPDU) {
613 // Just opcode
614 // clang-format off
615 const StaticByteBuffer kInvalidPDU(0x10);
616 const StaticByteBuffer kExpected(
617 0x01, // opcode: error response
618 0x10, // request: read by group type
619 0x00, 0x00, // handle: 0
620 0x04 // error: Invalid PDU
621 );
622 // clang-format on
623
624 EXPECT_PACKET_OUT(kExpected);
625 fake_chan()->Receive(kInvalidPDU);
626 }
627
TEST_F(ServerTest,ReadByGroupTypeUnsupportedGroupType)628 TEST_F(ServerTest, ReadByGroupTypeUnsupportedGroupType) {
629 // 16-bit UUID
630 // clang-format off
631 const StaticByteBuffer kUsing16BitType(
632 0x10, // opcode: read by group type
633 0x01, 0x00, // start: 0x0001
634 0xFF, 0xFF, // end: 0xFFFF
635 0x01, 0x00 // group type: 1 (unsupported)
636 );
637
638 // 128-bit UUID
639 const StaticByteBuffer kUsing128BitType(
640 0x10, // opcode: read by group type
641 0x01, 0x00, // start: 0x0001
642 0xFF, 0xFF, // end: 0xFFFF
643
644 // group type: 00112233-4455-6677-8899-AABBCCDDEEFF (unsupported)
645 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99, 0x88,
646 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00);
647
648 const StaticByteBuffer kExpected(
649 0x01, // opcode: error response
650 0x10, // request: read by group type
651 0x01, 0x00, // handle: 0x0001 (start handle in request)
652 0x10 // error: Unsupported Group Type
653 );
654 // clang-format on
655
656 EXPECT_PACKET_OUT(kExpected);
657 fake_chan()->Receive(kUsing16BitType);
658 EXPECT_PACKET_OUT(kExpected);
659 fake_chan()->Receive(kUsing128BitType);
660 }
661
TEST_F(ServerTest,ReadByGroupTypeInvalidHandle)662 TEST_F(ServerTest, ReadByGroupTypeInvalidHandle) {
663 // Start handle is 0
664 // clang-format off
665 const StaticByteBuffer kInvalidStartHandle(
666 0x10, // opcode: read by group type
667 0x00, 0x00, // start: 0x0000
668 0xFF, 0xFF, // end: 0xFFFF
669 0x00, 0x28 // group type: 0x2800 (primary service)
670 );
671
672 const StaticByteBuffer kExpected1(
673 0x01, // opcode: error response
674 0x10, // request: read by group type
675 0x00, 0x00, // handle: 0x0000 (start handle in request)
676 0x01 // error: Invalid handle
677 );
678
679 // End handle is smaller than start handle
680 const StaticByteBuffer kInvalidEndHandle(
681 0x10, // opcode: read by group type
682 0x02, 0x00, // start: 0x0002
683 0x01, 0x00, // end: 0x0001
684 0x00, 0x28 // group type: 0x2800 (primary service)
685 );
686
687 const StaticByteBuffer kExpected2(
688 0x01, // opcode: error response
689 0x10, // request: read by group type
690 0x02, 0x00, // handle: 0x0002 (start handle in request)
691 0x01 // error: Invalid handle
692 );
693 // clang-format on
694
695 EXPECT_PACKET_OUT(kExpected1);
696 fake_chan()->Receive(kInvalidStartHandle);
697 EXPECT_PACKET_OUT(kExpected2);
698 fake_chan()->Receive(kInvalidEndHandle);
699 }
700
TEST_F(ServerTest,ReadByGroupTypeAttributeNotFound)701 TEST_F(ServerTest, ReadByGroupTypeAttributeNotFound) {
702 // clang-format off
703 const StaticByteBuffer kRequest(
704 0x10, // opcode: read by group type
705 0x01, 0x00, // start: 0x0001
706 0xFF, 0xFF, // end: 0xFFFF
707 0x00, 0x28 // group type: 0x2800 (primary service)
708 );
709
710 const StaticByteBuffer kExpected(
711 0x01, // opcode: error response
712 0x10, // request: read by group type
713 0x01, 0x00, // handle: 0x0001 (start handle in request)
714 0x0A // error: Attribute not found
715 );
716 // clang-format on
717
718 // Database is empty.
719 EXPECT_PACKET_OUT(kExpected);
720 fake_chan()->Receive(kRequest);
721
722 // Group type does not match.
723 db()->NewGrouping(types::kSecondaryService, 0, kTestValue1)->set_active(true);
724 EXPECT_PACKET_OUT(kExpected);
725 fake_chan()->Receive(kRequest);
726 }
727
TEST_F(ServerTest,ReadByGroupTypeSingle)728 TEST_F(ServerTest, ReadByGroupTypeSingle) {
729 const StaticByteBuffer kTestValue('t', 'e', 's', 't');
730
731 // Start: 1, end: 2
732 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue);
733 grp->AddAttribute(
734 UUID(), att::AccessRequirements(), att::AccessRequirements());
735 grp->set_active(true);
736
737 // clang-format off
738 const StaticByteBuffer kRequest(
739 0x10, // opcode: read by group type
740 0x01, 0x00, // start: 0x0001
741 0xFF, 0xFF, // end: 0xFFFF
742 0x00, 0x28 // group type: 0x2800 (primary service)
743 );
744
745 const StaticByteBuffer kExpected(
746 0x11, // opcode: read by group type response
747 0x08, // length: 8 (strlen("test") + 4)
748 0x01, 0x00, // start: 0x0001
749 0x02, 0x00, // end: 0x0002
750 't', 'e', 's', 't' // value: "test"
751 );
752 // clang-format on
753
754 EXPECT_PACKET_OUT(kExpected);
755 fake_chan()->Receive(kRequest);
756 }
757
TEST_F(ServerTest,ReadByGroupTypeSingle128)758 TEST_F(ServerTest, ReadByGroupTypeSingle128) {
759 const StaticByteBuffer kTestValue('t', 'e', 's', 't');
760
761 // Start: 1, end: 2
762 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue);
763 grp->AddAttribute(
764 UUID(), att::AccessRequirements(), att::AccessRequirements());
765 grp->set_active(true);
766
767 // clang-format off
768 const StaticByteBuffer kRequest(
769 0x10, // opcode: read by group type
770 0x01, 0x00, // start: 0x0001
771 0xFF, 0xFF, // end: 0xFFFF
772
773 // group type: 00002800-0000-1000-8000-00805F9B34FB (primary service)
774 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
775 0x00, 0x10, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00);
776
777 const StaticByteBuffer kExpected(
778 0x11, // opcode: read by group type response
779 0x08, // length: 8 (strlen("test") + 4)
780 0x01, 0x00, // start: 0x0001
781 0x02, 0x00, // end: 0x0002
782 't', 'e', 's', 't' // value: "test"
783 );
784 // clang-format on
785
786 EXPECT_PACKET_OUT(kExpected);
787 fake_chan()->Receive(kRequest);
788 }
789
TEST_F(ServerTest,ReadByGroupTypeSingleTruncated)790 TEST_F(ServerTest, ReadByGroupTypeSingleTruncated) {
791 const StaticByteBuffer kTestValue('t', 'e', 's', 't');
792
793 // Start: 1, end: 1
794 auto* grp = db()->NewGrouping(types::kPrimaryService, 0, kTestValue);
795 grp->set_active(true);
796
797 // clang-format off
798 const StaticByteBuffer kRequest(
799 0x10, // opcode: read by group type
800 0x01, 0x00, // start: 0x0001
801 0xFF, 0xFF, // end: 0xFFFF
802 0x00, 0x28 // group type: 0x2800 (primary service)
803 );
804
805 const StaticByteBuffer kExpected(
806 0x11, // opcode: read by group type response
807 0x06, // length: 6 (strlen("te") + 4)
808 0x01, 0x00, // start: 0x0001
809 0x01, 0x00, // end: 0x0001
810 't', 'e' // value: "te"
811 );
812 // clang-format on
813
814 // Force the MTU to exactly fit |kExpected| which partially contains
815 // |kTestValue|.
816 att()->set_mtu(static_cast<uint16_t>(kExpected.size()));
817
818 EXPECT_PACKET_OUT(kExpected);
819 fake_chan()->Receive(kRequest);
820 }
821
TEST_F(ServerTest,ReadByGroupTypeMultipleSameValueSize)822 TEST_F(ServerTest, ReadByGroupTypeMultipleSameValueSize) {
823 // Start: 1, end: 1
824 db()->NewGrouping(types::kPrimaryService, 0, kTestValue1)->set_active(true);
825
826 // Start: 2, end: 2
827 auto* grp2 = db()->NewGrouping(types::kPrimaryService, 0, kTestValue2);
828 grp2->set_active(true);
829
830 // Start: 3, end: 3
831 db()->NewGrouping(types::kSecondaryService, 0, kTestValue3)->set_active(true);
832
833 // Start: 4, end: 4
834 db()->NewGrouping(types::kPrimaryService, 0, kTestValue3)->set_active(true);
835
836 // Start: 5, end: 5
837 db()->NewGrouping(types::kPrimaryService, 0, kTestValue4)->set_active(true);
838
839 // clang-format off
840 const StaticByteBuffer kRequest1(
841 0x10, // opcode: read by group type
842 0x01, 0x00, // start: 0x0001
843 0xFF, 0xFF, // end: 0xFFFF
844 0x00, 0x28 // group type: 0x2800 (primary service)
845 );
846
847 const StaticByteBuffer kExpected1(
848 0x11, // opcode: read by group type response
849 0x07, // length: 7 (strlen("foo") + 4)
850 0x01, 0x00, // start: 0x0001
851 0x01, 0x00, // end: 0x0001
852 'f', 'o', 'o', // value: "foo"
853 0x02, 0x00, // start: 0x0002
854 0x02, 0x00, // end: 0x0002
855 'b', 'a', 'r', // value: "bar"
856 0x04, 0x00, // start: 0x0004
857 0x04, 0x00, // end: 0x0004
858 'b', 'a', 'z' // value: "baz"
859 );
860 // clang-format on
861
862 // Set the MTU to be one byte too short to include the 5th attribute group.
863 // The 3rd group is omitted as its group type does not match.
864 att()->set_mtu(static_cast<uint16_t>(kExpected1.size() + 6));
865
866 EXPECT_PACKET_OUT(kExpected1);
867 fake_chan()->Receive(kRequest1);
868
869 // Search a narrower range. Only two groups should be returned even with room
870 // in MTU.
871 // clang-format off
872 const StaticByteBuffer kRequest2(
873 0x10, // opcode: read by group type
874 0x02, 0x00, // start: 0x0002
875 0x04, 0x00, // end: 0x0004
876 0x00, 0x28 // group type: 0x2800 (primary service)
877 );
878
879 const StaticByteBuffer kExpected2(
880 0x11, // opcode: read by group type response
881 0x07, // length: 7 (strlen("foo") + 4)
882 0x02, 0x00, // start: 0x0002
883 0x02, 0x00, // end: 0x0002
884 'b', 'a', 'r', // value: "bar"
885 0x04, 0x00, // start: 0x0004
886 0x04, 0x00, // end: 0x0004
887 'b', 'a', 'z' // value: "baz"
888 );
889 // clang-format on
890
891 EXPECT_PACKET_OUT(kExpected2);
892 fake_chan()->Receive(kRequest2);
893
894 // Make the second group inactive. It should get omitted.
895 // clang-format off
896 const StaticByteBuffer kExpected3(
897 0x11, // opcode: read by group type response
898 0x07, // length: 7 (strlen("foo") + 4)
899 0x04, 0x00, // start: 0x0004
900 0x04, 0x00, // end: 0x0004
901 'b', 'a', 'z' // value: "baz"
902 );
903 // clang-format on
904
905 grp2->set_active(false);
906 EXPECT_PACKET_OUT(kExpected3);
907 fake_chan()->Receive(kRequest2);
908 }
909
910 // The responses should only include 1 value because the next value has a
911 // different length.
TEST_F(ServerTest,ReadByGroupTypeMultipleVaryingLengths)912 TEST_F(ServerTest, ReadByGroupTypeMultipleVaryingLengths) {
913 // Start: 1, end: 1
914 db()->NewGrouping(types::kPrimaryService, 0, kTestValue1)->set_active(true);
915 // Start: 2, end: 2
916 db()->NewGrouping(types::kPrimaryService, 0, kTestValueLong)
917 ->set_active(true);
918 // Start: 3, end: 3
919 db()->NewGrouping(types::kPrimaryService, 0, kTestValue1)->set_active(true);
920
921 // clang-format off
922 const StaticByteBuffer kRequest1(
923 0x10, // opcode: read by group type
924 0x01, 0x00, // start: 0x0001
925 0xFF, 0xFF, // end: 0xFFFF
926 0x00, 0x28 // group type: 0x2800 (primary service)
927 );
928
929 const StaticByteBuffer kExpected1(
930 0x11, // opcode: read by group type response
931 0x07, // length: 7 (strlen("foo") + 4)
932 0x01, 0x00, // start: 0x0001
933 0x01, 0x00, // end: 0x0001
934 'f', 'o', 'o' // value: "foo"
935 );
936
937 const StaticByteBuffer kRequest2(
938 0x10, // opcode: read by group type
939 0x02, 0x00, // start: 0x0002
940 0xFF, 0xFF, // end: 0xFFFF
941 0x00, 0x28 // group type: 0x2800 (primary service)
942 );
943
944 const StaticByteBuffer kExpected2(
945 0x11, // opcode: read by group type response
946 0x08, // length: 8 (strlen("long") + 4)
947 0x02, 0x00, // start: 0x0002
948 0x02, 0x00, // end: 0x0002
949 'l', 'o', 'n', 'g' // value
950 );
951
952 const StaticByteBuffer kRequest3(
953 0x10, // opcode: read by group type
954 0x03, 0x00, // start: 0x0003
955 0xFF, 0xFF, // end: 0xFFFF
956 0x00, 0x28 // group type: 0x2800 (primary service)
957 );
958
959 const StaticByteBuffer kExpected3(
960 0x11, // opcode: read by group type response
961 0x07, // length: 7 (strlen("foo") + 4)
962 0x03, 0x00, // start: 0x0003
963 0x03, 0x00, // end: 0x0003
964 'f', 'o', 'o' // value: "foo"
965 );
966 // clang-format on
967
968 EXPECT_PACKET_OUT(kExpected1);
969 fake_chan()->Receive(kRequest1);
970 EXPECT_PACKET_OUT(kExpected2);
971 fake_chan()->Receive(kRequest2);
972 EXPECT_PACKET_OUT(kExpected3);
973 fake_chan()->Receive(kRequest3);
974 }
975
TEST_F(ServerTest,ReadByTypeInvalidPDU)976 TEST_F(ServerTest, ReadByTypeInvalidPDU) {
977 // Just opcode
978 // clang-format off
979 const StaticByteBuffer kInvalidPDU(0x08);
980 const StaticByteBuffer kExpected(
981 0x01, // opcode: error response
982 0x08, // request: read by type
983 0x00, 0x00, // handle: 0
984 0x04 // error: Invalid PDU
985 );
986 // clang-format on
987
988 EXPECT_PACKET_OUT(kExpected);
989 fake_chan()->Receive(kInvalidPDU);
990 }
991
TEST_F(ServerTest,ReadByTypeInvalidHandle)992 TEST_F(ServerTest, ReadByTypeInvalidHandle) {
993 // Start handle is 0
994 // clang-format off
995 const StaticByteBuffer kInvalidStartHandle(
996 0x08, // opcode: read by type
997 0x00, 0x00, // start: 0x0000
998 0xFF, 0xFF, // end: 0xFFFF
999 0x00, 0x28 // group type: 0x2800 (primary service)
1000 );
1001
1002 const StaticByteBuffer kExpected1(
1003 0x01, // opcode: error response
1004 0x08, // request: read by type
1005 0x00, 0x00, // handle: 0x0000 (start handle in request)
1006 0x01 // error: Invalid handle
1007 );
1008
1009 // End handle is smaller than start handle
1010 const StaticByteBuffer kInvalidEndHandle(
1011 0x08, // opcode: read by type
1012 0x02, 0x00, // start: 0x0002
1013 0x01, 0x00, // end: 0x0001
1014 0x00, 0x28 // group type: 0x2800 (primary service)
1015 );
1016
1017 const StaticByteBuffer kExpected2(
1018 0x01, // opcode: error response
1019 0x08, // request: read by type
1020 0x02, 0x00, // handle: 0x0002 (start handle in request)
1021 0x01 // error: Invalid handle
1022 );
1023 // clang-format on
1024
1025 EXPECT_PACKET_OUT(kExpected1);
1026 fake_chan()->Receive(kInvalidStartHandle);
1027 EXPECT_PACKET_OUT(kExpected2);
1028 fake_chan()->Receive(kInvalidEndHandle);
1029 }
1030
TEST_F(ServerTest,ReadByTypeAttributeNotFound)1031 TEST_F(ServerTest, ReadByTypeAttributeNotFound) {
1032 // clang-format off
1033 const StaticByteBuffer kRequest(
1034 0x08, // opcode: read by type
1035 0x01, 0x00, // start: 0x0001
1036 0xFF, 0xFF, // end: 0xFFFF
1037 0xEF, 0xBE // type: 0xBEEF
1038 );
1039
1040 const StaticByteBuffer kExpected(
1041 0x01, // opcode: error response
1042 0x08, // request: read by type
1043 0x01, 0x00, // handle: 0x0001 (start handle in request)
1044 0x0A // error: Attribute not found
1045 );
1046 // clang-format on
1047
1048 // Database is empty.
1049 EXPECT_PACKET_OUT(kExpected);
1050 fake_chan()->Receive(kRequest);
1051
1052 // Attribute type does not match.
1053 db()->NewGrouping(types::kSecondaryService, 0, kTestValue1)->set_active(true);
1054 EXPECT_PACKET_OUT(kExpected);
1055 fake_chan()->Receive(kRequest);
1056 }
1057
TEST_F(ServerTest,ReadByTypeDynamicValueNoHandler)1058 TEST_F(ServerTest, ReadByTypeDynamicValueNoHandler) {
1059 const StaticByteBuffer kTestValue('t', 'e', 's', 't');
1060
1061 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue);
1062 grp->AddAttribute(
1063 kTestType16, AllowedNoSecurity(), att::AccessRequirements());
1064 grp->set_active(true);
1065
1066 // clang-format off
1067 const StaticByteBuffer kRequest(
1068 0x08, // opcode: read by type
1069 0x01, 0x00, // start: 0x0001
1070 0xFF, 0xFF, // end: 0xFFFF
1071 0xEF, 0xBE // type: 0xBEEF
1072 );
1073
1074 const StaticByteBuffer kExpected(
1075 0x01, // opcode: error response
1076 0x08, // request: read by type
1077 0x02, 0x00, // handle: 0x0002 (the attribute causing the error)
1078 0x02 // error: Read not permitted
1079 );
1080 // clang-format on
1081
1082 EXPECT_PACKET_OUT(kExpected);
1083 fake_chan()->Receive(kRequest);
1084 }
1085
TEST_F(ServerTest,ReadByTypeDynamicValue)1086 TEST_F(ServerTest, ReadByTypeDynamicValue) {
1087 auto* grp = db()->NewGrouping(types::kPrimaryService, 2, kTestValue1);
1088 auto* attr = grp->AddAttribute(kTestType16, AllowedNoSecurity());
1089 attr->set_read_handler(
1090 [attr](PeerId, auto handle, uint16_t offset, auto result_cb) {
1091 EXPECT_EQ(attr->handle(), handle);
1092 EXPECT_EQ(0u, offset);
1093 result_cb(fit::ok(), StaticByteBuffer('f', 'o', 'r', 'k'));
1094 });
1095
1096 // Add a second dynamic attribute, which should be omitted.
1097 attr = grp->AddAttribute(kTestType16, AllowedNoSecurity());
1098 grp->set_active(true);
1099
1100 // clang-format off
1101 const StaticByteBuffer kRequest(
1102 0x08, // opcode: read by type
1103 0x01, 0x00, // start: 0x0001
1104 0xFF, 0xFF, // end: 0xFFFF
1105 0xEF, 0xBE // type: 0xBEEF
1106 );
1107
1108 const StaticByteBuffer kExpected(
1109 0x09, // opcode: read by type response
1110 0x06, // length: 6 (strlen("fork") + 2)
1111 0x02, 0x00, // handle: 0x0002
1112 'f', 'o', 'r', 'k' // value: "fork"
1113 );
1114 // clang-format on
1115
1116 EXPECT_PACKET_OUT(kExpected);
1117 fake_chan()->Receive(kRequest);
1118
1119 // Assign a static value to the second attribute. It should still be omitted
1120 // as the first attribute is dynamic.
1121 attr->SetValue(kTestValue1);
1122 EXPECT_PACKET_OUT(kExpected);
1123 fake_chan()->Receive(kRequest);
1124 }
1125
TEST_F(ServerTest,ReadByTypeDynamicValueError)1126 TEST_F(ServerTest, ReadByTypeDynamicValueError) {
1127 const StaticByteBuffer kTestValue('t', 'e', 's', 't');
1128
1129 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue);
1130 auto* attr = grp->AddAttribute(
1131 kTestType16, AllowedNoSecurity(), att::AccessRequirements());
1132 attr->set_read_handler([](PeerId, auto, uint16_t, auto result_cb) {
1133 result_cb(fit::error(att::ErrorCode::kUnlikelyError), BufferView());
1134 });
1135 grp->set_active(true);
1136
1137 // clang-format off
1138 const StaticByteBuffer kRequest(
1139 0x08, // opcode: read by type
1140 0x01, 0x00, // start: 0x0001
1141 0xFF, 0xFF, // end: 0xFFFF
1142 0xEF, 0xBE // type: 0xBEEF
1143 );
1144
1145 const StaticByteBuffer kExpected(
1146 0x01, // opcode: error response
1147 0x08, // request: read by type
1148 0x02, 0x00, // handle: 0x0002 (the attribute causing the error)
1149 0x0E // error: Unlikely error
1150 );
1151 // clang-format on
1152
1153 EXPECT_PACKET_OUT(kExpected);
1154 fake_chan()->Receive(kRequest);
1155 }
1156
TEST_F(ServerTest,ReadByTypeSingle)1157 TEST_F(ServerTest, ReadByTypeSingle) {
1158 const StaticByteBuffer kTestValue('t', 'e', 's', 't');
1159
1160 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue1);
1161 grp->AddAttribute(kTestType16, AllowedNoSecurity(), att::AccessRequirements())
1162 ->SetValue(kTestValue);
1163 grp->set_active(true);
1164
1165 // clang-format off
1166 const StaticByteBuffer kRequest(
1167 0x08, // opcode: read by type
1168 0x01, 0x00, // start: 0x0001
1169 0xFF, 0xFF, // end: 0xFFFF
1170 0xEF, 0xBE // type: 0xBEEF
1171 );
1172
1173 const StaticByteBuffer kExpected(
1174 0x09, // opcode: read by type response
1175 0x06, // length: 6 (strlen("test") + 2)
1176 0x02, 0x00, // handle: 0x0002
1177 't', 'e', 's', 't' // value: "test"
1178 );
1179
1180 // clang-format on
1181
1182 EXPECT_PACKET_OUT(kExpected);
1183 fake_chan()->Receive(kRequest);
1184 }
1185
TEST_F(ServerTest,ReadByTypeSingle128)1186 TEST_F(ServerTest, ReadByTypeSingle128) {
1187 const StaticByteBuffer kTestValue('t', 'e', 's', 't');
1188
1189 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue1);
1190 grp->AddAttribute(
1191 kTestType128, AllowedNoSecurity(), att::AccessRequirements())
1192 ->SetValue(kTestValue);
1193 grp->set_active(true);
1194
1195 // clang-format off
1196 const StaticByteBuffer kRequest(
1197 0x08, // opcode: read by type
1198 0x01, 0x00, // start: 0x0001
1199 0xFF, 0xFF, // end: 0xFFFF
1200
1201 // type: 0F0E0D0C-0B0A-0908-0706-050403020100
1202 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1203 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F);
1204
1205 const StaticByteBuffer kExpected(
1206 0x09, // opcode: read by type response
1207 0x06, // length: 6 (strlen("test") + 2)
1208 0x02, 0x00, // handle: 0x0002
1209 't', 'e', 's', 't' // value: "test"
1210 );
1211 // clang-format on
1212
1213 EXPECT_PACKET_OUT(kExpected);
1214 fake_chan()->Receive(kRequest);
1215 }
1216
TEST_F(ServerTest,ReadByTypeSingleTruncated)1217 TEST_F(ServerTest, ReadByTypeSingleTruncated) {
1218 const StaticByteBuffer kVeryLongValue(
1219 't', 'e', 's', 't', 'i', 'n', 'g', ' ', 'i', 's', ' ', 'f', 'u', 'n');
1220
1221 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue1);
1222 grp->AddAttribute(kTestType16, AllowedNoSecurity(), att::AccessRequirements())
1223 ->SetValue(kVeryLongValue);
1224 grp->set_active(true);
1225
1226 // clang-format off
1227 const StaticByteBuffer kRequest(
1228 0x08, // opcode: read by type
1229 0x01, 0x00, // start: 0x0001
1230 0xFF, 0xFF, // end: 0xFFFF
1231 0xEF, 0xBE // type: 0xBEEF
1232 );
1233
1234 const StaticByteBuffer kExpected(
1235 0x09, // opcode: read by type response
1236 0x05, // length: 5 (strlen("tes") + 2)
1237 0x02, 0x00, // handle: 0x0002
1238 't', 'e', 's' // value: "tes"
1239 );
1240 // clang-format on
1241
1242 // Force the MTU to exactly fit |kExpected| which partially contains
1243 // |kTestValue2| (the packet is crafted so that both |kRequest| and
1244 // |kExpected| fit within the MTU).
1245 att()->set_mtu(static_cast<uint16_t>(kExpected.size()));
1246
1247 EXPECT_PACKET_OUT(kExpected);
1248 fake_chan()->Receive(kRequest);
1249 }
1250
1251 // When there are more than one matching attributes, the list should end at the
1252 // first attribute that causes an error.
TEST_F(ServerTest,ReadByTypeMultipleExcludeFirstError)1253 TEST_F(ServerTest, ReadByTypeMultipleExcludeFirstError) {
1254 // handle 1: readable
1255 auto* grp = db()->NewGrouping(kTestType16, 1, kTestValue1);
1256
1257 // handle 2: not readable.
1258 grp->AddAttribute(kTestType16)->SetValue(kTestValue1);
1259 grp->set_active(true);
1260
1261 // clang-format off
1262 const StaticByteBuffer kRequest(
1263 0x08, // opcode: read by type
1264 0x01, 0x00, // start: 0x0001
1265 0xFF, 0xFF, // end: 0xFFFF
1266 0xEF, 0xBE // type: 0xBEEF
1267 );
1268 const StaticByteBuffer kExpected(
1269 0x09, // opcode: read by type response
1270 0x05, // length: 5 (strlen("foo") + 2)
1271 0x01, 0x00, // handle: 0x0001
1272 'f', 'o', 'o' // value: "foo"
1273 );
1274 // clang-format on
1275
1276 EXPECT_PACKET_OUT(kExpected);
1277 fake_chan()->Receive(kRequest);
1278 }
1279
TEST_F(ServerTest,ReadByTypeMultipleSameValueSize)1280 TEST_F(ServerTest, ReadByTypeMultipleSameValueSize) {
1281 // handle: 1, value: foo
1282 auto* grp = db()->NewGrouping(types::kPrimaryService, 2, kTestValue1);
1283
1284 // handle: 2, value: foo
1285 grp->AddAttribute(kTestType16, AllowedNoSecurity(), att::AccessRequirements())
1286 ->SetValue(kTestValue1);
1287
1288 // handle: 3, value: bar
1289 grp->AddAttribute(kTestType16, AllowedNoSecurity(), att::AccessRequirements())
1290 ->SetValue(kTestValue2);
1291 grp->set_active(true);
1292
1293 // handle: 4, value: foo (new grouping)
1294 grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue1);
1295
1296 // handle: 5, value: baz
1297 grp->AddAttribute(kTestType16, AllowedNoSecurity(), att::AccessRequirements())
1298 ->SetValue(kTestValue3);
1299 grp->set_active(true);
1300
1301 // clang-format off
1302 const StaticByteBuffer kRequest1(
1303 0x08, // opcode: read by type
1304 0x01, 0x00, // start: 0x0001
1305 0xFF, 0xFF, // end: 0xFFFF
1306 0xEF, 0xBE // type: 0xBEEF
1307 );
1308
1309 const StaticByteBuffer kExpected1(
1310 0x09, // opcode: read by type response
1311 0x05, // length: 5 (strlen("foo") + 2)
1312 0x02, 0x00, // handle: 0x0002
1313 'f', 'o', 'o', // value: "foo"
1314 0x03, 0x00, // handle: 0x0003
1315 'b', 'a', 'r', // value: "bar"
1316 0x05, 0x00, // handle: 0x0005
1317 'b', 'a', 'z' // value: "baz"
1318 );
1319 // clang-format on
1320
1321 EXPECT_PACKET_OUT(kExpected1);
1322 fake_chan()->Receive(kRequest1);
1323
1324 // Set the MTU 1 byte too short for |kExpected1|.
1325 att()->set_mtu(static_cast<uint16_t>(kExpected1.size() - 1));
1326
1327 // clang-format off
1328 const StaticByteBuffer kExpected2(
1329 0x09, // opcode: read by type response
1330 0x05, // length: 5 (strlen("foo") + 2)
1331 0x02, 0x00, // handle: 0x0002
1332 'f', 'o', 'o', // value: "foo"
1333 0x03, 0x00, // handle: 0x0003
1334 'b', 'a', 'r' // value: "bar"
1335 );
1336 // clang-format on
1337
1338 EXPECT_PACKET_OUT(kExpected2);
1339 fake_chan()->Receive(kRequest1);
1340
1341 // Try a different range.
1342 // clang-format off
1343 const StaticByteBuffer kRequest2(
1344 0x08, // opcode: read by type
1345 0x03, 0x00, // start: 0x0003
1346 0x05, 0x00, // end: 0x0005
1347 0xEF, 0xBE // type: 0xBEEF
1348 );
1349
1350 const StaticByteBuffer kExpected3(
1351 0x09, // opcode: read by type response
1352 0x05, // length: 5 (strlen("bar") + 2)
1353 0x03, 0x00, // handle: 0x0003
1354 'b', 'a', 'r', // value: "bar"
1355 0x05, 0x00, // handle: 0x0005
1356 'b', 'a', 'z' // value: "baz"
1357 );
1358 // clang-format on
1359
1360 EXPECT_PACKET_OUT(kExpected3);
1361 fake_chan()->Receive(kRequest2);
1362
1363 // Make the second group inactive.
1364 grp->set_active(false);
1365
1366 // clang-format off
1367 const StaticByteBuffer kExpected4(
1368 0x09, // opcode: read by type response
1369 0x05, // length: 5 (strlen("bar") + 2)
1370 0x03, 0x00, // handle: 0x0003
1371 'b', 'a', 'r' // value: "bar"
1372 );
1373 // clang-format on
1374
1375 EXPECT_PACKET_OUT(kExpected4);
1376 fake_chan()->Receive(kRequest2);
1377 }
1378
1379 // A response packet should only include consecutive attributes with the same
1380 // value size.
TEST_F(ServerTest,ReadByTypeMultipleVaryingLengths)1381 TEST_F(ServerTest, ReadByTypeMultipleVaryingLengths) {
1382 // handle: 1 - value: "foo"
1383 auto* grp = db()->NewGrouping(kTestType16, 2, kTestValue1);
1384
1385 // handle: 2 - value: "long"
1386 grp->AddAttribute(kTestType16, AllowedNoSecurity())->SetValue(kTestValueLong);
1387
1388 // handle: 3 - value: "foo"
1389 grp->AddAttribute(kTestType16, AllowedNoSecurity())->SetValue(kTestValue1);
1390 grp->set_active(true);
1391
1392 // Even though we have 3 attributes with a matching type, the requests below
1393 // will always return one attribute at a time as their values have different
1394 // sizes.
1395
1396 // clang-format off
1397 const StaticByteBuffer kRequest1(
1398 0x08, // opcode: read by type
1399 0x01, 0x00, // start: 0x0001
1400 0xFF, 0xFF, // end: 0xFFFF
1401 0xEF, 0xBE // type: 0xBEEF
1402 );
1403 const StaticByteBuffer kExpected1(
1404 0x09, // opcode: read by type response
1405 0x05, // length: 5 (strlen("foo") + 2)
1406 0x01, 0x00, // handle: 0x0001
1407 'f', 'o', 'o' // value: "foo"
1408 );
1409 const StaticByteBuffer kRequest2(
1410 0x08, // opcode: read by type
1411 0x02, 0x00, // start: 0x0002
1412 0xFF, 0xFF, // end: 0xFFFF
1413 0xEF, 0xBE // type: 0xBEEF
1414 );
1415 const StaticByteBuffer kExpected2(
1416 0x09, // opcode: read by type response
1417 0x06, // length: 6 (strlen("long") + 2)
1418 0x02, 0x00, // handle: 0x0002
1419 'l', 'o', 'n', 'g' // value: "long"
1420 );
1421 const StaticByteBuffer kRequest3(
1422 0x08, // opcode: read by type
1423 0x03, 0x00, // start: 0x0003
1424 0xFF, 0xFF, // end: 0xFFFF
1425 0xEF, 0xBE // type: 0xBEEF
1426 );
1427 const StaticByteBuffer kExpected3(
1428 0x09, // opcode: read by type response
1429 0x05, // length: 5 (strlen("foo") + 2)
1430 0x03, 0x00, // handle: 0x0003
1431 'f', 'o', 'o' // value: "foo"
1432 );
1433 // clang-format on
1434
1435 EXPECT_PACKET_OUT(kExpected1);
1436 fake_chan()->Receive(kRequest1);
1437 EXPECT_PACKET_OUT(kExpected2);
1438 fake_chan()->Receive(kRequest2);
1439 EXPECT_PACKET_OUT(kExpected3);
1440 fake_chan()->Receive(kRequest3);
1441 }
1442
1443 // When there are more than one matching attributes, the list should end at the
1444 // first attribute with a dynamic value.
TEST_F(ServerTest,ReadByTypeMultipleExcludeFirstDynamic)1445 TEST_F(ServerTest, ReadByTypeMultipleExcludeFirstDynamic) {
1446 // handle: 1 - value: "foo"
1447 auto* grp = db()->NewGrouping(kTestType16, 1, kTestValue1);
1448
1449 // handle: 2 - value: dynamic
1450 grp->AddAttribute(kTestType16, AllowedNoSecurity());
1451 grp->set_active(true);
1452
1453 // clang-format off
1454 const StaticByteBuffer kRequest(
1455 0x08, // opcode: read by type
1456 0x01, 0x00, // start: 0x0001
1457 0xFF, 0xFF, // end: 0xFFFF
1458 0xEF, 0xBE // type: 0xBEEF
1459 );
1460 const StaticByteBuffer kExpected(
1461 0x09, // opcode: read by type response
1462 0x05, // length: 5 (strlen("foo") + 2)
1463 0x01, 0x00, // handle: 0x0001
1464 'f', 'o', 'o' // value: "foo"
1465 );
1466 // clang-format on
1467
1468 EXPECT_PACKET_OUT(kExpected);
1469 fake_chan()->Receive(kRequest);
1470 }
1471
TEST_F(ServerTest,WriteRequestInvalidPDU)1472 TEST_F(ServerTest, WriteRequestInvalidPDU) {
1473 // Just opcode
1474 // clang-format off
1475 const StaticByteBuffer kInvalidPDU(0x12);
1476 const StaticByteBuffer kExpected(
1477 0x01, // opcode: error response
1478 0x12, // request: write request
1479 0x00, 0x00, // handle: 0
1480 0x04 // error: Invalid PDU
1481 );
1482 // clang-format on
1483
1484 EXPECT_PACKET_OUT(kExpected);
1485 fake_chan()->Receive(kInvalidPDU);
1486 }
1487
TEST_F(ServerTest,WriteRequestInvalidHandle)1488 TEST_F(ServerTest, WriteRequestInvalidHandle) {
1489 // clang-format off
1490 const StaticByteBuffer kRequest(
1491 0x12, // opcode: write request
1492 0x01, 0x00, // handle: 0x0001
1493
1494 // value: "test"
1495 't', 'e', 's', 't');
1496
1497 const StaticByteBuffer kExpected(
1498 0x01, // opcode: error response
1499 0x12, // request: write request
1500 0x01, 0x00, // handle: 0x0001
1501 0x01 // error: invalid handle
1502 );
1503 // clang-format on
1504
1505 EXPECT_PACKET_OUT(kExpected);
1506 fake_chan()->Receive(kRequest);
1507 }
1508
TEST_F(ServerTest,WriteRequestSecurity)1509 TEST_F(ServerTest, WriteRequestSecurity) {
1510 const StaticByteBuffer kTestValue('f', 'o', 'o');
1511 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue);
1512
1513 // Requires encryption
1514 grp->AddAttribute(kTestType16,
1515 att::AccessRequirements(),
1516 att::AccessRequirements(/*encryption=*/true,
1517 /*authentication=*/false,
1518 /*authorization=*/false));
1519 grp->set_active(true);
1520
1521 // We send two write requests:
1522 // 1. 0x0001: not writable
1523 // 2. 0x0002: writable but requires encryption
1524 //
1525 // clang-format off
1526 const StaticByteBuffer kRequest1(
1527 0x12, // opcode: write request
1528 0x01, 0x00, // handle: 0x0001
1529
1530 // value: "test"
1531 't', 'e', 's', 't');
1532
1533 const StaticByteBuffer kExpected1(
1534 0x01, // opcode: error response
1535 0x12, // request: write request
1536 0x01, 0x00, // handle: 0x0001
1537 0x03 // error: write not permitted
1538 );
1539 const StaticByteBuffer kRequest2(
1540 0x12, // opcode: write request
1541 0x02, 0x00, // handle: 0x0002
1542
1543 // value: "test"
1544 't', 'e', 's', 't');
1545
1546 const StaticByteBuffer kExpected2(
1547 0x01, // opcode: error response
1548 0x12, // request: write request
1549 0x02, 0x00, // handle: 0x0002
1550 0x05 // error: insufficient authentication
1551 );
1552 // clang-format on
1553
1554 EXPECT_PACKET_OUT(kExpected1);
1555 fake_chan()->Receive(kRequest1);
1556 EXPECT_PACKET_OUT(kExpected2);
1557 fake_chan()->Receive(kRequest2);
1558 }
1559
TEST_F(ServerTest,WriteRequestNoHandler)1560 TEST_F(ServerTest, WriteRequestNoHandler) {
1561 const StaticByteBuffer kTestValue('f', 'o', 'o');
1562 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue);
1563
1564 grp->AddAttribute(
1565 kTestType16, att::AccessRequirements(), AllowedNoSecurity());
1566 grp->set_active(true);
1567
1568 // clang-format off
1569 const StaticByteBuffer kRequest(
1570 0x12, // opcode: write request
1571 0x02, 0x00, // handle: 0x0002
1572
1573 // value: "test"
1574 't', 'e', 's', 't');
1575
1576 const StaticByteBuffer kExpected(
1577 0x01, // opcode: error response
1578 0x12, // request: write request
1579 0x02, 0x00, // handle: 0x0002
1580 0x03 // error: write not permitted
1581 );
1582 // clang-format on
1583
1584 EXPECT_PACKET_OUT(kExpected);
1585 fake_chan()->Receive(kRequest);
1586 }
1587
TEST_F(ServerTest,WriteRequestError)1588 TEST_F(ServerTest, WriteRequestError) {
1589 const StaticByteBuffer kTestValue('f', 'o', 'o');
1590 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue);
1591 auto* attr = grp->AddAttribute(
1592 kTestType16, att::AccessRequirements(), AllowedNoSecurity());
1593
1594 attr->set_write_handler([&](PeerId peer_id,
1595 att::Handle handle,
1596 uint16_t offset,
1597 const auto& value,
1598 auto result_cb) {
1599 EXPECT_EQ(kTestPeerId, peer_id);
1600 EXPECT_EQ(attr->handle(), handle);
1601 EXPECT_EQ(0u, offset);
1602 EXPECT_TRUE(ContainersEqual(StaticByteBuffer('t', 'e', 's', 't'), value));
1603
1604 result_cb(fit::error(att::ErrorCode::kUnlikelyError));
1605 });
1606 grp->set_active(true);
1607
1608 // clang-format off
1609 const StaticByteBuffer kRequest(
1610 0x12, // opcode: write request
1611 0x02, 0x00, // handle: 0x0002
1612
1613 // value: "test"
1614 't', 'e', 's', 't');
1615
1616 const StaticByteBuffer kExpected(
1617 0x01, // opcode: error response
1618 0x12, // request: write request
1619 0x02, 0x00, // handle: 0x0002
1620 0x0E // error: unlikely error
1621 );
1622 // clang-format on
1623
1624 EXPECT_PACKET_OUT(kExpected);
1625 fake_chan()->Receive(kRequest);
1626 }
1627
TEST_F(ServerTest,WriteRequestSuccess)1628 TEST_F(ServerTest, WriteRequestSuccess) {
1629 const StaticByteBuffer kTestValue('f', 'o', 'o');
1630 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue);
1631 auto* attr = grp->AddAttribute(
1632 kTestType16, att::AccessRequirements(), AllowedNoSecurity());
1633
1634 attr->set_write_handler([&](PeerId peer_id,
1635 att::Handle handle,
1636 uint16_t offset,
1637 const auto& value,
1638 auto result_cb) {
1639 EXPECT_EQ(kTestPeerId, peer_id);
1640 EXPECT_EQ(attr->handle(), handle);
1641 EXPECT_EQ(0u, offset);
1642 EXPECT_TRUE(ContainersEqual(StaticByteBuffer('t', 'e', 's', 't'), value));
1643
1644 result_cb(fit::ok());
1645 });
1646 grp->set_active(true);
1647
1648 // clang-format off
1649 const StaticByteBuffer kRequest(
1650 0x12, // opcode: write request
1651 0x02, 0x00, // handle: 0x0002
1652
1653 // value: "test"
1654 't', 'e', 's', 't');
1655 // clang-format on
1656
1657 // opcode: write response
1658 const StaticByteBuffer kExpected(0x13);
1659
1660 EXPECT_PACKET_OUT(kExpected);
1661 fake_chan()->Receive(kRequest);
1662 }
1663
1664 // TODO(bwb): Add test cases for the error conditions involved in a Write
1665 // Command (fxbug.dev/42146420)
1666
TEST_F(ServerTest,WriteCommandSuccess)1667 TEST_F(ServerTest, WriteCommandSuccess) {
1668 const StaticByteBuffer kTestValue('f', 'o', 'o');
1669 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue);
1670 auto* attr = grp->AddAttribute(
1671 kTestType16, att::AccessRequirements(), AllowedNoSecurity());
1672
1673 attr->set_write_handler([&](PeerId peer_id,
1674 att::Handle handle,
1675 uint16_t offset,
1676 const auto& value,
1677 const auto&) {
1678 EXPECT_EQ(kTestPeerId, peer_id);
1679 EXPECT_EQ(attr->handle(), handle);
1680 EXPECT_EQ(0u, offset);
1681 EXPECT_TRUE(ContainersEqual(StaticByteBuffer('t', 'e', 's', 't'), value));
1682 });
1683 grp->set_active(true);
1684
1685 // clang-format off
1686 const StaticByteBuffer kCmd(
1687 0x52, // opcode: write command
1688 0x02, 0x00, // handle: 0x0002
1689 't', 'e', 's', 't');
1690 // clang-format on
1691
1692 fake_chan()->Receive(kCmd);
1693 }
1694
TEST_F(ServerTest,ReadRequestInvalidPDU)1695 TEST_F(ServerTest, ReadRequestInvalidPDU) {
1696 // Just opcode
1697 // clang-format off
1698 const StaticByteBuffer kInvalidPDU(0x0A);
1699 const StaticByteBuffer kExpected(
1700 0x01, // opcode: error response
1701 0x0A, // request: read request
1702 0x00, 0x00, // handle: 0
1703 0x04 // error: Invalid PDU
1704 );
1705 // clang-format on
1706
1707 EXPECT_PACKET_OUT(kExpected);
1708 fake_chan()->Receive(kInvalidPDU);
1709 }
1710
TEST_F(ServerTest,ReadRequestInvalidHandle)1711 TEST_F(ServerTest, ReadRequestInvalidHandle) {
1712 // clang-format off
1713 const StaticByteBuffer kRequest(
1714 0x0A, // opcode: read request
1715 0x01, 0x00 // handle: 0x0001
1716 );
1717
1718 const StaticByteBuffer kExpected(
1719 0x01, // opcode: error response
1720 0x0A, // request: read request
1721 0x01, 0x00, // handle: 0x0001
1722 0x01 // error: invalid handle
1723 );
1724 // clang-format on
1725
1726 EXPECT_PACKET_OUT(kExpected);
1727 fake_chan()->Receive(kRequest);
1728 }
1729
TEST_F(ServerTest,ReadRequestSecurity)1730 TEST_F(ServerTest, ReadRequestSecurity) {
1731 const StaticByteBuffer kTestValue('f', 'o', 'o');
1732 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue);
1733
1734 // Requires encryption
1735 grp->AddAttribute(kTestType16,
1736 att::AccessRequirements(/*encryption=*/true,
1737 /*authentication=*/false,
1738 /*authorization=*/false),
1739 att::AccessRequirements());
1740 grp->set_active(true);
1741
1742 // clang-format off
1743 const StaticByteBuffer kRequest(
1744 0x0A, // opcode: read request
1745 0x02, 0x00 // handle: 0x0002
1746 );
1747 const StaticByteBuffer kExpected(
1748 0x01, // opcode: error response
1749 0x0A, // request: read request
1750 0x02, 0x00, // handle: 0x0002
1751 0x05 // error: insufficient authentication
1752 );
1753 // clang-format on
1754
1755 EXPECT_PACKET_OUT(kExpected);
1756 fake_chan()->Receive(kRequest);
1757 }
1758
TEST_F(ServerTest,ReadRequestCached)1759 TEST_F(ServerTest, ReadRequestCached) {
1760 const StaticByteBuffer kDeclValue('d', 'e', 'c', 'l');
1761 const StaticByteBuffer kTestValue('f', 'o', 'o');
1762 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kDeclValue);
1763 auto* attr = grp->AddAttribute(
1764 kTestType16, AllowedNoSecurity(), att::AccessRequirements());
1765 attr->SetValue(kTestValue);
1766 grp->set_active(true);
1767
1768 // clang-format off
1769 const StaticByteBuffer kRequest1(
1770 0x0A, // opcode: read request
1771 0x01, 0x00 // handle: 0x0001
1772 );
1773 const StaticByteBuffer kExpected1(
1774 0x0B, // opcode: read response
1775 'd', 'e', 'c', 'l' // value: kDeclValue
1776 );
1777 const StaticByteBuffer kRequest2(
1778 0x0A, // opcode: read request
1779 0x02, 0x00 // handle: 0x0002
1780 );
1781 const StaticByteBuffer kExpected2(
1782 0x0B, // opcode: read response
1783 'f', 'o', 'o' // value: kTestValue
1784 );
1785 // clang-format on
1786
1787 EXPECT_PACKET_OUT(kExpected1);
1788 fake_chan()->Receive(kRequest1);
1789 EXPECT_PACKET_OUT(kExpected2);
1790 fake_chan()->Receive(kRequest2);
1791 }
1792
TEST_F(ServerTest,ReadRequestNoHandler)1793 TEST_F(ServerTest, ReadRequestNoHandler) {
1794 const StaticByteBuffer kTestValue('f', 'o', 'o');
1795 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue);
1796
1797 grp->AddAttribute(
1798 kTestType16, AllowedNoSecurity(), att::AccessRequirements());
1799 grp->set_active(true);
1800
1801 // clang-format off
1802 const StaticByteBuffer kRequest(
1803 0x0A, // opcode: read request
1804 0x02, 0x00 // handle: 0x0002
1805 );
1806
1807 const StaticByteBuffer kExpected(
1808 0x01, // opcode: error response
1809 0x0A, // request: read request
1810 0x02, 0x00, // handle: 0x0002
1811 0x02 // error: read not permitted
1812 );
1813 // clang-format on
1814
1815 EXPECT_PACKET_OUT(kExpected);
1816 fake_chan()->Receive(kRequest);
1817 }
1818
TEST_F(ServerTest,ReadRequestError)1819 TEST_F(ServerTest, ReadRequestError) {
1820 const StaticByteBuffer kTestValue('f', 'o', 'o');
1821 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue);
1822 auto* attr = grp->AddAttribute(
1823 kTestType16, AllowedNoSecurity(), att::AccessRequirements());
1824 attr->set_read_handler(
1825 [&](PeerId peer_id, att::Handle handle, uint16_t offset, auto result_cb) {
1826 EXPECT_EQ(kTestPeerId, peer_id);
1827 EXPECT_EQ(attr->handle(), handle);
1828 EXPECT_EQ(0u, offset);
1829
1830 result_cb(fit::error(att::ErrorCode::kUnlikelyError), BufferView());
1831 });
1832 grp->set_active(true);
1833
1834 // clang-format off
1835 const StaticByteBuffer kRequest(
1836 0x0A, // opcode: read request
1837 0x02, 0x00 // handle: 0x0002
1838 );
1839
1840 const StaticByteBuffer kExpected(
1841 0x01, // opcode: error response
1842 0x0A, // request: read request
1843 0x02, 0x00, // handle: 0x0002
1844 0x0E // error: unlikely error
1845 );
1846 // clang-format on
1847
1848 EXPECT_PACKET_OUT(kExpected);
1849 fake_chan()->Receive(kRequest);
1850 }
1851
TEST_F(ServerTest,ReadBlobRequestInvalidPDU)1852 TEST_F(ServerTest, ReadBlobRequestInvalidPDU) {
1853 // Just opcode
1854 // clang-format off
1855 const StaticByteBuffer kInvalidPDU(0x0C);
1856 const StaticByteBuffer kExpected(
1857 0x01, // opcode: error response
1858 0x0C, // request: read blob request
1859 0x00, 0x00, // handle: 0
1860 0x04 // error: Invalid PDU
1861 );
1862 // clang-format on
1863
1864 EXPECT_PACKET_OUT(kExpected);
1865 fake_chan()->Receive(kInvalidPDU);
1866 }
1867
TEST_F(ServerTest,ReadBlobRequestDynamicSuccess)1868 TEST_F(ServerTest, ReadBlobRequestDynamicSuccess) {
1869 const StaticByteBuffer kDeclValue('d', 'e', 'c', 'l');
1870 const StaticByteBuffer kTestValue('A',
1871 ' ',
1872 'V',
1873 'e',
1874 'r',
1875 'y',
1876 ' ',
1877 'L',
1878 'o',
1879 'n',
1880 'g',
1881 ' ',
1882 'D',
1883 'e',
1884 'v',
1885 'i',
1886 'c',
1887 'e',
1888 ' ',
1889 'N',
1890 'a',
1891 'm',
1892 'e',
1893 ' ',
1894 'U',
1895 's',
1896 'i',
1897 'n',
1898 'g',
1899 ' ',
1900 'A',
1901 ' ',
1902 'L',
1903 'o',
1904 'n',
1905 'g',
1906 ' ',
1907 'A',
1908 't',
1909 't',
1910 'r',
1911 'i',
1912 'b',
1913 'u',
1914 't',
1915 'e');
1916
1917 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue);
1918 auto* attr = grp->AddAttribute(
1919 kTestType16, AllowedNoSecurity(), att::AccessRequirements());
1920
1921 attr->set_read_handler(
1922 [&](PeerId peer_id, att::Handle handle, uint16_t offset, auto result_cb) {
1923 EXPECT_EQ(kTestPeerId, peer_id);
1924 EXPECT_EQ(attr->handle(), handle);
1925 EXPECT_EQ(22u, offset);
1926 result_cb(fit::ok(),
1927 StaticByteBuffer('e',
1928 ' ',
1929 'U',
1930 's',
1931 'i',
1932 'n',
1933 'g',
1934 ' ',
1935 'A',
1936 ' ',
1937 'L',
1938 'o',
1939 'n',
1940 'g',
1941 ' ',
1942 'A',
1943 't',
1944 't',
1945 'r',
1946 'i',
1947 'b',
1948 'u'));
1949 });
1950 grp->set_active(true);
1951
1952 // clang-format off
1953 const StaticByteBuffer kRequest(
1954 0x0C, // opcode: read blob request
1955 0x02, 0x00, // handle: 0x0002
1956 0x16, 0x00 // offset: 0x0016
1957 );
1958 const StaticByteBuffer kExpected(
1959 0x0D, // opcode: read blob response
1960 // Read Request response
1961 'e', ' ', 'U', 's', 'i', 'n', 'g', ' ', 'A', ' ', 'L',
1962 'o', 'n', 'g', ' ', 'A', 't', 't', 'r', 'i', 'b', 'u'
1963 );
1964 // clang-format on
1965
1966 EXPECT_PACKET_OUT(kExpected);
1967 fake_chan()->Receive(kRequest);
1968 }
1969
TEST_F(ServerTest,ReadBlobDynamicRequestError)1970 TEST_F(ServerTest, ReadBlobDynamicRequestError) {
1971 const StaticByteBuffer kTestValue('A',
1972 ' ',
1973 'V',
1974 'e',
1975 'r',
1976 'y',
1977 ' ',
1978 'L',
1979 'o',
1980 'n',
1981 'g',
1982 ' ',
1983 'D',
1984 'e',
1985 'v',
1986 'i',
1987 'c',
1988 'e',
1989 ' ',
1990 'N',
1991 'a',
1992 'm',
1993 'e',
1994 ' ',
1995 'U',
1996 's',
1997 'i',
1998 'n',
1999 'g',
2000 ' ',
2001 'A',
2002 ' ',
2003 'L',
2004 'o',
2005 'n',
2006 'g',
2007 ' ',
2008 'A',
2009 't',
2010 't',
2011 'r',
2012 'i',
2013 'b',
2014 'u',
2015 't',
2016 'e');
2017 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue);
2018 auto* attr = grp->AddAttribute(
2019 kTestType16, AllowedNoSecurity(), att::AccessRequirements());
2020 attr->set_read_handler(
2021 [&](PeerId peer_id, att::Handle handle, uint16_t, auto result_cb) {
2022 EXPECT_EQ(kTestPeerId, peer_id);
2023 EXPECT_EQ(attr->handle(), handle);
2024
2025 result_cb(fit::error(att::ErrorCode::kUnlikelyError), BufferView());
2026 });
2027 grp->set_active(true);
2028
2029 // clang-format off
2030 const StaticByteBuffer kRequest(
2031 0x0C, // opcode: read blob request
2032 0x02, 0x00, // handle: 0x0002
2033 0x16, 0x00 // offset: 0x0016
2034 );
2035 const StaticByteBuffer kExpected(
2036 0x01, // opcode: error response
2037 0x0C, // request: read by type
2038 0x02, 0x00, // handle: 0x0002 (the attribute causing the error)
2039 0x0E // error: Unlikely error
2040 );
2041 // clang-format on
2042
2043 EXPECT_PACKET_OUT(kExpected);
2044 fake_chan()->Receive(kRequest);
2045 }
2046
TEST_F(ServerTest,ReadBlobRequestStaticSuccess)2047 TEST_F(ServerTest, ReadBlobRequestStaticSuccess) {
2048 const StaticByteBuffer kTestValue('A',
2049 ' ',
2050 'V',
2051 'e',
2052 'r',
2053 'y',
2054 ' ',
2055 'L',
2056 'o',
2057 'n',
2058 'g',
2059 ' ',
2060 'D',
2061 'e',
2062 'v',
2063 'i',
2064 'c',
2065 'e',
2066 ' ',
2067 'N',
2068 'a',
2069 'm',
2070 'e',
2071 ' ',
2072 'U',
2073 's',
2074 'i',
2075 'n',
2076 'g',
2077 ' ',
2078 'A',
2079 ' ',
2080 'L',
2081 'o',
2082 'n',
2083 'g',
2084 ' ',
2085 'A',
2086 't',
2087 't',
2088 'r',
2089 'i',
2090 'b',
2091 'u',
2092 't',
2093 'e');
2094
2095 auto* grp = db()->NewGrouping(types::kPrimaryService, 0, kTestValue);
2096 grp->set_active(true);
2097
2098 // clang-format off
2099 const StaticByteBuffer kRequest(
2100 0x0C, // opcode: read blob request
2101 0x01, 0x00, // handle: 0x0002
2102 0x16, 0x00 // offset: 0x0016
2103 );
2104 const StaticByteBuffer kExpected(
2105 0x0D, // opcode: read blob response
2106 // Read Request response
2107 'e', ' ', 'U', 's', 'i', 'n', 'g', ' ', 'A', ' ', 'L',
2108 'o', 'n', 'g', ' ', 'A', 't', 't', 'r', 'i', 'b', 'u'
2109 );
2110 // clang-format on
2111
2112 EXPECT_PACKET_OUT(kExpected);
2113 fake_chan()->Receive(kRequest);
2114 }
2115
TEST_F(ServerTest,ReadBlobRequestStaticOverflowError)2116 TEST_F(ServerTest, ReadBlobRequestStaticOverflowError) {
2117 const StaticByteBuffer kTestValue('s', 'h', 'o', 'r', 't', 'e', 'r');
2118
2119 auto* grp = db()->NewGrouping(types::kPrimaryService, 0, kTestValue);
2120 grp->set_active(true);
2121
2122 // clang-format off
2123 const StaticByteBuffer kRequest(
2124 0x0C, // opcode: read blob request
2125 0x01, 0x00, // handle: 0x0001
2126 0x16, 0x10 // offset: 0x1016
2127 );
2128 const StaticByteBuffer kExpected(
2129 0x01, // Error
2130 0x0C, // opcode
2131 0x01, 0x00, // handle: 0x0001
2132 0x07 // InvalidOffset
2133 );
2134 // clang-format on
2135
2136 EXPECT_PACKET_OUT(kExpected);
2137 fake_chan()->Receive(kRequest);
2138 }
2139
TEST_F(ServerTest,ReadBlobRequestInvalidHandleError)2140 TEST_F(ServerTest, ReadBlobRequestInvalidHandleError) {
2141 const StaticByteBuffer kTestValue('A',
2142 ' ',
2143 'V',
2144 'e',
2145 'r',
2146 'y',
2147 ' ',
2148 'L',
2149 'o',
2150 'n',
2151 'g',
2152 ' ',
2153 'D',
2154 'e',
2155 'v',
2156 'i',
2157 'c',
2158 'e',
2159 ' ',
2160 'N',
2161 'a',
2162 'm',
2163 'e',
2164 ' ',
2165 'U',
2166 's',
2167 'i',
2168 'n',
2169 'g',
2170 ' ',
2171 'A',
2172 ' ',
2173 'L',
2174 'o',
2175 'n',
2176 'g',
2177 ' ',
2178 'A',
2179 't',
2180 't',
2181 'r',
2182 'i',
2183 'b',
2184 'u',
2185 't',
2186 'e');
2187 auto* grp = db()->NewGrouping(types::kPrimaryService, 0, kTestValue);
2188 grp->set_active(true);
2189
2190 // clang-format off
2191 const StaticByteBuffer kRequest(
2192 0x0C, // opcode: read blob request
2193 0x02, 0x30, // handle: 0x0002
2194 0x16, 0x00 // offset: 0x0016
2195 );
2196 const StaticByteBuffer kExpected(
2197 0x01, // opcode: error response
2198 0x0C, // request: read blob request
2199 0x02, 0x30, // handle: 0x0001
2200 0x01 // error: invalid handle
2201 );
2202 // clang-format on
2203
2204 EXPECT_PACKET_OUT(kExpected);
2205 fake_chan()->Receive(kRequest);
2206 }
2207
TEST_F(ServerTest,ReadBlobRequestNotPermitedError)2208 TEST_F(ServerTest, ReadBlobRequestNotPermitedError) {
2209 const StaticByteBuffer kTestValue('A',
2210 ' ',
2211 'V',
2212 'e',
2213 'r',
2214 'y',
2215 ' ',
2216 'L',
2217 'o',
2218 'n',
2219 'g',
2220 ' ',
2221 'D',
2222 'e',
2223 'v',
2224 'i',
2225 'c',
2226 'e',
2227 ' ',
2228 'N',
2229 'a',
2230 'm',
2231 'e',
2232 ' ',
2233 'U',
2234 's',
2235 'i',
2236 'n',
2237 'g',
2238 ' ',
2239 'A',
2240 ' ',
2241 'L',
2242 'o',
2243 'n',
2244 'g',
2245 ' ',
2246 'A',
2247 't',
2248 't',
2249 'r',
2250 'i',
2251 'b',
2252 'u',
2253 't',
2254 'e');
2255 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue);
2256 auto* attr =
2257 grp->AddAttribute(kTestType16,
2258 att::AccessRequirements(),
2259 att::AccessRequirements(/*encryption=*/true,
2260 /*authentication=*/false,
2261 /*authorization=*/false));
2262 attr->set_read_handler(
2263 [&](PeerId peer_id, att::Handle handle, uint16_t, auto result_cb) {
2264 EXPECT_EQ(kTestPeerId, peer_id);
2265 EXPECT_EQ(attr->handle(), handle);
2266
2267 result_cb(fit::error(att::ErrorCode::kUnlikelyError), BufferView());
2268 });
2269 grp->set_active(true);
2270
2271 // clang-format off
2272 const StaticByteBuffer kRequest(
2273 0x0C, // opcode: read blob request
2274 0x02, 0x00, // handle: 0x0002
2275 0x16, 0x00 // offset: 0x0016
2276 );
2277 const StaticByteBuffer kExpected(
2278 0x01, // opcode: error response
2279 0x0C, // request: read by type
2280 0x02, 0x00, // handle: 0x0002 (the attribute causing the error)
2281 0x02 // error: Not Permitted
2282 );
2283 // clang-format on
2284
2285 EXPECT_PACKET_OUT(kExpected);
2286 fake_chan()->Receive(kRequest);
2287 }
2288
TEST_F(ServerTest,ReadBlobRequestInvalidOffsetError)2289 TEST_F(ServerTest, ReadBlobRequestInvalidOffsetError) {
2290 const StaticByteBuffer kTestValue('A',
2291 ' ',
2292 'V',
2293 'e',
2294 'r',
2295 'y',
2296 ' ',
2297 'L',
2298 'o',
2299 'n',
2300 'g',
2301 ' ',
2302 'D',
2303 'e',
2304 'v',
2305 'i',
2306 'c',
2307 'e',
2308 ' ',
2309 'N',
2310 'a',
2311 'm',
2312 'e',
2313 ' ',
2314 'U',
2315 's',
2316 'i',
2317 'n',
2318 'g',
2319 ' ',
2320 'A',
2321 ' ',
2322 'L',
2323 'o',
2324 'n',
2325 'g',
2326 ' ',
2327 'A',
2328 't',
2329 't',
2330 'r',
2331 'i',
2332 'b',
2333 'u',
2334 't',
2335 'e');
2336
2337 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue);
2338 auto* attr = grp->AddAttribute(
2339 kTestType16, AllowedNoSecurity(), att::AccessRequirements());
2340 attr->set_read_handler(
2341 [&](PeerId peer_id, att::Handle handle, uint16_t, auto result_cb) {
2342 EXPECT_EQ(kTestPeerId, peer_id);
2343 EXPECT_EQ(attr->handle(), handle);
2344
2345 result_cb(fit::error(att::ErrorCode::kInvalidOffset), BufferView());
2346 });
2347 grp->set_active(true);
2348
2349 // clang-format off
2350 const StaticByteBuffer kRequest(
2351 0x0C, // opcode: read blob request
2352 0x02, 0x00, // handle: 0x0002
2353 0x16, 0x40 // offset: 0x4016
2354 );
2355 const StaticByteBuffer kExpected(
2356 0x01, // opcode: error response
2357 0x0C, // request: read by type
2358 0x02, 0x00, // handle: 0x0002 (the attribute causing the error)
2359 0x07 // error: Invalid Offset Error
2360 );
2361 // clang-format on
2362
2363 EXPECT_PACKET_OUT(kExpected);
2364 fake_chan()->Receive(kRequest);
2365 }
2366
TEST_F(ServerTest,ReadRequestSuccess)2367 TEST_F(ServerTest, ReadRequestSuccess) {
2368 const StaticByteBuffer kDeclValue('d', 'e', 'c', 'l');
2369 const StaticByteBuffer kTestValue('f', 'o', 'o');
2370 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue);
2371 auto* attr = grp->AddAttribute(
2372 kTestType16, AllowedNoSecurity(), att::AccessRequirements());
2373 attr->set_read_handler(
2374 [&](PeerId peer_id, att::Handle handle, uint16_t offset, auto result_cb) {
2375 EXPECT_EQ(kTestPeerId, peer_id);
2376 EXPECT_EQ(attr->handle(), handle);
2377 EXPECT_EQ(0u, offset);
2378
2379 result_cb(fit::ok(), kTestValue);
2380 });
2381 grp->set_active(true);
2382
2383 // clang-format off
2384 const StaticByteBuffer kRequest(
2385 0x0A, // opcode: read request
2386 0x02, 0x00 // handle: 0x0002
2387 );
2388 const StaticByteBuffer kExpected(
2389 0x0B, // opcode: read response
2390 'f', 'o', 'o' // value: kTestValue
2391 );
2392 // clang-format on
2393
2394 EXPECT_PACKET_OUT(kExpected);
2395 fake_chan()->Receive(kRequest);
2396 }
2397
TEST_F(ServerTest,PrepareWriteRequestInvalidPDU)2398 TEST_F(ServerTest, PrepareWriteRequestInvalidPDU) {
2399 // Payload is one byte too short.
2400 // clang-format off
2401 const StaticByteBuffer kInvalidPDU(
2402 0x16, // opcode: prepare write request
2403 0x01, 0x00, // handle: 0x0001
2404 0x01 // offset (should be 2 bytes).
2405 );
2406 const StaticByteBuffer kExpected(
2407 0x01, // opcode: error response
2408 0x16, // request: prepare write request
2409 0x00, 0x00, // handle: 0
2410 0x04 // error: Invalid PDU
2411 );
2412 // clang-format on
2413
2414 EXPECT_PACKET_OUT(kExpected);
2415 fake_chan()->Receive(kInvalidPDU);
2416 }
2417
TEST_F(ServerTest,PrepareWriteRequestInvalidHandle)2418 TEST_F(ServerTest, PrepareWriteRequestInvalidHandle) {
2419 // clang-format off
2420 const StaticByteBuffer kRequest(
2421 0x16, // opcode: prepare write request
2422 0x01, 0x00, // handle: 0x0001
2423 0x00, 0x00, // offset: 0
2424 't', 'e', 's', 't' // value: "test"
2425 );
2426 const StaticByteBuffer kResponse(
2427 0x01, // opcode: error response
2428 0x16, // request: prepare write request
2429 0x01, 0x00, // handle: 0x0001
2430 0x01 // error: invalid handle
2431 );
2432 // clang-format on
2433
2434 EXPECT_PACKET_OUT(kResponse);
2435 fake_chan()->Receive(kRequest);
2436 }
2437
TEST_F(ServerTest,PrepareWriteRequestSucceeds)2438 TEST_F(ServerTest, PrepareWriteRequestSucceeds) {
2439 const StaticByteBuffer kTestValue('f', 'o', 'o');
2440 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue);
2441
2442 // No security requirement
2443 auto* attr =
2444 grp->AddAttribute(kTestType16,
2445 att::AccessRequirements(),
2446 att::AccessRequirements(/*encryption=*/false,
2447 /*authentication=*/false,
2448 /*authorization=*/false));
2449 grp->set_active(true);
2450
2451 int write_count = 0;
2452 attr->set_write_handler(
2453 [&](PeerId, att::Handle, uint16_t, const auto&, const auto&) {
2454 write_count++;
2455 });
2456
2457 ASSERT_EQ(0x0002, attr->handle());
2458
2459 // clang-format off
2460 const StaticByteBuffer kRequest(
2461 0x16, // opcode: prepare write request
2462 0x02, 0x00, // handle: 0x0002
2463 0x00, 0x00, // offset: 0
2464 't', 'e', 's', 't' // value: "test"
2465 );
2466 const StaticByteBuffer kResponse(
2467 0x17, // opcode: prepare write response
2468 0x02, 0x00, // handle: 0x0002
2469 0x00, 0x00, // offset: 0
2470 't', 'e', 's', 't' // value: "test"
2471 );
2472 // clang-format on
2473
2474 EXPECT_PACKET_OUT(kResponse);
2475 fake_chan()->Receive(kRequest);
2476 // The attribute should not have been written yet.
2477 EXPECT_EQ(0, write_count);
2478 }
2479
TEST_F(ServerTest,PrepareWriteRequestPrepareQueueFull)2480 TEST_F(ServerTest, PrepareWriteRequestPrepareQueueFull) {
2481 const StaticByteBuffer kTestValue('f', 'o', 'o');
2482 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue);
2483
2484 // No security requirement
2485 const auto* attr =
2486 grp->AddAttribute(kTestType16,
2487 att::AccessRequirements(),
2488 att::AccessRequirements(/*encryption=*/false,
2489 /*authentication=*/false,
2490 /*authorization=*/false));
2491 grp->set_active(true);
2492
2493 ASSERT_EQ(0x0002, attr->handle());
2494
2495 // clang-format off
2496 const StaticByteBuffer kRequest(
2497 0x16, // opcode: prepare write request
2498 0x02, 0x00, // handle: 0x0002
2499 0x00, 0x00, // offset: 0
2500 't', 'e', 's', 't' // value: "test"
2501 );
2502 const StaticByteBuffer kSuccessResponse(
2503 0x17, // opcode: prepare write response
2504 0x02, 0x00, // handle: 0x0002
2505 0x00, 0x00, // offset: 0
2506 't', 'e', 's', 't' // value: "test"
2507 );
2508 const StaticByteBuffer kErrorResponse(
2509 0x01, // opcode: error response
2510 0x16, // request: prepare write request
2511 0x02, 0x00, // handle: 0x0002
2512 0x09 // error: prepare queue full
2513 );
2514 // clang-format on
2515
2516 // Write requests should succeed until capacity is filled.
2517 for (unsigned i = 0; i < att::kPrepareQueueMaxCapacity; i++) {
2518 EXPECT_PACKET_OUT(kSuccessResponse);
2519 fake_chan()->Receive(kRequest);
2520 ASSERT_TRUE(AllExpectedPacketsSent())
2521 << "Unexpected failure at attempt: " << i;
2522 }
2523
2524 // The next request should fail with a capacity error.
2525 EXPECT_PACKET_OUT(kErrorResponse);
2526 fake_chan()->Receive(kRequest);
2527 }
2528
TEST_F(ServerTest,ExecuteWriteMalformedPayload)2529 TEST_F(ServerTest, ExecuteWriteMalformedPayload) {
2530 // Payload is one byte too short.
2531 // clang-format off
2532 const StaticByteBuffer kInvalidPDU(
2533 0x18 // opcode: execute write request
2534 );
2535 const StaticByteBuffer kExpected(
2536 0x01, // opcode: error response
2537 0x18, // request: execute write request
2538 0x00, 0x00, // handle: 0
2539 0x04 // error: Invalid PDU
2540 );
2541 // clang-format on
2542
2543 EXPECT_PACKET_OUT(kExpected);
2544 fake_chan()->Receive(kInvalidPDU);
2545 }
2546
TEST_F(ServerTest,ExecuteWriteInvalidFlag)2547 TEST_F(ServerTest, ExecuteWriteInvalidFlag) {
2548 // Payload is one byte too short.
2549 // clang-format off
2550 const StaticByteBuffer kInvalidPDU(
2551 0x18, // opcode: execute write request
2552 0xFF // flag: invalid
2553 );
2554 const StaticByteBuffer kExpected(
2555 0x01, // opcode: error response
2556 0x18, // request: execute write request
2557 0x00, 0x00, // handle: 0
2558 0x04 // error: Invalid PDU
2559 );
2560 // clang-format on
2561
2562 EXPECT_PACKET_OUT(kExpected);
2563 fake_chan()->Receive(kInvalidPDU);
2564 }
2565
2566 // Tests that an "execute write request" without any prepared writes returns
2567 // success without writing to any attributes.
TEST_F(ServerTest,ExecuteWriteQueueEmpty)2568 TEST_F(ServerTest, ExecuteWriteQueueEmpty) {
2569 // clang-format off
2570 const StaticByteBuffer kExecute(
2571 0x18, // opcode: execute write request
2572 0x01 // flag: "write pending"
2573 );
2574 const StaticByteBuffer kExecuteResponse(
2575 0x19 // opcode: execute write response
2576 );
2577 // clang-format on
2578
2579 // |buffer| should contain the partial writes.
2580 EXPECT_PACKET_OUT(kExecuteResponse);
2581 fake_chan()->Receive(kExecute);
2582 }
2583
TEST_F(ServerTest,ExecuteWriteSuccess)2584 TEST_F(ServerTest, ExecuteWriteSuccess) {
2585 StaticByteBuffer buffer('x', 'x', 'x', 'x', 'x', 'x');
2586
2587 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue1);
2588 auto* attr = grp->AddAttribute(
2589 kTestType16, att::AccessRequirements(), AllowedNoSecurity());
2590 attr->set_write_handler([&](const auto& peer_id,
2591 att::Handle handle,
2592 uint16_t offset,
2593 const auto& value,
2594 auto result_cb) {
2595 EXPECT_EQ(kTestPeerId, peer_id);
2596 EXPECT_EQ(attr->handle(), handle);
2597
2598 // Write the contents into |buffer|.
2599 buffer.Write(value, offset);
2600 result_cb(fit::ok());
2601 });
2602 grp->set_active(true);
2603
2604 // Prepare two partial writes of the string "hello!".
2605 // clang-format off
2606 const StaticByteBuffer kPrepare1(
2607 0x016, // opcode: prepare write request
2608 0x02, 0x00, // handle: 0x0002
2609 0x00, 0x00, // offset: 0
2610 'h', 'e', 'l', 'l' // value: "hell"
2611 );
2612 const StaticByteBuffer kPrepareResponse1(
2613 0x017, // opcode: prepare write response
2614 0x02, 0x00, // handle: 0x0002
2615 0x00, 0x00, // offset: 0
2616 'h', 'e', 'l', 'l' // value: "hell"
2617 );
2618 const StaticByteBuffer kPrepare2(
2619 0x016, // opcode: prepare write request
2620 0x02, 0x00, // handle: 0x0002
2621 0x04, 0x00, // offset: 4
2622 'o', '!' // value: "o!"
2623 );
2624 const StaticByteBuffer kPrepareResponse2(
2625 0x017, // opcode: prepare write response
2626 0x02, 0x00, // handle: 0x0002
2627 0x04, 0x00, // offset: 4
2628 'o', '!' // value: "o!"
2629 );
2630
2631 // Add an overlapping write that partial overwrites data from previous
2632 // payloads.
2633 const StaticByteBuffer kPrepare3(
2634 0x016, // opcode: prepare write request
2635 0x02, 0x00, // handle: 0x0002
2636 0x02, 0x00, // offset: 2
2637 'r', 'p', '?' // value: "rp?"
2638 );
2639 const StaticByteBuffer kPrepareResponse3(
2640 0x017, // opcode: prepare write response
2641 0x02, 0x00, // handle: 0x0002
2642 0x02, 0x00, // offset: 2
2643 'r', 'p', '?' // value: "rp?"
2644 );
2645
2646 // clang-format on
2647
2648 EXPECT_PACKET_OUT(kPrepareResponse1);
2649 fake_chan()->Receive(kPrepare1);
2650 EXPECT_PACKET_OUT(kPrepareResponse2);
2651 fake_chan()->Receive(kPrepare2);
2652 EXPECT_PACKET_OUT(kPrepareResponse3);
2653 fake_chan()->Receive(kPrepare3);
2654
2655 // The writes should not be committed yet.
2656 EXPECT_EQ("xxxxxx", buffer.AsString());
2657
2658 // clang-format off
2659 const StaticByteBuffer kExecute(
2660 0x18, // opcode: execute write request
2661 0x01 // flag: "write pending"
2662 );
2663 const StaticByteBuffer kExecuteResponse(
2664 0x19 // opcode: execute write response
2665 );
2666 // clang-format on
2667
2668 // |buffer| should contain the partial writes.
2669 EXPECT_PACKET_OUT(kExecuteResponse);
2670 fake_chan()->Receive(kExecute);
2671 EXPECT_EQ("herp?!", buffer.AsString());
2672 }
2673
2674 // Tests that the rest of the queue is dropped if a prepared write fails.
TEST_F(ServerTest,ExecuteWriteError)2675 TEST_F(ServerTest, ExecuteWriteError) {
2676 StaticByteBuffer buffer('x', 'x', 'x', 'x', 'x', 'x');
2677
2678 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue1);
2679 auto* attr = grp->AddAttribute(
2680 kTestType16, att::AccessRequirements(), AllowedNoSecurity());
2681 attr->set_write_handler([&](const auto& peer_id,
2682 att::Handle handle,
2683 uint16_t offset,
2684 const auto& value,
2685 auto result_cb) {
2686 EXPECT_EQ(kTestPeerId, peer_id);
2687 EXPECT_EQ(attr->handle(), handle);
2688
2689 // Make the write to non-zero offsets fail (this corresponds to the second
2690 // partial write we prepare below.
2691 if (offset) {
2692 result_cb(fit::error(att::ErrorCode::kUnlikelyError));
2693 } else {
2694 buffer.Write(value);
2695 result_cb(fit::ok());
2696 }
2697 });
2698 grp->set_active(true);
2699
2700 // Prepare two partial writes of the string "hello!".
2701 // clang-format off
2702 const StaticByteBuffer kPrepare1(
2703 0x016, // opcode: prepare write request
2704 0x02, 0x00, // handle: 0x0002
2705 0x00, 0x00, // offset: 0
2706 'h', 'e', 'l', 'l' // value: "hell"
2707 );
2708 const StaticByteBuffer kPrepareResponse1(
2709 0x017, // opcode: prepare write response
2710 0x02, 0x00, // handle: 0x0002
2711 0x00, 0x00, // offset: 0
2712 'h', 'e', 'l', 'l' // value: "hell"
2713 );
2714 const StaticByteBuffer kPrepare2(
2715 0x016, // opcode: prepare write request
2716 0x02, 0x00, // handle: 0x0002
2717 0x04, 0x00, // offset: 4
2718 'o', '!' // value: "o!"
2719 );
2720 const StaticByteBuffer kPrepareResponse2(
2721 0x017, // opcode: prepare write response
2722 0x02, 0x00, // handle: 0x0002
2723 0x04, 0x00, // offset: 4
2724 'o', '!' // value: "o!"
2725 );
2726 // clang-format on
2727
2728 EXPECT_PACKET_OUT(kPrepareResponse1);
2729 fake_chan()->Receive(kPrepare1);
2730 EXPECT_PACKET_OUT(kPrepareResponse2);
2731 fake_chan()->Receive(kPrepare2);
2732
2733 // The writes should not be committed yet.
2734 EXPECT_EQ("xxxxxx", buffer.AsString());
2735
2736 // clang-format off
2737 const StaticByteBuffer kExecute(
2738 0x18, // opcode: execute write request
2739 0x01 // flag: "write pending"
2740 );
2741 const StaticByteBuffer kExecuteResponse(
2742 0x01, // opcode: error response
2743 0x18, // request: execute write request
2744 0x02, 0x00, // handle: 2 (the attribute in error)
2745 0x0E // error: Unlikely Error (returned by callback above).
2746 );
2747 // clang-format on
2748
2749 // Only the first partial write should have gone through as the second one
2750 // is expected to fail.
2751 EXPECT_PACKET_OUT(kExecuteResponse);
2752 fake_chan()->Receive(kExecute);
2753 EXPECT_EQ("hellxx", buffer.AsString());
2754 }
2755
TEST_F(ServerTest,ExecuteWriteAbort)2756 TEST_F(ServerTest, ExecuteWriteAbort) {
2757 auto* grp = db()->NewGrouping(types::kPrimaryService, 1, kTestValue1);
2758 // |attr| has handle "2".
2759 auto* attr = grp->AddAttribute(
2760 kTestType16, att::AccessRequirements(), AllowedNoSecurity());
2761
2762 int write_count = 0;
2763 attr->set_write_handler([&](const auto& peer_id,
2764 att::Handle handle,
2765 uint16_t offset,
2766 const auto& value,
2767 auto result_cb) {
2768 write_count++;
2769
2770 EXPECT_EQ(kTestPeerId, peer_id);
2771 EXPECT_EQ(attr->handle(), handle);
2772 EXPECT_EQ(0u, offset);
2773 EXPECT_TRUE(ContainersEqual(StaticByteBuffer('l', 'o', 'l'), value));
2774 result_cb(fit::ok());
2775 });
2776 grp->set_active(true);
2777
2778 // clang-format off
2779 const StaticByteBuffer kPrepareToAbort(
2780 0x016, // opcode: prepare write request
2781 0x02, 0x00, // handle: 0x0002
2782 0x00, 0x00, // offset: 0
2783 't', 'e', 's', 't' // value: "test"
2784 );
2785 const StaticByteBuffer kPrepareToAbortResponse(
2786 0x017, // opcode: prepare write response
2787 0x02, 0x00, // handle: 0x0002
2788 0x00, 0x00, // offset: 0
2789 't', 'e', 's', 't' // value: "test"
2790 );
2791 // clang-format on
2792
2793 // Prepare writes. These should get committed right away.
2794 EXPECT_PACKET_OUT(kPrepareToAbortResponse);
2795 fake_chan()->Receive(kPrepareToAbort);
2796 EXPECT_PACKET_OUT(kPrepareToAbortResponse);
2797 fake_chan()->Receive(kPrepareToAbort);
2798 EXPECT_PACKET_OUT(kPrepareToAbortResponse);
2799 fake_chan()->Receive(kPrepareToAbort);
2800 EXPECT_PACKET_OUT(kPrepareToAbortResponse);
2801 fake_chan()->Receive(kPrepareToAbort);
2802 EXPECT_TRUE(AllExpectedPacketsSent());
2803 EXPECT_EQ(0, write_count);
2804
2805 // Abort the writes. They should get dropped.
2806 // clang-format off
2807 const StaticByteBuffer kAbort(
2808 0x18, // opcode: execute write request
2809 0x00 // flag: "cancel all"
2810 );
2811 const StaticByteBuffer kAbortResponse(
2812 0x19 // opcode: execute write response
2813 );
2814 // clang-format on
2815 EXPECT_PACKET_OUT(kAbortResponse);
2816 fake_chan()->Receive(kAbort);
2817 EXPECT_EQ(0, write_count);
2818
2819 // Prepare and commit a new write request. This one should take effect without
2820 // involving the previously aborted writes.
2821 // clang-format off
2822 const StaticByteBuffer kPrepareToCommit(
2823 0x016, // opcode: prepare write request
2824 0x02, 0x00, // handle: 0x0002
2825 0x00, 0x00, // offset: 0
2826 'l', 'o', 'l' // value: "lol"
2827 );
2828 const StaticByteBuffer kPrepareToCommitResponse(
2829 0x017, // opcode: prepare write response
2830 0x02, 0x00, // handle: 0x0002
2831 0x00, 0x00, // offset: 0
2832 'l', 'o', 'l' // value: "lol"
2833 );
2834 const StaticByteBuffer kCommit(
2835 0x18, // opcode: execute write request
2836 0x01 // flag: "write pending"
2837 );
2838 const StaticByteBuffer kCommitResponse(
2839 0x19 // opcode: execute write response
2840 );
2841 // clang-format on
2842
2843 EXPECT_PACKET_OUT(kPrepareToCommitResponse);
2844 fake_chan()->Receive(kPrepareToCommit);
2845 EXPECT_PACKET_OUT(kCommitResponse);
2846 fake_chan()->Receive(kCommit);
2847 EXPECT_EQ(1, write_count);
2848 }
2849
TEST_F(ServerTest,TrySendNotificationNoCccConfig)2850 TEST_F(ServerTest, TrySendNotificationNoCccConfig) {
2851 IdType svc_id =
2852 RegisterSvcWithSingleChrc(kTestSvcType, kTestChrcId, kTestChrcType);
2853 const BufferView kTestValue;
2854 server()->SendUpdate(
2855 svc_id, kTestChrcId, kTestValue, /*indicate_cb=*/nullptr);
2856 }
2857
TEST_F(ServerTest,TrySendNotificationConfiguredForIndicationsOnly)2858 TEST_F(ServerTest, TrySendNotificationConfiguredForIndicationsOnly) {
2859 SvcIdAndChrcHandle registered = RegisterSvcWithConfiguredChrc(
2860 kTestSvcType, kTestChrcId, kTestChrcType, kCCCIndicationBit);
2861 const BufferView kTestValue;
2862 server()->SendUpdate(
2863 registered.svc_id, kTestChrcId, kTestValue, /*indicate_cb=*/nullptr);
2864 }
2865
TEST_F(ServerTest,SendNotificationEmpty)2866 TEST_F(ServerTest, SendNotificationEmpty) {
2867 SvcIdAndChrcHandle registered =
2868 RegisterSvcWithConfiguredChrc(kTestSvcType, kTestChrcId, kTestChrcType);
2869 const BufferView kTestValue;
2870
2871 // clang-format off
2872 const StaticByteBuffer kExpected{
2873 att::kNotification, // Opcode
2874 // Handle of the characteristic value being notified
2875 LowerBits(registered.chrc_val_handle), UpperBits(registered.chrc_val_handle)
2876 };
2877 // clang-format on
2878
2879 EXPECT_PACKET_OUT(kExpected);
2880 server()->SendUpdate(
2881 registered.svc_id, kTestChrcId, kTestValue, /*indicate_cb=*/nullptr);
2882 }
2883
TEST_F(ServerTest,SendNotification)2884 TEST_F(ServerTest, SendNotification) {
2885 SvcIdAndChrcHandle registered =
2886 RegisterSvcWithConfiguredChrc(kTestSvcType, kTestChrcId, kTestChrcType);
2887 const StaticByteBuffer kTestValue('f', 'o', 'o');
2888
2889 // clang-format off
2890 const StaticByteBuffer kExpected{
2891 att::kNotification, // Opcode
2892 // Handle of the characteristic value being notified
2893 LowerBits(registered.chrc_val_handle), UpperBits(registered.chrc_val_handle),
2894 kTestValue[0], kTestValue[1], kTestValue[2]
2895 };
2896 // clang-format on
2897
2898 EXPECT_PACKET_OUT(kExpected);
2899 server()->SendUpdate(registered.svc_id,
2900 kTestChrcId,
2901 kTestValue.view(),
2902 /*indicate_cb=*/nullptr);
2903 }
2904
TEST_F(ServerTest,TrySendIndicationNoCccConfig)2905 TEST_F(ServerTest, TrySendIndicationNoCccConfig) {
2906 IdType svc_id =
2907 RegisterSvcWithSingleChrc(kTestSvcType, kTestChrcId, kTestChrcType);
2908 const BufferView kTestValue;
2909
2910 att::Result<> indicate_res = fit::ok();
2911 auto indicate_cb = [&](att::Result<> res) { indicate_res = res; };
2912
2913 server()->SendUpdate(svc_id, kTestChrcId, kTestValue, std::move(indicate_cb));
2914 EXPECT_EQ(fit::failed(), indicate_res);
2915 }
2916
TEST_F(ServerTest,TrySendIndicationConfiguredForNotificationsOnly)2917 TEST_F(ServerTest, TrySendIndicationConfiguredForNotificationsOnly) {
2918 SvcIdAndChrcHandle registered = RegisterSvcWithConfiguredChrc(
2919 kTestSvcType, kTestChrcId, kTestChrcType, kCCCNotificationBit);
2920 const BufferView kTestValue;
2921
2922 att::Result<> indicate_res = fit::ok();
2923 auto indicate_cb = [&](att::Result<> res) { indicate_res = res; };
2924
2925 server()->SendUpdate(
2926 registered.svc_id, kTestChrcId, kTestValue, std::move(indicate_cb));
2927 EXPECT_EQ(fit::failed(), indicate_res);
2928 }
2929
TEST_F(ServerTest,SendIndicationEmpty)2930 TEST_F(ServerTest, SendIndicationEmpty) {
2931 SvcIdAndChrcHandle registered =
2932 RegisterSvcWithConfiguredChrc(kTestSvcType, kTestChrcId, kTestChrcType);
2933 const BufferView kTestValue;
2934
2935 att::Result<> indicate_res = ToResult(HostError::kFailed);
2936 auto indicate_cb = [&](att::Result<> res) { indicate_res = res; };
2937
2938 // clang-format off
2939 const StaticByteBuffer kExpected{
2940 att::kIndication, // Opcode
2941 // Handle of the characteristic value being notified
2942 LowerBits(registered.chrc_val_handle), UpperBits(registered.chrc_val_handle)
2943 };
2944 // clang-format on
2945
2946 EXPECT_PACKET_OUT(kExpected);
2947 server()->SendUpdate(
2948 registered.svc_id, kTestChrcId, kTestValue, std::move(indicate_cb));
2949 EXPECT_TRUE(AllExpectedPacketsSent());
2950
2951 const StaticByteBuffer kIndicationConfirmation{att::kConfirmation};
2952 fake_chan()->Receive(kIndicationConfirmation);
2953 EXPECT_EQ(fit::ok(), indicate_res);
2954 }
2955
TEST_F(ServerTest,SendIndication)2956 TEST_F(ServerTest, SendIndication) {
2957 SvcIdAndChrcHandle registered =
2958 RegisterSvcWithConfiguredChrc(kTestSvcType, kTestChrcId, kTestChrcType);
2959 const StaticByteBuffer kTestValue('f', 'o', 'o');
2960
2961 att::Result<> indicate_res = ToResult(HostError::kFailed);
2962 auto indicate_cb = [&](att::Result<> res) { indicate_res = res; };
2963
2964 // clang-format off
2965 const StaticByteBuffer kExpected{
2966 att::kIndication, // Opcode
2967 // Handle of the characteristic value being notified
2968 LowerBits(registered.chrc_val_handle), UpperBits(registered.chrc_val_handle),
2969 kTestValue[0], kTestValue[1], kTestValue[2]
2970 };
2971 // clang-format on
2972
2973 EXPECT_PACKET_OUT(kExpected);
2974 server()->SendUpdate(registered.svc_id,
2975 kTestChrcId,
2976 kTestValue.view(),
2977 std::move(indicate_cb));
2978 EXPECT_TRUE(AllExpectedPacketsSent());
2979
2980 const StaticByteBuffer kIndicationConfirmation{att::kConfirmation};
2981 fake_chan()->Receive(kIndicationConfirmation);
2982 EXPECT_EQ(fit::ok(), indicate_res);
2983 }
2984
2985 class ServerTestSecurity : public ServerTest {
2986 protected:
InitializeAttributesForReading()2987 void InitializeAttributesForReading() {
2988 auto* grp = db()->NewGrouping(types::kPrimaryService, 4, kTestValue1);
2989
2990 const att::AccessRequirements encryption(/*encryption=*/true,
2991 /*authentication=*/false,
2992 /*authorization=*/false);
2993 const att::AccessRequirements authentication(/*encryption=*/false,
2994 /*authentication=*/true,
2995 /*authorization=*/false);
2996 const att::AccessRequirements authorization(/*encryption=*/false,
2997 /*authentication=*/false,
2998 /*authorization=*/true);
2999
3000 not_permitted_attr_ = grp->AddAttribute(kTestType16);
3001 encryption_required_attr_ = grp->AddAttribute(kTestType16, encryption);
3002 authentication_required_attr_ =
3003 grp->AddAttribute(kTestType16, authentication);
3004 authorization_required_attr_ =
3005 grp->AddAttribute(kTestType16, authorization);
3006
3007 // Assigns all tests attributes a static value. Intended to be used by read
3008 // requests. (Note: assigning a static value makes an attribute
3009 // non-writable). All attributes are assigned kTestValue1 as their static
3010 // value.
3011 not_permitted_attr_->SetValue(kTestValue1);
3012 encryption_required_attr_->SetValue(kTestValue1);
3013 authentication_required_attr_->SetValue(kTestValue1);
3014 authorization_required_attr_->SetValue(kTestValue1);
3015
3016 grp->set_active(true);
3017 }
3018
InitializeAttributesForWriting()3019 void InitializeAttributesForWriting() {
3020 auto* grp = db()->NewGrouping(types::kPrimaryService, 4, kTestValue1);
3021
3022 const att::AccessRequirements encryption(/*encryption=*/true,
3023 /*authentication=*/false,
3024 /*authorization=*/false);
3025 const att::AccessRequirements authentication(/*encryption=*/false,
3026 /*authentication=*/true,
3027 /*authorization=*/false);
3028 const att::AccessRequirements authorization(/*encryption=*/false,
3029 /*authentication=*/false,
3030 /*authorization=*/true);
3031
3032 auto write_handler =
3033 [this](
3034 const auto&, att::Handle, uint16_t, const auto&, auto responder) {
3035 write_count_++;
3036 if (responder) {
3037 responder(fit::ok());
3038 }
3039 };
3040
3041 not_permitted_attr_ = grp->AddAttribute(kTestType16);
3042 not_permitted_attr_->set_write_handler(write_handler);
3043
3044 encryption_required_attr_ =
3045 grp->AddAttribute(kTestType16, att::AccessRequirements(), encryption);
3046 encryption_required_attr_->set_write_handler(write_handler);
3047
3048 authentication_required_attr_ = grp->AddAttribute(
3049 kTestType16, att::AccessRequirements(), authentication);
3050 authentication_required_attr_->set_write_handler(write_handler);
3051
3052 authorization_required_attr_ = grp->AddAttribute(
3053 kTestType16, att::AccessRequirements(), authorization);
3054 authorization_required_attr_->set_write_handler(write_handler);
3055
3056 grp->set_active(true);
3057 }
3058
MakeAttError(att::OpCode request,att::Handle handle,att::ErrorCode ecode)3059 auto MakeAttError(att::OpCode request,
3060 att::Handle handle,
3061 att::ErrorCode ecode) {
3062 return StaticByteBuffer(0x01, // opcode: error response
3063 request, // request opcode
3064 LowerBits(handle),
3065 UpperBits(handle), // handle
3066 ecode // error code
3067 );
3068 }
3069
3070 // Helpers for emulating the receipt of an ATT read/write request PDU and
3071 // expecting back a security error. Expects a successful response if
3072 // |expected_status| is fit::ok().
EmulateReadByTypeRequest(att::Handle handle,fit::result<att::ErrorCode> expected_status)3073 bool EmulateReadByTypeRequest(att::Handle handle,
3074 fit::result<att::ErrorCode> expected_status) {
3075 const StaticByteBuffer kReadByTypeRequestPdu(
3076 0x08, // opcode: read by type
3077 LowerBits(handle),
3078 UpperBits(handle), // start handle
3079 LowerBits(handle),
3080 UpperBits(handle), // end handle
3081 0xEF,
3082 0xBE); // type: 0xBEEF, i.e. kTestType16
3083 if (expected_status.is_ok()) {
3084 EXPECT_PACKET_OUT(StaticByteBuffer(0x09, // opcode: read by type response
3085 0x05, // length: 5 (strlen("foo") + 2)
3086 LowerBits(handle),
3087 UpperBits(handle), // handle
3088 'f',
3089 'o',
3090 'o' // value: "foo", i.e. kTestValue1
3091 ));
3092 } else {
3093 EXPECT_PACKET_OUT(
3094 MakeAttError(0x08, handle, expected_status.error_value()));
3095 }
3096 fake_chan()->Receive(kReadByTypeRequestPdu);
3097 return AllExpectedPacketsSent();
3098 }
3099
EmulateReadBlobRequest(att::Handle handle,fit::result<att::ErrorCode> expected_status)3100 bool EmulateReadBlobRequest(att::Handle handle,
3101 fit::result<att::ErrorCode> expected_status) {
3102 const StaticByteBuffer kReadBlobRequestPdu(0x0C, // opcode: read blob
3103 LowerBits(handle),
3104 UpperBits(handle), // handle
3105 0x00,
3106 0x00); // offset: 0
3107 if (expected_status.is_ok()) {
3108 EXPECT_PACKET_OUT(StaticByteBuffer(0x0D, // opcode: read blob response
3109 'f',
3110 'o',
3111 'o' // value: "foo", i.e. kTestValue1
3112 ));
3113 } else {
3114 EXPECT_PACKET_OUT(
3115 MakeAttError(0x0C, handle, expected_status.error_value()));
3116 }
3117 fake_chan()->Receive(kReadBlobRequestPdu);
3118 return AllExpectedPacketsSent();
3119 }
3120
EmulateReadRequest(att::Handle handle,fit::result<att::ErrorCode> expected_status)3121 bool EmulateReadRequest(att::Handle handle,
3122 fit::result<att::ErrorCode> expected_status) {
3123 const StaticByteBuffer kReadRequestPdu(0x0A, // opcode: read request
3124 LowerBits(handle),
3125 UpperBits(handle)); // handle
3126 if (expected_status.is_ok()) {
3127 EXPECT_PACKET_OUT(StaticByteBuffer(0x0B, // opcode: read response
3128 'f',
3129 'o',
3130 'o' // value: "foo", i.e. kTestValue1
3131 ));
3132 } else {
3133 EXPECT_PACKET_OUT(
3134 MakeAttError(0x0A, handle, expected_status.error_value()));
3135 }
3136 fake_chan()->Receive(kReadRequestPdu);
3137 return AllExpectedPacketsSent();
3138 }
3139
EmulateWriteRequest(att::Handle handle,fit::result<att::ErrorCode> expected_status)3140 bool EmulateWriteRequest(att::Handle handle,
3141 fit::result<att::ErrorCode> expected_status) {
3142 const StaticByteBuffer kWriteRequestPdu(0x12, // opcode: write request
3143 LowerBits(handle),
3144 UpperBits(handle), // handle
3145 't',
3146 'e',
3147 's',
3148 't'); // value: "test"
3149 if (expected_status.is_ok()) {
3150 EXPECT_PACKET_OUT(StaticByteBuffer(0x13));
3151 } else {
3152 EXPECT_PACKET_OUT(
3153 MakeAttError(0x12, handle, expected_status.error_value()));
3154 }
3155 fake_chan()->Receive(kWriteRequestPdu);
3156 return AllExpectedPacketsSent();
3157 }
3158
EmulatePrepareWriteRequest(att::Handle handle,fit::result<att::ErrorCode> expected_status)3159 bool EmulatePrepareWriteRequest(att::Handle handle,
3160 fit::result<att::ErrorCode> expected_status) {
3161 const auto kPrepareWriteRequestPdu =
3162 StaticByteBuffer(0x16, // opcode: prepare write request
3163 LowerBits(handle),
3164 UpperBits(handle), // handle
3165 0x00,
3166 0x00, // offset: 0
3167 't',
3168 'e',
3169 's',
3170 't' // value: "test"
3171 );
3172 if (expected_status.is_ok()) {
3173 EXPECT_PACKET_OUT(StaticByteBuffer(0x17, // prepare write response
3174 LowerBits(handle),
3175 UpperBits(handle), // handle
3176 0x00,
3177 0x00, // offset: 0
3178 't',
3179 'e',
3180 's',
3181 't' // value: "test"
3182 ));
3183 } else {
3184 EXPECT_PACKET_OUT(
3185 MakeAttError(0x16, handle, expected_status.error_value()));
3186 }
3187 fake_chan()->Receive(kPrepareWriteRequestPdu);
3188 return AllExpectedPacketsSent();
3189 }
3190
3191 // Emulates the receipt of a Write Command. The expected error code parameter
3192 // is unused since ATT commands do not have a response.
EmulateWriteCommand(att::Handle handle,fit::result<att::ErrorCode>)3193 bool EmulateWriteCommand(att::Handle handle, fit::result<att::ErrorCode>) {
3194 fake_chan()->Receive(StaticByteBuffer(0x52, // opcode: write command
3195 LowerBits(handle),
3196 UpperBits(handle), // handle
3197 't',
3198 'e',
3199 's',
3200 't' // value: "test"
3201 ));
3202 RunUntilIdle();
3203 return true;
3204 }
3205
3206 template <bool (ServerTestSecurity::*EmulateMethod)(
3207 att::Handle, fit::result<att::ErrorCode>),
3208 bool IsWrite>
RunTest()3209 void RunTest() {
3210 const fit::error<att::ErrorCode> kNotPermittedError =
3211 fit::error(IsWrite ? att::ErrorCode::kWriteNotPermitted
3212 : att::ErrorCode::kReadNotPermitted);
3213
3214 // No security.
3215 EXPECT_TRUE((this->*EmulateMethod)(not_permitted_attr()->handle(),
3216 fit::error(kNotPermittedError)));
3217 EXPECT_TRUE((this->*EmulateMethod)(
3218 encryption_required_attr()->handle(),
3219 fit::error(att::ErrorCode::kInsufficientAuthentication)));
3220 EXPECT_TRUE((this->*EmulateMethod)(
3221 authentication_required_attr()->handle(),
3222 fit::error(att::ErrorCode::kInsufficientAuthentication)));
3223 EXPECT_TRUE((this->*EmulateMethod)(
3224 authorization_required_attr()->handle(),
3225 fit::error(att::ErrorCode::kInsufficientAuthentication)));
3226
3227 // Link encrypted.
3228 fake_chan()->set_security(sm::SecurityProperties(
3229 sm::SecurityLevel::kEncrypted, 16, /*secure_connections=*/false));
3230 EXPECT_TRUE((this->*EmulateMethod)(not_permitted_attr()->handle(),
3231 kNotPermittedError));
3232 EXPECT_TRUE((this->*EmulateMethod)(encryption_required_attr()->handle(),
3233 fit::ok()));
3234 EXPECT_TRUE((this->*EmulateMethod)(
3235 authentication_required_attr()->handle(),
3236 fit::error(att::ErrorCode::kInsufficientAuthentication)));
3237 EXPECT_TRUE((this->*EmulateMethod)(
3238 authorization_required_attr()->handle(),
3239 fit::error(att::ErrorCode::kInsufficientAuthentication)));
3240
3241 // inclusive-language: ignore
3242 // Link encrypted w/ MITM.
3243 fake_chan()->set_security(
3244 sm::SecurityProperties(sm::SecurityLevel::kAuthenticated,
3245 16,
3246 /*secure_connections=*/false));
3247 EXPECT_TRUE((this->*EmulateMethod)(not_permitted_attr()->handle(),
3248 kNotPermittedError));
3249 EXPECT_TRUE((this->*EmulateMethod)(encryption_required_attr()->handle(),
3250 fit::ok()));
3251 EXPECT_TRUE((this->*EmulateMethod)(authentication_required_attr()->handle(),
3252 fit::ok()));
3253 EXPECT_TRUE((this->*EmulateMethod)(authorization_required_attr()->handle(),
3254 fit::ok()));
3255 }
3256
RunReadByTypeTest()3257 void RunReadByTypeTest() {
3258 RunTest<&ServerTestSecurity::EmulateReadByTypeRequest, false>();
3259 }
RunReadBlobTest()3260 void RunReadBlobTest() {
3261 RunTest<&ServerTestSecurity::EmulateReadBlobRequest, false>();
3262 }
RunReadRequestTest()3263 void RunReadRequestTest() {
3264 RunTest<&ServerTestSecurity::EmulateReadRequest, false>();
3265 }
RunWriteRequestTest()3266 void RunWriteRequestTest() {
3267 RunTest<&ServerTestSecurity::EmulateWriteRequest, true>();
3268 }
RunPrepareWriteRequestTest()3269 void RunPrepareWriteRequestTest() {
3270 RunTest<&ServerTestSecurity::EmulatePrepareWriteRequest, true>();
3271 }
RunWriteCommandTest()3272 void RunWriteCommandTest() {
3273 RunTest<&ServerTestSecurity::EmulateWriteCommand, true>();
3274 }
3275
not_permitted_attr() const3276 const att::Attribute* not_permitted_attr() const {
3277 return not_permitted_attr_;
3278 }
encryption_required_attr() const3279 const att::Attribute* encryption_required_attr() const {
3280 return encryption_required_attr_;
3281 }
authentication_required_attr() const3282 const att::Attribute* authentication_required_attr() const {
3283 return authentication_required_attr_;
3284 }
authorization_required_attr() const3285 const att::Attribute* authorization_required_attr() const {
3286 return authorization_required_attr_;
3287 }
3288
write_count() const3289 size_t write_count() const { return write_count_; }
3290
3291 private:
3292 att::Attribute* not_permitted_attr_ = nullptr;
3293 att::Attribute* encryption_required_attr_ = nullptr;
3294 att::Attribute* authentication_required_attr_ = nullptr;
3295 att::Attribute* authorization_required_attr_ = nullptr;
3296
3297 size_t write_count_ = 0u;
3298 };
3299
3300 // Tests receiving a Read By Type error under 3 possible link security levels.
TEST_F(ServerTestSecurity,ReadByTypeErrorSecurity)3301 TEST_F(ServerTestSecurity, ReadByTypeErrorSecurity) {
3302 InitializeAttributesForReading();
3303 RunReadByTypeTest();
3304 }
3305
TEST_F(ServerTestSecurity,ReadBlobErrorSecurity)3306 TEST_F(ServerTestSecurity, ReadBlobErrorSecurity) {
3307 InitializeAttributesForReading();
3308 RunReadBlobTest();
3309 }
3310
TEST_F(ServerTestSecurity,ReadErrorSecurity)3311 TEST_F(ServerTestSecurity, ReadErrorSecurity) {
3312 InitializeAttributesForReading();
3313 RunReadRequestTest();
3314 }
3315
TEST_F(ServerTestSecurity,WriteErrorSecurity)3316 TEST_F(ServerTestSecurity, WriteErrorSecurity) {
3317 InitializeAttributesForWriting();
3318 RunWriteRequestTest();
3319
3320 // Only 4 writes should have gone through.
3321 EXPECT_EQ(4u, write_count());
3322 }
3323
TEST_F(ServerTestSecurity,WriteCommandErrorSecurity)3324 TEST_F(ServerTestSecurity, WriteCommandErrorSecurity) {
3325 InitializeAttributesForWriting();
3326 RunWriteCommandTest();
3327
3328 // Only 4 writes should have gone through.
3329 EXPECT_EQ(4u, write_count());
3330 }
3331
TEST_F(ServerTestSecurity,PrepareWriteRequestSecurity)3332 TEST_F(ServerTestSecurity, PrepareWriteRequestSecurity) {
3333 InitializeAttributesForWriting();
3334 RunPrepareWriteRequestTest();
3335
3336 // None of the write handlers should have been called since no execute write
3337 // request has been sent.
3338 EXPECT_EQ(0u, write_count());
3339 }
3340
3341 } // namespace
3342 } // namespace bt::gatt
3343