1 /*
2 * Copyright 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "model/hci/h4_parser.h"
18
19 #include <gtest/gtest.h>
20
21 #include <array>
22
23 namespace rootcanal {
24 using PacketData = std::vector<uint8_t>;
25
26 class H4ParserTest : public ::testing::Test {
27 public:
28 protected:
SetUp()29 void SetUp() override {
30 packet_.clear();
31 parser_.Reset();
32 }
33
TearDown()34 void TearDown() override { parser_.Reset(); }
35
PacketReadCallback(const std::vector<uint8_t> & packet)36 void PacketReadCallback(const std::vector<uint8_t>& packet) { packet_ = std::move(packet); }
37
38 protected:
39 H4Parser parser_{
__anonaf6867ac0102() 40 [&](auto p) {
41 type_ = PacketType::COMMAND;
42 PacketReadCallback(p);
43 },
__anonaf6867ac0202() 44 [&](auto p) {
45 type_ = PacketType::EVENT;
46 PacketReadCallback(p);
47 },
__anonaf6867ac0302() 48 [&](auto p) {
49 type_ = PacketType::ACL;
50 PacketReadCallback(p);
51 },
__anonaf6867ac0402() 52 [&](auto p) {
53 type_ = PacketType::SCO;
54 PacketReadCallback(p);
55 },
__anonaf6867ac0502() 56 [&](auto p) {
57 type_ = PacketType::ISO;
58 PacketReadCallback(p);
59 },
60 true,
61 };
62 PacketData packet_;
63 PacketType type_;
64 };
65
TEST_F(H4ParserTest,InitiallyExpectOneByte)66 TEST_F(H4ParserTest, InitiallyExpectOneByte) { ASSERT_EQ(1, (int)parser_.BytesRequested()); }
67
TEST_F(H4ParserTest,SwitchStateAfterType)68 TEST_F(H4ParserTest, SwitchStateAfterType) {
69 uint8_t typ = (uint8_t)PacketType::ACL;
70 ASSERT_TRUE(parser_.Consume(&typ, 1));
71 ASSERT_EQ(parser_.CurrentState(), H4Parser::State::HCI_PREAMBLE);
72 }
73
TEST_F(H4ParserTest,RequestedBytesDecreases)74 TEST_F(H4ParserTest, RequestedBytesDecreases) {
75 // Make sure that the requested bytes is monotonically decreasing
76 // for the requested types.
77 uint8_t typ = (uint8_t)PacketType::ACL;
78 ASSERT_TRUE(parser_.Consume(&typ, 1));
79 auto wanted = parser_.BytesRequested();
80 while (wanted > 0) {
81 ASSERT_EQ(wanted, parser_.BytesRequested());
82 ASSERT_TRUE(parser_.Consume(&typ, 1));
83 wanted--;
84 }
85
86 ASSERT_EQ(parser_.CurrentState(), H4Parser::State::HCI_PAYLOAD);
87 wanted = parser_.BytesRequested();
88 while (wanted > 0) {
89 ASSERT_EQ(wanted, parser_.BytesRequested());
90 ASSERT_TRUE(parser_.Consume(&typ, 1));
91 wanted--;
92 }
93
94 // A callback should have been invoked.
95 ASSERT_LT(0, (int)packet_.size());
96 }
97
TEST_F(H4ParserTest,RejectNoData)98 TEST_F(H4ParserTest, RejectNoData) {
99 // You need to give us something!
100 PacketData bad_bit;
101 ASSERT_FALSE(parser_.Consume(bad_bit.data(), bad_bit.size()));
102 }
103
TEST_F(H4ParserTest,TooMuchIsDeath)104 TEST_F(H4ParserTest, TooMuchIsDeath) {
105 PacketData bad_bit({0xfd});
106 ASSERT_DEATH(parser_.Consume(bad_bit.data(), parser_.BytesRequested() + 1),
107 "More bytes read .* than expected .*!");
108 }
109
TEST_F(H4ParserTest,WrongTypeIsDeath)110 TEST_F(H4ParserTest, WrongTypeIsDeath) {
111 parser_.DisableRecovery();
112 PacketData bad_bit({0xfd});
113 ASSERT_DEATH(parser_.Consume(bad_bit.data(), bad_bit.size()), "Received invalid packet type.*");
114 }
115
TEST_F(H4ParserTest,CallsTheRightCallbacks)116 TEST_F(H4ParserTest, CallsTheRightCallbacks) {
117 // Make sure that the proper type of callback is invoked.
118 std::vector<PacketType> types({PacketType::ACL, PacketType::SCO, PacketType::COMMAND,
119 PacketType::EVENT, PacketType::ISO});
120 for (auto packetType : types) {
121 // Configure the incoming packet.
122 uint8_t typ = (uint8_t)packetType;
123 ASSERT_TRUE(parser_.Consume(&typ, 1));
124
125 // Feed data as long as this packet is not complete.
126 while (parser_.CurrentState() != H4Parser::State::HCI_TYPE) {
127 PacketData data;
128 for (uint32_t i = 0; i < parser_.BytesRequested(); i++) {
129 data.push_back((uint8_t)i);
130 }
131 ASSERT_TRUE(parser_.Consume(data.data(), data.size()));
132 }
133
134 // The proper callbacks should have been invoked.
135 ASSERT_LT(0, (int)packet_.size());
136 ASSERT_EQ(packetType, type_);
137 }
138 }
139
TEST_F(H4ParserTest,Recovery)140 TEST_F(H4ParserTest, Recovery) {
141 // Validate that the recovery state is exited only after receiving the
142 // HCI Reset command.
143 parser_.EnableRecovery();
144
145 // Enter recovery state after receiving an invalid packet type.
146 uint8_t invalid_packet_type = 0xfd;
147 ASSERT_TRUE(parser_.Consume(&invalid_packet_type, 1));
148 ASSERT_EQ(parser_.CurrentState(), H4Parser::State::HCI_RECOVERY);
149
150 const std::array<uint8_t, 4> reset_command{0x01, 0x03, 0x0c, 0x00};
151
152 // Send prefixes of the HCI Reset command, restarting over from the start.
153 for (size_t n = 1; n < 4; n++) {
154 for (size_t i = 0; i < n; i++) {
155 ASSERT_TRUE(parser_.Consume(&reset_command[i], 1));
156 ASSERT_EQ(parser_.CurrentState(), H4Parser::State::HCI_RECOVERY);
157 }
158 }
159
160 // Finally send the full HCI Reset command.
161 for (size_t i = 0; i < 4; i++) {
162 ASSERT_EQ(parser_.CurrentState(), H4Parser::State::HCI_RECOVERY);
163 ASSERT_TRUE(parser_.Consume(&reset_command[i], 1));
164 }
165
166 // Validate that the HCI recovery state is exited,
167 // and the HCI Reset command correctly received on the command callback.
168 ASSERT_EQ(parser_.CurrentState(), H4Parser::State::HCI_TYPE);
169 ASSERT_LT(0, (int)packet_.size());
170
171 // Validate that the HCI Reset command was correctly received.
172 ASSERT_EQ(type_, PacketType::COMMAND);
173 ASSERT_EQ(packet_.size(), reset_command.size() - 1);
174 for (size_t i = 1; i < packet_.size(); i++) {
175 ASSERT_EQ(packet_[i - 1], reset_command[i]);
176 }
177 }
178
179 } // namespace rootcanal
180