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) {
37     packet_ = std::move(packet);
38   }
39 
40  protected:
41   H4Parser parser_{
__anon362f6ab60102() 42       [&](auto p) {
43         type_ = PacketType::COMMAND;
44         PacketReadCallback(p);
45       },
__anon362f6ab60202() 46       [&](auto p) {
47         type_ = PacketType::EVENT;
48         PacketReadCallback(p);
49       },
__anon362f6ab60302() 50       [&](auto p) {
51         type_ = PacketType::ACL;
52         PacketReadCallback(p);
53       },
__anon362f6ab60402() 54       [&](auto p) {
55         type_ = PacketType::SCO;
56         PacketReadCallback(p);
57       },
__anon362f6ab60502() 58       [&](auto p) {
59         type_ = PacketType::ISO;
60         PacketReadCallback(p);
61       },
62       true,
63   };
64   PacketData packet_;
65   PacketType type_;
66 };
67 
TEST_F(H4ParserTest,InitiallyExpectOneByte)68 TEST_F(H4ParserTest, InitiallyExpectOneByte) {
69   ASSERT_EQ(1, (int)parser_.BytesRequested());
70 }
71 
TEST_F(H4ParserTest,SwitchStateAfterType)72 TEST_F(H4ParserTest, SwitchStateAfterType) {
73   uint8_t typ = (uint8_t)PacketType::ACL;
74   ASSERT_TRUE(parser_.Consume(&typ, 1));
75   ASSERT_EQ(parser_.CurrentState(), H4Parser::State::HCI_PREAMBLE);
76 }
77 
TEST_F(H4ParserTest,RequestedBytesDecreases)78 TEST_F(H4ParserTest, RequestedBytesDecreases) {
79   // Make sure that the requested bytes is monotonically decreasing
80   // for the requested types.
81   uint8_t typ = (uint8_t)PacketType::ACL;
82   ASSERT_TRUE(parser_.Consume(&typ, 1));
83   auto wanted = parser_.BytesRequested();
84   while (wanted > 0) {
85     ASSERT_EQ(wanted, parser_.BytesRequested());
86     ASSERT_TRUE(parser_.Consume(&typ, 1));
87     wanted--;
88   }
89 
90   ASSERT_EQ(parser_.CurrentState(), H4Parser::State::HCI_PAYLOAD);
91   wanted = parser_.BytesRequested();
92   while (wanted > 0) {
93     ASSERT_EQ(wanted, parser_.BytesRequested());
94     ASSERT_TRUE(parser_.Consume(&typ, 1));
95     wanted--;
96   }
97 
98   // A callback should have been invoked.
99   ASSERT_LT(0, (int)packet_.size());
100 }
101 
TEST_F(H4ParserTest,RejectNoData)102 TEST_F(H4ParserTest, RejectNoData) {
103   // You need to give us something!
104   PacketData bad_bit;
105   ASSERT_FALSE(parser_.Consume(bad_bit.data(), bad_bit.size()));
106 }
107 
TEST_F(H4ParserTest,TooMuchIsDeath)108 TEST_F(H4ParserTest, TooMuchIsDeath) {
109   PacketData bad_bit({0xfd});
110   ASSERT_DEATH(parser_.Consume(bad_bit.data(), parser_.BytesRequested() + 1),
111                "More bytes read .* than expected .*!");
112 }
113 
TEST_F(H4ParserTest,WrongTypeIsDeath)114 TEST_F(H4ParserTest, WrongTypeIsDeath) {
115   parser_.DisableRecovery();
116   PacketData bad_bit({0xfd});
117   ASSERT_DEATH(parser_.Consume(bad_bit.data(), bad_bit.size()),
118                "Received invalid packet type.*");
119 }
120 
TEST_F(H4ParserTest,CallsTheRightCallbacks)121 TEST_F(H4ParserTest, CallsTheRightCallbacks) {
122   // Make sure that the proper type of callback is invoked.
123   std::vector<PacketType> types({PacketType::ACL, PacketType::SCO,
124                                  PacketType::COMMAND, PacketType::EVENT,
125                                  PacketType::ISO});
126   for (auto packetType : types) {
127     // Configure the incoming packet.
128     uint8_t typ = (uint8_t)packetType;
129     ASSERT_TRUE(parser_.Consume(&typ, 1));
130 
131     // Feed data as long as this packet is not complete.
132     while (parser_.CurrentState() != H4Parser::State::HCI_TYPE) {
133       PacketData data;
134       for (uint32_t i = 0; i < parser_.BytesRequested(); i++) {
135         data.push_back((uint8_t)i);
136       }
137       ASSERT_TRUE(parser_.Consume(data.data(), data.size()));
138     }
139 
140     // The proper callbacks should have been invoked.
141     ASSERT_LT(0, (int)packet_.size());
142     ASSERT_EQ(packetType, type_);
143   }
144 }
145 
TEST_F(H4ParserTest,Recovery)146 TEST_F(H4ParserTest, Recovery) {
147   // Validate that the recovery state is exited only after receiving the
148   // HCI Reset command.
149   parser_.EnableRecovery();
150 
151   // Enter recovery state after receiving an invalid packet type.
152   uint8_t invalid_packet_type = 0xfd;
153   ASSERT_TRUE(parser_.Consume(&invalid_packet_type, 1));
154   ASSERT_EQ(parser_.CurrentState(), H4Parser::State::HCI_RECOVERY);
155 
156   const std::array<uint8_t, 4> reset_command{0x01, 0x03, 0x0c, 0x00};
157 
158   // Send prefixes of the HCI Reset command, restarting over from the start.
159   for (size_t n = 1; n < 4; n++) {
160     for (size_t i = 0; i < n; i++) {
161       ASSERT_TRUE(parser_.Consume(&reset_command[i], 1));
162       ASSERT_EQ(parser_.CurrentState(), H4Parser::State::HCI_RECOVERY);
163     }
164   }
165 
166   // Finally send the full HCI Reset command.
167   for (size_t i = 0; i < 4; i++) {
168     ASSERT_EQ(parser_.CurrentState(), H4Parser::State::HCI_RECOVERY);
169     ASSERT_TRUE(parser_.Consume(&reset_command[i], 1));
170   }
171 
172   // Validate that the HCI recovery state is exited,
173   // and the HCI Reset command correctly received on the command callback.
174   ASSERT_EQ(parser_.CurrentState(), H4Parser::State::HCI_TYPE);
175   ASSERT_LT(0, (int)packet_.size());
176 
177   // Validate that the HCI Reset command was correctly received.
178   ASSERT_EQ(type_, PacketType::COMMAND);
179   ASSERT_EQ(packet_.size(), reset_command.size() - 1);
180   for (size_t i = 1; i < packet_.size(); i++) {
181     ASSERT_EQ(packet_[i - 1], reset_command[i]);
182   }
183 }
184 
185 }  // namespace rootcanal
186