1 /*
2  * Copyright 2020 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 "hal/fuzz/fuzz_hci_hal.h"
18 
19 #include "fuzz/helpers.h"
20 #include "hci/fuzz/status_vs_complete_commands.h"
21 
22 namespace bluetooth {
23 namespace hal {
24 namespace fuzz {
25 using bluetooth::fuzz::GetArbitraryBytes;
26 
registerIncomingPacketCallback(HciHalCallbacks * callbacks)27 void FuzzHciHal::registerIncomingPacketCallback(HciHalCallbacks* callbacks) {
28   callbacks_ = callbacks;
29 }
30 
unregisterIncomingPacketCallback()31 void FuzzHciHal::unregisterIncomingPacketCallback() {
32   callbacks_ = nullptr;
33 }
34 
injectArbitrary(FuzzedDataProvider & fdp)35 void FuzzHciHal::injectArbitrary(FuzzedDataProvider& fdp) {
36   const uint8_t action = fdp.ConsumeIntegralInRange(0, 4);
37   switch (action) {
38     case 1:
39       injectAclData(GetArbitraryBytes(&fdp));
40       break;
41     case 2:
42       injectHciEvent(GetArbitraryBytes(&fdp));
43       break;
44     case 3:
45       injectScoData(GetArbitraryBytes(&fdp));
46       break;
47     case 4:
48       injectIsoData(GetArbitraryBytes(&fdp));
49       break;
50   }
51 }
52 
sendHciCommand(HciPacket packet)53 void FuzzHciHal::sendHciCommand(HciPacket packet) {
54   hci::CommandView command = hci::CommandView::FromBytes(packet);
55   if (!command.IsValid()) {
56     return;
57   }
58 
59   waiting_opcode_ = command.GetOpCode();
60   waiting_for_status_ = hci::fuzz::uses_command_status(waiting_opcode_);
61 }
62 
injectHciEvent(std::vector<uint8_t> data)63 void FuzzHciHal::injectHciEvent(std::vector<uint8_t> data) {
64   hci::EventView event = hci::EventView::FromBytes(data);
65   if (!event.IsValid()) {
66     return;
67   }
68 
69   hci::CommandCompleteView complete = hci::CommandCompleteView::Create(event);
70   if (complete.IsValid()) {
71     if (waiting_for_status_ || complete.GetCommandOpCode() != waiting_opcode_) {
72       return;
73     }
74   } else if (!waiting_for_status_) {
75     return;
76   }
77 
78   hci::CommandStatusView status = hci::CommandStatusView::Create(event);
79   if (status.IsValid()) {
80     if (!waiting_for_status_ || status.GetCommandOpCode() != waiting_opcode_) {
81       return;
82     }
83   } else if (waiting_for_status_) {
84     return;
85   }
86 
87   callbacks_->hciEventReceived(data);
88 }
89 
injectAclData(std::vector<uint8_t> data)90 void FuzzHciHal::injectAclData(std::vector<uint8_t> data) {
91   hci::AclView aclPacket = hci::AclView::FromBytes(data);
92   if (!aclPacket.IsValid()) {
93     return;
94   }
95 
96   callbacks_->aclDataReceived(data);
97 }
98 
injectScoData(std::vector<uint8_t> data)99 void FuzzHciHal::injectScoData(std::vector<uint8_t> data) {
100   hci::ScoView scoPacket = hci::ScoView::FromBytes(data);
101   if (!scoPacket.IsValid()) {
102     return;
103   }
104 
105   callbacks_->scoDataReceived(data);
106 }
107 
injectIsoData(std::vector<uint8_t> data)108 void FuzzHciHal::injectIsoData(std::vector<uint8_t> data) {
109   hci::IsoView isoPacket = hci::IsoView::FromBytes(data);
110   if (!isoPacket.IsValid()) {
111     return;
112   }
113 
114   callbacks_->isoDataReceived(data);
115 }
116 
__anon1eefef5e0102() 117 const ModuleFactory FuzzHciHal::Factory = ModuleFactory([]() { return new FuzzHciHal(); });
118 
119 }  // namespace fuzz
120 }  // namespace hal
121 }  // namespace bluetooth
122