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