blob: 2a319414bf063442d54307030a555cf8da8c2870 [file]
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <vector>
extern "C" {
#include <bluetooth.h>
}
#include <lib/support/CodeUtils.h>
namespace {
constexpr char kRemoteAddress[] = "00:11:22:33:44:55";
constexpr uint8_t kMatterUuidLow = 0xF6;
constexpr uint8_t kMatterUuidHigh = 0xFF;
constexpr uint8_t kDecoyUuidLow = 0x34;
constexpr uint8_t kDecoyUuidHigh = 0x12;
constexpr size_t kMaxServiceDataLen = 124;
bt_adapter_le_device_scan_result_info_s * gStartScanResult = nullptr;
int gStartScanReturn = BT_ERROR_NONE;
int gStartScanCallbackResult = BT_ERROR_NONE;
int gScanFilterReturn = BT_ERROR_NONE;
bool gScanFilterSupported = true;
bool gInvokeStartScanCallback = false;
void AppendServiceData(std::vector<char> & output, bool matterUuid, const uint8_t * data, size_t dataLen)
{
const size_t boundedLen = std::min(dataLen, kMaxServiceDataLen);
output.push_back(static_cast<char>(boundedLen + 3));
output.push_back(static_cast<char>(BT_ADAPTER_LE_ADVERTISING_DATA_SERVICE_DATA));
output.push_back(static_cast<char>(matterUuid ? kMatterUuidLow : kDecoyUuidLow));
output.push_back(static_cast<char>(matterUuid ? kMatterUuidHigh : kDecoyUuidHigh));
for (size_t i = 0; i < boundedLen; ++i)
{
output.push_back(static_cast<char>(data[i]));
}
}
std::vector<char> BuildPacket(const uint8_t * data, size_t len, bool forceMatterUuid, bool includeDecoy)
{
std::vector<char> packet;
const size_t decoyLen = includeDecoy ? len / 2 : 0;
if (includeDecoy)
{
AppendServiceData(packet, false, data, decoyLen);
}
AppendServiceData(packet, forceMatterUuid, data + decoyLen, len - decoyLen);
return packet;
}
} // namespace
extern "C" int bt_adapter_le_start_scan(void (*callback)(int, bt_adapter_le_device_scan_result_info_s *, void *), void * userData)
{
if (gInvokeStartScanCallback && callback != nullptr)
{
callback(gStartScanCallbackResult, gStartScanResult, userData);
}
return gStartScanReturn;
}
extern "C" int bt_adapter_le_stop_scan(void)
{
return BT_ERROR_NONE;
}
extern "C" int bt_adapter_le_is_scan_filter_supported(bool * isSupported)
{
if (isSupported == nullptr)
{
return BT_ERROR_INVALID_PARAMETER;
}
*isSupported = gScanFilterSupported;
return BT_ERROR_NONE;
}
extern "C" int bt_adapter_le_scan_filter_create(bt_scan_filter_h * filter)
{
if (filter == nullptr)
{
return BT_ERROR_INVALID_PARAMETER;
}
*filter = reinterpret_cast<bt_scan_filter_h>(0x1);
return gScanFilterReturn;
}
extern "C" int bt_adapter_le_scan_filter_unregister(bt_scan_filter_h)
{
return gScanFilterReturn;
}
extern "C" int bt_adapter_le_scan_filter_destroy(bt_scan_filter_h)
{
return gScanFilterReturn;
}
extern "C" int bt_adapter_le_scan_filter_set_device_address(bt_scan_filter_h, const char *)
{
return gScanFilterReturn;
}
extern "C" int bt_adapter_le_scan_filter_set_service_uuid(bt_scan_filter_h, const char *)
{
return gScanFilterReturn;
}
extern "C" int bt_adapter_le_scan_filter_set_service_data(bt_scan_filter_h, const char *, const char *, unsigned int)
{
return gScanFilterReturn;
}
extern "C" int bt_adapter_le_scan_filter_register(bt_scan_filter_h)
{
return gScanFilterReturn;
}
extern "C" const char * get_error_message(int)
{
return "stub";
}
#define private public
#include <platform/Tizen/ChipDeviceScanner.cpp>
#undef private
namespace {
class RecordingDelegate : public chip::DeviceLayer::Internal::ChipDeviceScannerDelegate
{
public:
void OnDeviceScanned(const bt_adapter_le_device_scan_result_info_s &,
const chip::Ble::ChipBLEDeviceIdentificationInfo &) override
{
deviceScannedCount++;
}
void OnScanComplete() override { scanCompleteCount++; }
void OnScanError(CHIP_ERROR) override { scanErrorCount++; }
size_t deviceScannedCount = 0;
size_t scanCompleteCount = 0;
size_t scanErrorCount = 0;
};
chip::DeviceLayer::Internal::ScanFilterType PickFilterType(uint8_t value)
{
using chip::DeviceLayer::Internal::ScanFilterType;
switch (value & 0x03)
{
case 0:
return ScanFilterType::kAddress;
case 1:
return ScanFilterType::kServiceUUID;
case 2:
return ScanFilterType::kServiceData;
default:
return ScanFilterType::kNoFilter;
}
}
void FillFilterData(chip::DeviceLayer::Internal::ScanFilterData & filterData, const uint8_t * data, size_t len)
{
std::memset(&filterData, 0, sizeof(filterData));
constexpr char fallbackAddress[] = "AA:BB:CC:DD:EE:FF";
constexpr char fallbackUuid[] = "0000fff6-0000-1000-8000-00805f9b34fb";
std::memcpy(filterData.address, fallbackAddress, sizeof(fallbackAddress));
std::memcpy(filterData.service_uuid, fallbackUuid, sizeof(fallbackUuid));
const size_t serviceDataLen = std::min(sizeof(filterData.service_data), len);
if (serviceDataLen > 0)
{
std::memcpy(filterData.service_data, data, serviceDataLen);
}
filterData.service_data_len = static_cast<unsigned int>(serviceDataLen);
}
void ExerciseTizenRTParser(bt_adapter_le_device_scan_result_info_s & scanInfo, uint8_t selector)
{
bt_adapter_le_service_data_s * dataList = nullptr;
int count = 0;
const auto packetType = (selector & 0x01) ? BT_ADAPTER_LE_PACKET_SCAN_RESPONSE : BT_ADAPTER_LE_PACKET_ADVERTISING;
if (bt_adapter_le_get_scan_result_service_data_list(&scanInfo, packetType, &dataList, &count) == BT_ERROR_NONE)
{
bt_adapter_le_free_service_data_list(dataList, count);
}
}
} // namespace
extern "C" int LLVMFuzzerTestOneInput(const uint8_t * data, size_t len)
{
if (len < 4)
{
return 0;
}
const uint8_t flags = data[0];
const size_t split = 1 + (data[1] % (len - 1));
const bool matterUuid = (flags & 0x01) != 0;
const bool includeDecoy = (flags & 0x02) != 0;
const bool scannerError = (flags & 0x04) != 0;
const bool nullScanInfo = (flags & 0x08) != 0;
std::vector<char> advData = BuildPacket(data + 2, split - 1, matterUuid, includeDecoy);
std::vector<char> scanData = BuildPacket(data + split, len - split, (flags & 0x10) != 0, (flags & 0x20) != 0);
bt_adapter_le_device_scan_result_info_s scanInfo = {
kRemoteAddress,
advData.empty() ? nullptr : advData.data(),
static_cast<int>(advData.size()),
scanData.empty() ? nullptr : scanData.data(),
static_cast<int>(scanData.size()),
};
RecordingDelegate delegate;
chip::DeviceLayer::Internal::ChipDeviceScanner scanner(&delegate);
ExerciseTizenRTParser(scanInfo, flags >> 6);
scanner.LeScanResultCb(scannerError ? BT_ERROR_INVALID_PARAMETER : BT_ERROR_NONE, nullScanInfo ? nullptr : &scanInfo);
chip::DeviceLayer::Internal::ScanFilterData filterData;
FillFilterData(filterData, data + 2, len - 2);
gStartScanResult = &scanInfo;
gStartScanCallbackResult = scannerError ? BT_ERROR_INVALID_PARAMETER : BT_ERROR_NONE;
gStartScanReturn = (flags & 0x40) ? BT_ERROR_INVALID_PARAMETER : BT_ERROR_NONE;
gScanFilterReturn = (flags & 0x80) ? BT_ERROR_INVALID_PARAMETER : BT_ERROR_NONE;
gScanFilterSupported = (data[2] & 0x01) == 0;
gInvokeStartScanCallback = (data[2] & 0x02) != 0;
(void) scanner.SetupScanFilter(PickFilterType(data[3]), filterData);
(void) scanner.RegisterScanFilter(PickFilterType(data[3] >> 2), filterData);
(void) scanner.StartScan(PickFilterType(data[3] >> 4), filterData);
(void) scanner.StopScan();
gStartScanResult = nullptr;
return 0;
}