/* * Copyright 2016 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "broken_adv.h" #include "model/setup/device_boutique.h" using std::vector; namespace rootcanal { bool BrokenAdv::registered_ = DeviceBoutique::Register("broken_adv", &BrokenAdv::Create); BrokenAdv::BrokenAdv() { advertising_interval_ms_ = std::chrono::milliseconds(1280); properties_.SetLeAdvertisementType(0x03 /* NON_CONNECT */); constant_adv_data_ = { 0x02, // Length 0x01, // TYPE_FLAG 0x4 | 0x2, // BREDR_NOT_SPT | GEN_DISC_FLAG 0x13, // Length 0x09, // TYPE_NAME_CMPL 'g', 'D', 'e', 'v', 'i', 'c', 'e', '-', 'b', 'r', 'o', 'k', 'e', 'n', '_', 'a', 'd', 'v', }; properties_.SetLeAdvertisement(constant_adv_data_); properties_.SetLeScanResponse({0x0b, // Length 0x08, // TYPE_NAME_SHORT 'b', 'r', 'o', 'k', 'e', 'n', 'n', 'e', 's', 's'}); properties_.SetExtendedInquiryData({0x07, // Length 0x09, // TYPE_NAME_COMPLETE 'B', 'R', '0', 'K', '3', 'N'}); properties_.SetPageScanRepetitionMode(0); page_scan_delay_ms_ = std::chrono::milliseconds(600); } BrokenAdv::BrokenAdv(const vector& args) : BrokenAdv() { if (args.size() >= 2) { Address addr{}; if (Address::FromString(args[1], addr)) properties_.SetLeAddress(addr); } if (args.size() >= 3) { SetAdvertisementInterval(std::chrono::milliseconds(std::stoi(args[2]))); } } // Mostly return the correct length static uint8_t random_length(size_t bytes_remaining) { uint32_t randomness = rand(); switch ((randomness & 0xf000000) >> 24) { case (0): return bytes_remaining + (randomness & 0xff); case (1): return bytes_remaining - (randomness & 0xff); case (2): return bytes_remaining + (randomness & 0xf); case (3): return bytes_remaining - (randomness & 0xf); case (5): case (6): return bytes_remaining + (randomness & 0x3); case (7): case (8): return bytes_remaining - (randomness & 0x3); default: return bytes_remaining; } } static size_t random_adv_type() { uint32_t randomness = rand(); switch ((randomness & 0xf000000) >> 24) { case (0): return 0xff; // TYPE_MANUFACTURER_SPECIFIC case (1): return (randomness & 0xff); default: return (randomness & 0x1f); } } static size_t random_data_length(size_t length, size_t bytes_remaining) { uint32_t randomness = rand(); switch ((randomness & 0xf000000) >> 24) { case (0): return bytes_remaining; case (1): return (length + (randomness & 0xff)) % bytes_remaining; default: return (length <= bytes_remaining ? length : bytes_remaining); } } static void RandomizeAdvertisement(vector& ad, size_t max) { uint8_t length = random_length(max); uint8_t data_length = random_data_length(length, max); ad.push_back(random_adv_type()); ad.push_back(length); for (size_t i = 0; i < data_length; i++) ad.push_back(rand() & 0xff); } void BrokenAdv::UpdateAdvertisement() { std::vector adv_data; for (size_t i = 0; i < constant_adv_data_.size(); i++) adv_data.push_back(constant_adv_data_[i]); RandomizeAdvertisement(adv_data, 31 - adv_data.size()); properties_.SetLeAdvertisement(adv_data); adv_data.clear(); RandomizeAdvertisement(adv_data, 31); properties_.SetLeScanResponse(adv_data); Address le_addr = properties_.GetLeAddress(); uint8_t* low_order_byte = (uint8_t*)(&le_addr); *low_order_byte += 1; properties_.SetLeAddress(le_addr); } std::string BrokenAdv::ToString() const { std::string str = Device::ToString() + std::string(": Interval = ") + std::to_string(advertising_interval_ms_.count()); return str; } void BrokenAdv::UpdatePageScan() { RandomizeAdvertisement(constant_scan_data_, 31); Address page_addr = properties_.GetAddress(); uint8_t* low_order_byte = (uint8_t*)(&page_addr); *low_order_byte += 1; properties_.SetAddress(page_addr); } void BrokenAdv::TimerTick() { UpdatePageScan(); UpdateAdvertisement(); } } // namespace rootcanal