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