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