Merge "Revert "Fix potential OOB write in btm_read_remote_ext_features_complete"" into oc-dev am: aa754ed3ec am: 53afb387a4 am: a651e35ad0 am: 91f38752fa am: 9d7aa50fb7 am: 9e976434fe
am: 2908ff6dbf
Change-Id: I71810ad8cf13389e09aa469b5c410ef8c9705d14
diff --git a/Android.bp b/Android.bp
index 49af99c..c56d51d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -28,8 +28,8 @@
]
filegroup {
- name: "BluetoothTestConfigTemplate",
- srcs: [
- "AndroidTestTemplate.xml"
- ]
+ name: "BluetoothTestConfigTemplate",
+ srcs: [
+ "AndroidTestTemplate.xml",
+ ],
}
diff --git a/OWNERS b/OWNERS
index 5596ce1..aeb2b83 100644
--- a/OWNERS
+++ b/OWNERS
@@ -2,7 +2,6 @@
# Project owners
zachoverflow@google.com
-apanicke@google.com
cmanton@google.com
hsz@google.com
jpawlowski@google.com
diff --git a/audio_a2dp_hw/Android.bp b/audio_a2dp_hw/Android.bp
index 7a23e27..fac3655 100644
--- a/audio_a2dp_hw/Android.bp
+++ b/audio_a2dp_hw/Android.bp
@@ -5,7 +5,7 @@
"system/bt",
"system/bt/include",
"system/bt/audio_a2dp_hw/include",
- ]
+ ],
}
// Audio A2DP shared library for target
diff --git a/audio_bluetooth_hw/Android.bp b/audio_bluetooth_hw/Android.bp
index 9cdd64a..de1effd 100644
--- a/audio_bluetooth_hw/Android.bp
+++ b/audio_bluetooth_hw/Android.bp
@@ -19,7 +19,6 @@
"libcutils",
"libfmq",
"libhidlbase",
- "libhidltransport",
"liblog",
"libutils",
],
diff --git a/audio_bluetooth_hw/stream_apis.cc b/audio_bluetooth_hw/stream_apis.cc
index 74b6f2a..9b4c5cf 100644
--- a/audio_bluetooth_hw/stream_apis.cc
+++ b/audio_bluetooth_hw/stream_apis.cc
@@ -36,13 +36,95 @@
namespace {
-constexpr unsigned int kMinimumDelayMs = 100;
+constexpr unsigned int kMinimumDelayMs = 50;
constexpr unsigned int kMaximumDelayMs = 1000;
constexpr int kExtraAudioSyncMs = 200;
std::ostream& operator<<(std::ostream& os, const audio_config& config) {
return os << "audio_config[sample_rate=" << config.sample_rate
- << ", channels=" << StringPrintf("%#x", config.channel_mask) << ", format=" << config.format << "]";
+ << ", channels=" << StringPrintf("%#x", config.channel_mask)
+ << ", format=" << config.format << "]";
+}
+
+void out_calculate_feeding_delay_ms(const BluetoothStreamOut* out,
+ uint32_t* latency_ms,
+ uint64_t* frames = nullptr,
+ struct timespec* timestamp = nullptr) {
+ if (latency_ms == nullptr && frames == nullptr && timestamp == nullptr) {
+ return;
+ }
+
+ // delay_report is the audio delay from the remote headset receiving data to
+ // the headset playing sound in units of nanoseconds
+ uint64_t delay_report_ns = 0;
+ uint64_t delay_report_ms = 0;
+ // absorbed_bytes is the total number of bytes sent by the Bluetooth stack to
+ // a remote headset
+ uint64_t absorbed_bytes = 0;
+ // absorbed_timestamp is the ...
+ struct timespec absorbed_timestamp = {};
+ bool timestamp_fetched = false;
+
+ std::unique_lock<std::mutex> lock(out->mutex_);
+ if (out->bluetooth_output_.GetPresentationPosition(
+ &delay_report_ns, &absorbed_bytes, &absorbed_timestamp)) {
+ delay_report_ms = delay_report_ns / 1000000;
+ // assume kMinimumDelayMs (50ms) < delay_report_ns < kMaximumDelayMs
+ // (1000ms), or it is invalid / ignored and use old delay calculated
+ // by ourselves.
+ if (delay_report_ms > kMinimumDelayMs &&
+ delay_report_ms < kMaximumDelayMs) {
+ timestamp_fetched = true;
+ } else if (delay_report_ms >= kMaximumDelayMs) {
+ LOG(INFO) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", delay_report=" << delay_report_ns << "ns abnormal";
+ }
+ }
+ if (!timestamp_fetched) {
+ // default to old delay if any failure is found when fetching from ports
+ // audio_a2dp_hw:
+ // frames_count = buffer_size / frame_size
+ // latency (sec.) = frames_count / samples_per_second (sample_rate)
+ // Sync from audio_a2dp_hw to add extra delay kExtraAudioSyncMs(+200ms)
+ delay_report_ms =
+ out->frames_count_ * 1000 / out->sample_rate_ + kExtraAudioSyncMs;
+ if (timestamp != nullptr) {
+ clock_gettime(CLOCK_MONOTONIC, &absorbed_timestamp);
+ }
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << " uses the legacy delay " << delay_report_ms << " ms";
+ }
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", delay=" << delay_report_ms << "ms, data=" << absorbed_bytes
+ << " bytes, timestamp=" << absorbed_timestamp.tv_sec << "."
+ << StringPrintf("%09ld", absorbed_timestamp.tv_nsec) << "s";
+
+ if (latency_ms != nullptr) {
+ *latency_ms = delay_report_ms;
+ }
+ if (frames != nullptr) {
+ const uint64_t latency_frames = delay_report_ms * out->sample_rate_ / 1000;
+ *frames = absorbed_bytes / audio_stream_out_frame_size(&out->stream_out_);
+ if (out->frames_presented_ < *frames) {
+ // Are we (the audio HAL) reset?! The stack counter is obsoleted.
+ *frames = out->frames_presented_;
+ } else if ((out->frames_presented_ - *frames) > latency_frames) {
+ // Is the Bluetooth output reset / restarted by AVDTP reconfig?! Its
+ // counter was reset but could not be used.
+ *frames = out->frames_presented_;
+ }
+ // suppose frames would be queued in the headset buffer for delay_report
+ // period, so those frames in buffers should not be included in the number
+ // of presented frames at the timestamp.
+ if (*frames > latency_frames) {
+ *frames -= latency_frames;
+ } else {
+ *frames = 0;
+ }
+ }
+ if (timestamp != nullptr) {
+ *timestamp = absorbed_timestamp;
+ }
}
} // namespace
@@ -340,17 +422,11 @@
static uint32_t out_get_latency_ms(const struct audio_stream_out* stream) {
const auto* out = reinterpret_cast<const BluetoothStreamOut*>(stream);
- std::unique_lock<std::mutex> lock(out->mutex_);
- /***
- * audio_a2dp_hw:
- * frames_count = buffer_size / frame_size
- * latency (sec.) = frames_count / sample_rate
- */
- uint32_t latency_ms = out->frames_count_ * 1000 / out->sample_rate_;
+ uint32_t latency_ms = 0;
+ out_calculate_feeding_delay_ms(out, &latency_ms);
LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
- << ", latency_ms=" << latency_ms;
- // Sync from audio_a2dp_hw to add extra +200ms
- return latency_ms + kExtraAudioSyncMs;
+ << ", latency=" << latency_ms << "ms";
+ return latency_ms;
}
static int out_set_volume(struct audio_stream_out* stream, float left,
@@ -419,13 +495,11 @@
static int out_get_render_position(const struct audio_stream_out* stream,
uint32_t* dsp_frames) {
- const auto* out = reinterpret_cast<const BluetoothStreamOut*>(stream);
- std::unique_lock<std::mutex> lock(out->mutex_);
-
if (dsp_frames == nullptr) return -EINVAL;
- /* frames = (latency (ms) / 1000) * sample_per_seconds */
- uint64_t latency_frames =
+ const auto* out = reinterpret_cast<const BluetoothStreamOut*>(stream);
+ // frames = (latency (ms) / 1000) * samples_per_second (sample_rate)
+ const uint64_t latency_frames =
(uint64_t)out_get_latency_ms(stream) * out->sample_rate_ / 1000;
if (out->frames_rendered_ >= latency_frames) {
*dsp_frames = (uint32_t)(out->frames_rendered_ - latency_frames);
@@ -527,52 +601,12 @@
return -EINVAL;
}
- // bytes is the total number of bytes sent by the Bluetooth stack to a
- // remote headset
- uint64_t bytes = 0;
- // delay_report is the audio delay from the remote headset receiving data to
- // the headset playing sound in units of nanoseconds
- uint64_t delay_report_ns = 0;
const auto* out = reinterpret_cast<const BluetoothStreamOut*>(stream);
- std::unique_lock<std::mutex> lock(out->mutex_);
-
- if (out->bluetooth_output_.GetPresentationPosition(&delay_report_ns, &bytes,
- timestamp)) {
- // assume kMinimumDelayMs (100ms) < delay_report_ns < kMaximumDelayMs
- // (1000ms), or it is invalid / ignored and use old delay calculated
- // by ourselves.
- if (delay_report_ns > kMinimumDelayMs * 1000000 &&
- delay_report_ns < kMaximumDelayMs * 1000000) {
- *frames = bytes / audio_stream_out_frame_size(stream);
- timestamp->tv_nsec += delay_report_ns;
- if (timestamp->tv_nsec > 1000000000) {
- timestamp->tv_sec += static_cast<int>(timestamp->tv_nsec / 1000000000);
- timestamp->tv_nsec %= 1000000000;
- }
- LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState() << ", frames=" << *frames << " ("
- << bytes << " bytes), timestamp=" << timestamp->tv_sec << "."
- << StringPrintf("%09ld", timestamp->tv_nsec) << "s";
- return 0;
- } else if (delay_report_ns >= kMaximumDelayMs * 1000000) {
- LOG(WARNING) << __func__
- << ": state=" << out->bluetooth_output_.GetState()
- << ", delay_report=" << delay_report_ns << "ns abnormal";
- }
- }
-
- // default to old delay if any failure is found when fetching from ports
- if (out->frames_presented_ >= out->frames_count_) {
- clock_gettime(CLOCK_MONOTONIC, timestamp);
- *frames = out->frames_presented_ - out->frames_count_;
- LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState() << ", frames=" << *frames << " ("
- << bytes << " bytes), timestamp=" << timestamp->tv_sec << "."
- << StringPrintf("%09ld", timestamp->tv_nsec) << "s";
- return 0;
- }
-
- *frames = 0;
- *timestamp = {};
- return -EWOULDBLOCK;
+ out_calculate_feeding_delay_ms(out, nullptr, frames, timestamp);
+ LOG(VERBOSE) << __func__ << ": state=" << out->bluetooth_output_.GetState()
+ << ", frames=" << *frames << ", timestamp=" << timestamp->tv_sec
+ << "." << StringPrintf("%09ld", timestamp->tv_nsec) << "s";
+ return 0;
}
static void out_update_source_metadata(
diff --git a/audio_bluetooth_hw/utils_unittest.cc b/audio_bluetooth_hw/utils_unittest.cc
index a457797..665dea6 100644
--- a/audio_bluetooth_hw/utils_unittest.cc
+++ b/audio_bluetooth_hw/utils_unittest.cc
@@ -25,8 +25,8 @@
class UtilsTest : public testing::Test {
protected:
- virtual void SetUp() {}
- virtual void TearDown() { map_.clear(); }
+ void SetUp() override {}
+ void TearDown() override { map_.clear(); }
std::unordered_map<std::string, std::string> map_;
};
diff --git a/audio_hal_interface/Android.bp b/audio_hal_interface/Android.bp
index 4b10435..94a77ff 100644
--- a/audio_hal_interface/Android.bp
+++ b/audio_hal_interface/Android.bp
@@ -19,7 +19,6 @@
"android.hardware.bluetooth.audio@2.0",
"libfmq",
"libhidlbase",
- "libhidltransport",
],
static_libs: [
"libosi",
@@ -46,7 +45,6 @@
"libcutils",
"libfmq",
"libhidlbase",
- "libhidltransport",
"liblog",
"libutils",
],
diff --git a/audio_hal_interface/a2dp_encoding.cc b/audio_hal_interface/a2dp_encoding.cc
index fc61128..1b362e5 100644
--- a/audio_hal_interface/a2dp_encoding.cc
+++ b/audio_hal_interface/a2dp_encoding.cc
@@ -82,11 +82,10 @@
return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_INCALL_FAILURE);
}
- if (btif_a2dp_source_is_streaming()) {
- LOG(ERROR) << __func__ << ": source is busy streaming";
- return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_FAILURE);
+ if (btif_av_stream_started_ready()) {
+ // Already started, ACK back immediately.
+ return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_SUCCESS);
}
-
if (btif_av_stream_ready()) {
/*
* Post start event and wait for audio path to open.
@@ -102,11 +101,6 @@
a2dp_pending_cmd_ = A2DP_CTRL_CMD_NONE;
return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_SUCCESS);
}
-
- if (btif_av_stream_started_ready()) {
- // Already started, ACK back immediately.
- return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_SUCCESS);
- }
LOG(ERROR) << __func__ << ": AV stream is not ready to start";
return a2dp_ack_to_bt_audio_ctrl_ack(A2DP_CTRL_ACK_FAILURE);
}
@@ -137,7 +131,7 @@
void StopRequest() override {
if (btif_av_get_peer_sep() == AVDT_TSEP_SNK &&
- !btif_a2dp_source_is_streaming()) {
+ !btif_av_stream_started_ready()) {
return;
}
LOG(INFO) << __func__ << ": handling";
diff --git a/audio_hal_interface/client_interface.cc b/audio_hal_interface/client_interface.cc
index 501e113..9f1be24 100644
--- a/audio_hal_interface/client_interface.cc
+++ b/audio_hal_interface/client_interface.cc
@@ -73,7 +73,7 @@
const android::sp<IBluetoothAudioProvider>& provider)
: sink_(sink), provider_(provider){};
- Return<void> startStream() {
+ Return<void> startStream() override {
BluetoothAudioCtrlAck ack = sink_->StartRequest();
if (ack != BluetoothAudioCtrlAck::PENDING) {
auto hidl_retval =
@@ -85,7 +85,7 @@
return Void();
}
- Return<void> suspendStream() {
+ Return<void> suspendStream() override {
BluetoothAudioCtrlAck ack = sink_->SuspendRequest();
if (ack != BluetoothAudioCtrlAck::PENDING) {
auto hidl_retval =
@@ -97,12 +97,13 @@
return Void();
}
- Return<void> stopStream() {
+ Return<void> stopStream() override {
sink_->StopRequest();
return Void();
}
- Return<void> getPresentationPosition(getPresentationPosition_cb _hidl_cb) {
+ Return<void> getPresentationPosition(
+ getPresentationPosition_cb _hidl_cb) override {
uint64_t remote_delay_report_ns;
uint64_t total_bytes_read;
timespec data_position;
@@ -128,7 +129,7 @@
return Void();
}
- Return<void> updateMetadata(const SourceMetadata& sourceMetadata) {
+ Return<void> updateMetadata(const SourceMetadata& sourceMetadata) override {
LOG(INFO) << __func__ << ": " << sourceMetadata.tracks.size()
<< " track(s)";
// refer to StreamOut.impl.h within Audio HAL (AUDIO_HAL_VERSION_5_0)
@@ -166,7 +167,8 @@
: bluetooth_audio_clientif_(clientif), message_loop_(message_loop) {}
void serviceDied(
uint64_t /*cookie*/,
- const ::android::wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
+ const ::android::wp<::android::hidl::base::V1_0::IBase>& /*who*/)
+ override {
LOG(WARNING) << __func__ << ": restarting connection with new Audio Hal";
if (bluetooth_audio_clientif_ != nullptr && message_loop_ != nullptr) {
// restart the session on the correct thread
diff --git a/audio_hal_interface/client_interface.h b/audio_hal_interface/client_interface.h
index 11984aa..8ee2bb1 100644
--- a/audio_hal_interface/client_interface.h
+++ b/audio_hal_interface/client_interface.h
@@ -158,8 +158,9 @@
static constexpr PcmParameters kInvalidPcmConfiguration = {
.sampleRate = SampleRate::RATE_UNKNOWN,
+ .channelMode = ChannelMode::UNKNOWN,
.bitsPerSample = BitsPerSample::BITS_UNKNOWN,
- .channelMode = ChannelMode::UNKNOWN};
+ };
private:
// Helper function to connect to an IBluetoothAudioProvider
diff --git a/audio_hal_interface/client_interface_unittest.cc b/audio_hal_interface/client_interface_unittest.cc
index de6ba52..fd8c8dc 100644
--- a/audio_hal_interface/client_interface_unittest.cc
+++ b/audio_hal_interface/client_interface_unittest.cc
@@ -65,16 +65,16 @@
public:
TestTransport(SessionType session_type)
: bluetooth::audio::IBluetoothTransportInstance(session_type, {}){};
- bluetooth::audio::BluetoothAudioCtrlAck StartRequest() {
+ bluetooth::audio::BluetoothAudioCtrlAck StartRequest() override {
return bluetooth::audio::BluetoothAudioCtrlAck::SUCCESS_FINISHED;
}
- bluetooth::audio::BluetoothAudioCtrlAck SuspendRequest() {
+ bluetooth::audio::BluetoothAudioCtrlAck SuspendRequest() override {
return bluetooth::audio::BluetoothAudioCtrlAck::SUCCESS_FINISHED;
}
- void StopRequest() {}
+ void StopRequest() override {}
bool GetPresentationPosition(uint64_t* remote_delay_report_ns,
uint64_t* total_bytes_readed,
- timespec* data_position) {
+ timespec* data_position) override {
if (remote_delay_report_ns) {
*remote_delay_report_ns = kRemoteDelayReportMs * 1000000;
}
@@ -86,9 +86,10 @@
}
return true;
}
- void MetadataChanged(const source_metadata_t& source_metadata __unused) {}
- void ResetPresentationPosition(){};
- void LogBytesRead(size_t bytes_readed __unused){};
+ void MetadataChanged(
+ const source_metadata_t& source_metadata __unused) override {}
+ void ResetPresentationPosition() override{};
+ void LogBytesRead(size_t bytes_readed __unused) override{};
};
class BluetoothAudioClientInterfaceTest : public Test {
@@ -98,9 +99,9 @@
static constexpr int kClientIfReturnSuccess = 0;
- virtual void SetUp() override {}
+ void SetUp() override {}
- virtual void TearDown() override {
+ void TearDown() override {
clientif_ = nullptr;
test_transport_ = nullptr;
}
diff --git a/audio_hearing_aid_hw/Android.bp b/audio_hearing_aid_hw/Android.bp
index 229fc25..4ed9e76 100644
--- a/audio_hearing_aid_hw/Android.bp
+++ b/audio_hearing_aid_hw/Android.bp
@@ -5,7 +5,7 @@
"system/bt",
"system/bt/include",
"system/bt/audio_hearing_aid_hw/include",
- ]
+ ],
}
// Audio A2DP shared library for target
diff --git a/binder/Android.bp b/binder/Android.bp
index 650906c..e4beadb 100644
--- a/binder/Android.bp
+++ b/binder/Android.bp
@@ -9,7 +9,7 @@
"android/bluetooth/bluetooth_device.cc",
"android/bluetooth/IBluetoothSocketManager.aidl",
"android/os/parcel_uuid.cc",
-/* TODO: Uncomment this files as they get converted one-by-one into native implementation
+ /* TODO: Uncomment this files as they get converted one-by-one into native implementation
"android/bluetooth/IBluetooth.aidl",
"android/bluetooth/IBluetoothA2dp.aidl",
"android/bluetooth/IBluetoothA2dpSink.aidl",
@@ -40,21 +40,20 @@
"android/bluetooth/le/IAdvertisingSetCallback.aidl",
"android/bluetooth/le/IPeriodicAdvertisingCallback.aidl",
"android/bluetooth/le/IScannerCallback.aidl"
-*/
- ],
- export_include_dirs: [ "./"],
+ */
+ ],
+ export_include_dirs: ["./"],
aidl: {
export_aidl_headers: true,
include_dirs: [
"frameworks/native/aidl/binder",
- /* required for android.os.ParcelUuid, and android.os.ParcelFileDescriptor */
+ /* required for android.os.ParcelUuid, and android.os.ParcelFileDescriptor */
"frameworks/base/core/java",
"system/bt/binder",
],
},
include_dirs: [
- "libnativehelper/include/nativehelper",
"system/bt/types",
],
shared_libs: [
diff --git a/binder/android/bluetooth/IBluetooth.aidl b/binder/android/bluetooth/IBluetooth.aidl
index 6bda14b..d095682 100644
--- a/binder/android/bluetooth/IBluetooth.aidl
+++ b/binder/android/bluetooth/IBluetooth.aidl
@@ -35,12 +35,14 @@
*/
interface IBluetooth
{
+ @UnsupportedAppUsage
boolean isEnabled();
int getState();
boolean enable();
boolean enableNoAutoConnect();
boolean disable();
+ @UnsupportedAppUsage
String getAddress();
ParcelUuid[] getUuids();
boolean setName(in String name);
@@ -79,10 +81,12 @@
String getRemoteName(in BluetoothDevice device);
int getRemoteType(in BluetoothDevice device);
+ @UnsupportedAppUsage
String getRemoteAlias(in BluetoothDevice device);
boolean setRemoteAlias(in BluetoothDevice device, in String name);
int getRemoteClass(in BluetoothDevice device);
ParcelUuid[] getRemoteUuids(in BluetoothDevice device);
+ @UnsupportedAppUsage
boolean fetchRemoteUuids(in BluetoothDevice device);
boolean sdpSearch(in BluetoothDevice device, in ParcelUuid uuid);
int getBatteryLevel(in BluetoothDevice device);
@@ -102,6 +106,7 @@
int getSimAccessPermission(in BluetoothDevice device);
boolean setSimAccessPermission(in BluetoothDevice device, int value);
+ @UnsupportedAppUsage
void sendConnectionStateChange(in BluetoothDevice device, int profile, int state, int prevState);
void registerCallback(in IBluetoothCallback callback);
@@ -141,4 +146,7 @@
void onLeServiceUp();
void onBrEdrDown();
+
+ boolean connectAllEnabledProfiles(in BluetoothDevice device);
+ boolean disconnectAllEnabledProfiles(in BluetoothDevice device);
}
diff --git a/binder/android/bluetooth/IBluetoothA2dp.aidl b/binder/android/bluetooth/IBluetoothA2dp.aidl
index 6606a1b..9cbd9ca 100644
--- a/binder/android/bluetooth/IBluetoothA2dp.aidl
+++ b/binder/android/bluetooth/IBluetoothA2dp.aidl
@@ -27,14 +27,20 @@
*/
interface IBluetoothA2dp {
// Public API
+ @UnsupportedAppUsage
boolean connect(in BluetoothDevice device);
+ @UnsupportedAppUsage
boolean disconnect(in BluetoothDevice device);
+ @UnsupportedAppUsage
List<BluetoothDevice> getConnectedDevices();
+ @UnsupportedAppUsage
List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+ @UnsupportedAppUsage
int getConnectionState(in BluetoothDevice device);
boolean setActiveDevice(in BluetoothDevice device);
BluetoothDevice getActiveDevice();
boolean setPriority(in BluetoothDevice device, int priority);
+ @UnsupportedAppUsage
int getPriority(in BluetoothDevice device);
boolean isAvrcpAbsoluteVolumeSupported();
oneway void setAvrcpAbsoluteVolume(int volume);
diff --git a/binder/android/bluetooth/IBluetoothGatt.aidl b/binder/android/bluetooth/IBluetoothGatt.aidl
index c9e1c4b..016eeff 100644
--- a/binder/android/bluetooth/IBluetoothGatt.aidl
+++ b/binder/android/bluetooth/IBluetoothGatt.aidl
@@ -71,8 +71,10 @@
void registerSync(in ScanResult scanResult, in int skip, in int timeout, in IPeriodicAdvertisingCallback callback);
void unregisterSync(in IPeriodicAdvertisingCallback callback);
+ @UnsupportedAppUsage
void registerClient(in ParcelUuid appId, in IBluetoothGattCallback callback);
+ @UnsupportedAppUsage
void unregisterClient(in int clientIf);
void clientConnect(in int clientIf, in String address, in boolean isDirect, in int transport, in boolean opportunistic, in int phy);
void clientDisconnect(in int clientIf, in String address);
diff --git a/binder/android/bluetooth/IBluetoothHeadset.aidl b/binder/android/bluetooth/IBluetoothHeadset.aidl
index 0f6954c..c59cab1 100644
--- a/binder/android/bluetooth/IBluetoothHeadset.aidl
+++ b/binder/android/bluetooth/IBluetoothHeadset.aidl
@@ -29,8 +29,10 @@
*/
interface IBluetoothHeadset {
// Public API
+ @UnsupportedAppUsage
List<BluetoothDevice> getConnectedDevices();
List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
+ @UnsupportedAppUsage
int getConnectionState(in BluetoothDevice device);
boolean startVoiceRecognition(in BluetoothDevice device);
boolean stopVoiceRecognition(in BluetoothDevice device);
@@ -40,9 +42,13 @@
in String arg);
// Hidden API
+ @UnsupportedAppUsage
boolean connect(in BluetoothDevice device);
+ @UnsupportedAppUsage
boolean disconnect(in BluetoothDevice device);
+ @UnsupportedAppUsage
boolean setPriority(in BluetoothDevice device, int priority);
+ @UnsupportedAppUsage
int getPriority(in BluetoothDevice device);
int getAudioState(in BluetoothDevice device);
boolean isAudioOn();
diff --git a/binder/android/bluetooth/IBluetoothHeadsetClient.aidl b/binder/android/bluetooth/IBluetoothHeadsetClient.aidl
index 13495ae..6341af4 100644
--- a/binder/android/bluetooth/IBluetoothHeadsetClient.aidl
+++ b/binder/android/bluetooth/IBluetoothHeadsetClient.aidl
@@ -59,6 +59,7 @@
boolean disconnectAudio(in BluetoothDevice device);
void setAudioRouteAllowed(in BluetoothDevice device, boolean allowed);
boolean getAudioRouteAllowed(in BluetoothDevice device);
+ boolean sendVendorAtCommand(in BluetoothDevice device, int vendorId, String atCommand);
Bundle getCurrentAgFeatures(in BluetoothDevice device);
}
diff --git a/binder/android/bluetooth/IBluetoothManager.aidl b/binder/android/bluetooth/IBluetoothManager.aidl
index 2e12700..faf78d8 100644
--- a/binder/android/bluetooth/IBluetoothManager.aidl
+++ b/binder/android/bluetooth/IBluetoothManager.aidl
@@ -31,13 +31,16 @@
{
IBluetooth registerAdapter(in IBluetoothManagerCallback callback);
void unregisterAdapter(in IBluetoothManagerCallback callback);
+ @UnsupportedAppUsage
void registerStateChangeCallback(in IBluetoothStateChangeCallback callback);
+ @UnsupportedAppUsage
void unregisterStateChangeCallback(in IBluetoothStateChangeCallback callback);
boolean isEnabled();
boolean enable(String packageName);
boolean enableNoAutoConnect(String packageName);
boolean disable(String packageName, boolean persist);
int getState();
+ @UnsupportedAppUsage
IBluetoothGatt getBluetoothGatt();
boolean bindBluetoothProfileService(int profile, IBluetoothProfileServiceConnection proxy);
diff --git a/binder/android/bluetooth/IBluetoothMap.aidl b/binder/android/bluetooth/IBluetoothMap.aidl
index 562490e..1274787 100644
--- a/binder/android/bluetooth/IBluetoothMap.aidl
+++ b/binder/android/bluetooth/IBluetoothMap.aidl
@@ -26,7 +26,6 @@
interface IBluetoothMap {
int getState();
BluetoothDevice getClient();
- boolean connect(in BluetoothDevice device);
boolean disconnect(in BluetoothDevice device);
boolean isConnected(in BluetoothDevice device);
List<BluetoothDevice> getConnectedDevices();
diff --git a/bta/Android.bp b/bta/Android.bp
index 0e7bfe8..824076e 100644
--- a/bta/Android.bp
+++ b/bta/Android.bp
@@ -34,7 +34,6 @@
cc_library_static {
name: "libbt-bta",
defaults: ["fluoride_bta_defaults"],
- cflags: ["-Wno-implicit-fallthrough"],
srcs: [
"ag/bta_ag_act.cc",
"ag/bta_ag_api.cc",
diff --git a/bta/ag/bta_ag_main.cc b/bta/ag/bta_ag_main.cc
index f70027f..f7bb8be 100644
--- a/bta/ag/bta_ag_main.cc
+++ b/bta/ag/bta_ag_main.cc
@@ -564,8 +564,8 @@
if (p_scb->state == BTA_AG_INIT_ST) {
LOG(INFO) << __func__ << ": Resume connection to " << p_scb->peer_addr
<< ", handle" << bta_ag_scb_to_idx(p_scb);
- tBTA_AG_DATA open_data = {.api_open.bd_addr = p_scb->peer_addr,
- .api_open.sec_mask = p_scb->cli_sec_mask};
+ tBTA_AG_DATA open_data = {.api_open = {.bd_addr = p_scb->peer_addr,
+ .sec_mask = p_scb->cli_sec_mask}};
bta_ag_sm_execute(p_scb, BTA_AG_API_OPEN_EVT, open_data);
} else {
VLOG(1) << __func__ << ": device " << p_scb->peer_addr
diff --git a/bta/ag/bta_ag_sdp.cc b/bta/ag/bta_ag_sdp.cc
index ba955d3..88b3bdb 100644
--- a/bta/ag/bta_ag_sdp.cc
+++ b/bta/ag/bta_ag_sdp.cc
@@ -87,7 +87,7 @@
} else {
event = BTA_AG_DISC_INT_RES_EVT;
}
- tBTA_AG_DATA disc_result = {.disc_result.status = status};
+ tBTA_AG_DATA disc_result = {.disc_result = {.status = status}};
do_in_main_thread(FROM_HERE, base::Bind(&bta_ag_sm_execute_by_handle, idx,
event, disc_result));
}
diff --git a/bta/av/bta_av_aact.cc b/bta/av/bta_av_aact.cc
index b022b43..4cfc3e6 100644
--- a/bta/av/bta_av_aact.cc
+++ b/bta/av/bta_av_aact.cc
@@ -1167,6 +1167,7 @@
} else {
/* we do not know the peer device and it is using non-SBC codec
* we need to know all the SEPs on SNK */
+ if (p_scb->uuid_int == 0) p_scb->uuid_int = p_scb->open_api.uuid;
bta_av_discover_req(p_scb, NULL);
return;
}
@@ -1246,7 +1247,6 @@
open.chnl = p_scb->chnl;
open.hndl = p_scb->hndl;
open.status = BTA_AV_SUCCESS;
- open.starting = bta_av_chk_start(p_scb);
open.edr = 0;
p = BTM_ReadRemoteFeatures(p_scb->PeerAddress());
if (p != NULL) {
@@ -1262,8 +1262,10 @@
bta_ar_avdt_conn(BTA_ID_AV, open.bd_addr, p_scb->hdi);
#endif
if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SRC) {
+ open.starting = false;
open.sep = AVDT_TSEP_SNK;
} else if (p_scb->seps[p_scb->sep_idx].tsep == AVDT_TSEP_SNK) {
+ open.starting = bta_av_chk_start(p_scb);
open.sep = AVDT_TSEP_SRC;
}
@@ -2100,6 +2102,8 @@
uint8_t m_pt = 0x60;
tAVDT_DATA_OPT_MASK opt;
+ if (!p_scb->started) return;
+
if (p_scb->cong) return;
if (p_scb->use_rtp_header_marker_bit) {
@@ -3105,7 +3109,7 @@
ARRAY_TO_STREAM(p_param, offload_start->codec_info,
(int8_t)sizeof(offload_start->codec_info));
p_scb->offload_started = true;
- BTM_VendorSpecificCommand(HCI_CONTROLLER_A2DP_OPCODE_OCF, p_param - param,
+ BTM_VendorSpecificCommand(HCI_CONTROLLER_A2DP, p_param - param,
param, offload_vendor_callback);
}
@@ -3113,7 +3117,7 @@
uint8_t param[sizeof(tBT_A2DP_OFFLOAD)];
APPL_TRACE_DEBUG("%s", __func__);
param[0] = VS_HCI_A2DP_OFFLOAD_STOP;
- BTM_VendorSpecificCommand(HCI_CONTROLLER_A2DP_OPCODE_OCF, 1, param,
+ BTM_VendorSpecificCommand(HCI_CONTROLLER_A2DP, 1, param,
offload_vendor_callback);
}
/*******************************************************************************
diff --git a/bta/av/bta_av_main.cc b/bta/av/bta_av_main.cc
index bdd8a70..e33635e 100644
--- a/bta/av/bta_av_main.cc
+++ b/bta/av/bta_av_main.cc
@@ -243,9 +243,7 @@
enable.features = bta_av_cb.features;
/* Register for SCO change event */
- if (!(bta_av_cb.features & BTA_AV_FEAT_NO_SCO_SSPD)) {
- bta_sys_sco_register(bta_av_sco_chg_cback);
- }
+ bta_sys_sco_register(bta_av_sco_chg_cback);
/* call callback with enable event */
tBTA_AV bta_av_data;
@@ -986,16 +984,20 @@
int i;
tBTA_AV_API_STOP stop;
- APPL_TRACE_DEBUG("%s: id:%d status:%d", __func__, id, status);
+ LOG(INFO) << __func__ << ": status=" << +status << ", num_links=" << +id;
if (id) {
bta_av_cb.sco_occupied = true;
+ if (bta_av_cb.features & BTA_AV_FEAT_NO_SCO_SSPD) {
+ return;
+ }
+
/* either BTA_SYS_SCO_OPEN or BTA_SYS_SCO_CLOSE with remaining active SCO */
for (i = 0; i < BTA_AV_NUM_STRS; i++) {
p_scb = bta_av_cb.p_scb[i];
if (p_scb && p_scb->co_started && (!p_scb->sco_suspend)) {
- APPL_TRACE_DEBUG("%s: suspending scb:%d", __func__, i);
+ VLOG(1) << __func__ << ": suspending scb:" << i;
/* scb is used and started, not suspended automatically */
p_scb->sco_suspend = true;
stop.flush = false;
@@ -1007,12 +1009,16 @@
} else {
bta_av_cb.sco_occupied = false;
+ if (bta_av_cb.features & BTA_AV_FEAT_NO_SCO_SSPD) {
+ return;
+ }
+
for (i = 0; i < BTA_AV_NUM_STRS; i++) {
p_scb = bta_av_cb.p_scb[i];
if (p_scb && p_scb->sco_suspend) /* scb is used and suspended for SCO */
{
- APPL_TRACE_DEBUG("%s: starting scb:%d", __func__, i);
+ VLOG(1) << __func__ << ": starting scb:" << i;
bta_av_ssm_execute(p_scb, BTA_AV_AP_START_EVT, NULL);
}
}
@@ -1108,7 +1114,7 @@
"%s: peer %s BTM_SwitchRole(BTM_ROLE_MASTER) error: %d",
__func__, p_scb->PeerAddress().ToString().c_str(), status);
}
- if (status != BTM_DEV_BLACKLISTED) {
+ if (status != BTM_MODE_UNSUPPORTED && status != BTM_DEV_BLACKLISTED) {
is_ok = false;
p_scb->wait |= BTA_AV_WAIT_ROLE_SW_RES_START;
}
diff --git a/bta/av/bta_av_ssm.cc b/bta/av/bta_av_ssm.cc
index a1a94b0..80effa3 100644
--- a/bta/av/bta_av_ssm.cc
+++ b/bta/av/bta_av_ssm.cc
@@ -329,7 +329,7 @@
/* STR_RECONFIG_CFM_EVT */
{BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
/* AVRC_TIMER_EVT */
- {BTA_AV_OPEN_RC, BTA_AV_CHK_2ND_START, BTA_AV_OPEN_SST},
+ {BTA_AV_OPEN_RC, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
/* AVDT_CONNECT_EVT */ {BTA_AV_SIGNORE, BTA_AV_SIGNORE, BTA_AV_OPEN_SST},
/* AVDT_DISCONNECT_EVT */
{BTA_AV_STR_CLOSED, BTA_AV_SIGNORE, BTA_AV_INIT_SST},
diff --git a/bta/dm/bta_dm_act.cc b/bta/dm/bta_dm_act.cc
index 7ba3c74..4942eea 100644
--- a/bta/dm/bta_dm_act.cc
+++ b/bta/dm/bta_dm_act.cc
@@ -42,6 +42,7 @@
#include "btm_api.h"
#include "btm_int.h"
#include "btu.h"
+#include "device/include/interop.h"
#include "gap_api.h" /* For GAP_BleReadPeerPrefConnParams */
#include "l2c_api.h"
#include "osi/include/log.h"
@@ -1356,8 +1357,10 @@
do {
p_sdp_rec = NULL;
if (bta_dm_search_cb.service_index == (BTA_USER_SERVICE_ID + 1)) {
- p_sdp_rec = SDP_FindServiceUUIDInDb(bta_dm_search_cb.p_sdp_db,
- bta_dm_search_cb.uuid, p_sdp_rec);
+ if (!bta_dm_search_cb.uuid.IsEmpty()) {
+ p_sdp_rec = SDP_FindServiceUUIDInDb(bta_dm_search_cb.p_sdp_db,
+ bta_dm_search_cb.uuid, p_sdp_rec);
+ }
if (p_sdp_rec && SDP_FindProtocolListElemInRec(
p_sdp_rec, UUID_PROTOCOL_RFCOMM, &pe)) {
@@ -1771,7 +1774,6 @@
*
******************************************************************************/
static void bta_dm_find_services(const RawAddress& bd_addr) {
-
while (bta_dm_search_cb.service_index < BTA_MAX_SERVICE_ID) {
Uuid uuid = Uuid::kEmpty;
if (bta_dm_search_cb.services_to_search &
@@ -1945,10 +1947,13 @@
APPL_TRACE_DEBUG("%s appl_knows_rem_name %d", __func__,
bta_dm_search_cb.p_btm_inq_info->appl_knows_rem_name);
}
- if ((bta_dm_search_cb.p_btm_inq_info) &&
- (bta_dm_search_cb.p_btm_inq_info->results.device_type ==
- BT_DEVICE_TYPE_BLE) &&
- (bta_dm_search_cb.state == BTA_DM_SEARCH_ACTIVE)) {
+ if (((bta_dm_search_cb.p_btm_inq_info) &&
+ (bta_dm_search_cb.p_btm_inq_info->results.device_type ==
+ BT_DEVICE_TYPE_BLE) &&
+ (bta_dm_search_cb.state == BTA_DM_SEARCH_ACTIVE)) ||
+ (transport == BT_TRANSPORT_LE &&
+ interop_match_addr(INTEROP_DISABLE_NAME_REQUEST,
+ &bta_dm_search_cb.peer_bdaddr))) {
/* Do not perform RNR for LE devices at inquiry complete*/
bta_dm_search_cb.name_discover_done = true;
}
@@ -2504,7 +2509,7 @@
sec_event.cfm_req.loc_io_caps = p_data->cfm_req.loc_io_caps;
sec_event.cfm_req.rmt_io_caps = p_data->cfm_req.rmt_io_caps;
- /* continue to next case */
+ [[fallthrough]];
/* Passkey entry mode, mobile device with output capability is very
unlikely to receive key request, so skip this event */
/*case BTM_SP_KEY_REQ_EVT: */
@@ -2767,6 +2772,9 @@
bta_dm_cb.device_list.peer_device[i].peer_bdaddr))
issue_unpair_cb = true;
+ /* remove all cached GATT information */
+ BTA_GATTC_Refresh(bd_addr);
+
APPL_TRACE_DEBUG("%s: Unpairing: issue unpair CB = %d ", __func__,
issue_unpair_cb);
}
diff --git a/bta/dm/bta_dm_cfg.cc b/bta/dm/bta_dm_cfg.cc
index 438f329..e1e2cad 100644
--- a/bta/dm/bta_dm_cfg.cc
+++ b/bta/dm/bta_dm_cfg.cc
@@ -130,9 +130,9 @@
{BTA_ID_CG, BTA_ALL_APP_ID, 1}, /* cg resue ct spec table */
{BTA_ID_DG, BTA_ALL_APP_ID, 2}, /* dg spec table */
{BTA_ID_AV, BTA_ALL_APP_ID, 4}, /* av spec table */
- {BTA_ID_AVK, BTA_ALL_APP_ID, 12}, /* avk spec table */
- {BTA_ID_FTC, BTA_ALL_APP_ID, 6}, /* ftc spec table */
- {BTA_ID_FTS, BTA_ALL_APP_ID, 7}, /* fts spec table */
+ {BTA_ID_AVK, BTA_ALL_APP_ID, 13}, /* avk spec table */
+ {BTA_ID_FTC, BTA_ALL_APP_ID, 7}, /* ftc spec table */
+ {BTA_ID_FTS, BTA_ALL_APP_ID, 8}, /* fts spec table */
{BTA_ID_HD, BTA_ALL_APP_ID, 3}, /* hd spec table */
{BTA_ID_HH, BTA_HH_APP_ID_JOY, 5}, /* app BTA_HH_APP_ID_JOY,
similar to hh spec table */
@@ -140,19 +140,19 @@
similar to hh spec table */
{BTA_ID_HH, BTA_ALL_APP_ID, 6}, /* hh spec table */
{BTA_ID_PBC, BTA_ALL_APP_ID, 2}, /* reuse dg spec table */
- {BTA_ID_PBS, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */
- {BTA_ID_OPC, BTA_ALL_APP_ID, 6}, /* reuse ftc spec table */
- {BTA_ID_OPS, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */
- {BTA_ID_MSE, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */
+ {BTA_ID_PBS, BTA_ALL_APP_ID, 8}, /* reuse fts spec table */
+ {BTA_ID_OPC, BTA_ALL_APP_ID, 7}, /* reuse ftc spec table */
+ {BTA_ID_OPS, BTA_ALL_APP_ID, 8}, /* reuse fts spec table */
+ {BTA_ID_MSE, BTA_ALL_APP_ID, 8}, /* reuse fts spec table */
{BTA_ID_JV, BTA_JV_PM_ID_1,
- 6}, /* app BTA_JV_PM_ID_1, reuse ftc spec table */
- {BTA_ID_JV, BTA_ALL_APP_ID, 7}, /* reuse fts spec table */
- {BTA_ID_HL, BTA_ALL_APP_ID, 8}, /* reuse fts spec table */
- {BTA_ID_PAN, BTUI_PAN_ID_PANU, 9}, /* PANU spec table */
- {BTA_ID_PAN, BTUI_PAN_ID_NAP, 10}, /* NAP spec table */
- {BTA_ID_HS, BTA_ALL_APP_ID, 11}, /* HS spec table */
- {BTA_ID_GATTC, BTA_ALL_APP_ID, 13}, /* gattc spec table */
- {BTA_ID_GATTS, BTA_ALL_APP_ID, 14} /* gatts spec table */
+ 7}, /* app BTA_JV_PM_ID_1, reuse ftc spec table */
+ {BTA_ID_JV, BTA_ALL_APP_ID, 8}, /* reuse fts spec table */
+ {BTA_ID_HL, BTA_ALL_APP_ID, 9}, /* reuse fts spec table */
+ {BTA_ID_PAN, BTUI_PAN_ID_PANU, 10}, /* PANU spec table */
+ {BTA_ID_PAN, BTUI_PAN_ID_NAP, 11}, /* NAP spec table */
+ {BTA_ID_HS, BTA_ALL_APP_ID, 12}, /* HS spec table */
+ {BTA_ID_GATTC, BTA_ALL_APP_ID, 14}, /* gattc spec table */
+ {BTA_ID_GATTS, BTA_ALL_APP_ID, 15} /* gatts spec table */
};
tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = {
diff --git a/bta/gatt/bta_gattc_act.cc b/bta/gatt/bta_gattc_act.cc
index b009e5a..3ff55b1 100644
--- a/bta/gatt/bta_gattc_act.cc
+++ b/bta/gatt/bta_gattc_act.cc
@@ -213,7 +213,7 @@
}
/* remove bg connection associated with this rcb */
- for (uint8_t i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i++) {
+ for (uint8_t i = 0; i < BTM_GetWhiteListSize(); i++) {
if (!bta_gattc_cb.bg_track[i].in_use) continue;
if (bta_gattc_cb.bg_track[i].cif_mask & (1 << (p_clreg->client_if - 1))) {
diff --git a/bta/gatt/bta_gattc_int.h b/bta/gatt/bta_gattc_int.h
index f0ead49..45a54c3 100644
--- a/bta/gatt/bta_gattc_int.h
+++ b/bta/gatt/bta_gattc_int.h
@@ -71,9 +71,9 @@
#define BTA_GATTC_CL_MAX 32
#endif
-/* max known devices GATTC can support */
+/* max known devices GATTC can support in Bluetooth spec */
#ifndef BTA_GATTC_KNOWN_SR_MAX
-#define BTA_GATTC_KNOWN_SR_MAX 10
+#define BTA_GATTC_KNOWN_SR_MAX 255
#endif
#define BTA_GATTC_CONN_MAX GATT_MAX_PHY_CHANNEL
diff --git a/bta/gatt/bta_gattc_queue.cc b/bta/gatt/bta_gattc_queue.cc
index 6d9fff3..6d8f57c 100644
--- a/bta/gatt/bta_gattc_queue.cc
+++ b/bta/gatt/bta_gattc_queue.cc
@@ -171,9 +171,9 @@
GATT_WRITE_OP_CB cb, void* cb_data) {
gatt_op_queue[conn_id].push_back({.type = GATT_WRITE_CHAR,
.handle = handle,
- .write_type = write_type,
.write_cb = cb,
.write_cb_data = cb_data,
+ .write_type = write_type,
.value = std::move(value)});
gatt_execute_next_op(conn_id);
}
@@ -184,9 +184,9 @@
GATT_WRITE_OP_CB cb, void* cb_data) {
gatt_op_queue[conn_id].push_back({.type = GATT_WRITE_DESC,
.handle = handle,
- .write_type = write_type,
.write_cb = cb,
.write_cb_data = cb_data,
+ .write_type = write_type,
.value = std::move(value)});
gatt_execute_next_op(conn_id);
}
diff --git a/bta/gatt/bta_gattc_utils.cc b/bta/gatt/bta_gattc_utils.cc
index 2c8e5fd..d0b45c1 100644
--- a/bta/gatt/bta_gattc_utils.cc
+++ b/bta/gatt/bta_gattc_utils.cc
@@ -224,7 +224,7 @@
tBTA_GATTC_SERV* p_srcb = &bta_gattc_cb.known_server[0];
uint8_t i;
- for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i++, p_srcb++) {
+ for (i = 0; i < BTM_GetWhiteListSize(); i++, p_srcb++) {
if (p_srcb->in_use && p_srcb->server_bda == bda) return p_srcb;
}
return NULL;
@@ -243,7 +243,7 @@
tBTA_GATTC_SERV* p_srcb = &bta_gattc_cb.known_server[0];
uint8_t i;
- for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i++, p_srcb++) {
+ for (i = 0; i < BTM_GetWhiteListSize(); i++, p_srcb++) {
if (p_srcb->server_bda == bda) return p_srcb;
}
return NULL;
@@ -279,7 +279,7 @@
bool found = false;
uint8_t i;
- for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i++, p_tcb++) {
+ for (i = 0; i < BTM_GetWhiteListSize(); i++, p_tcb++) {
if (!p_tcb->in_use) {
found = true;
break;
@@ -409,7 +409,7 @@
uint8_t i = 0;
tBTA_GATTC_CIF_MASK* p_cif_mask;
- for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX; i++, p_bg_tck++) {
+ for (i = 0; i < BTM_GetWhiteListSize(); i++, p_bg_tck++) {
if (p_bg_tck->in_use && ((p_bg_tck->remote_bda == remote_bda_ptr) ||
(p_bg_tck->remote_bda.IsEmpty()))) {
p_cif_mask = &p_bg_tck->cif_mask;
@@ -437,7 +437,7 @@
} else /* adding a new device mask */
{
for (i = 0, p_bg_tck = &bta_gattc_cb.bg_track[0];
- i < BTA_GATTC_KNOWN_SR_MAX; i++, p_bg_tck++) {
+ i < BTM_GetWhiteListSize(); i++, p_bg_tck++) {
if (!p_bg_tck->in_use) {
p_bg_tck->in_use = true;
p_bg_tck->remote_bda = remote_bda_ptr;
@@ -468,7 +468,7 @@
uint8_t i = 0;
bool is_bg_conn = false;
- for (i = 0; i < BTA_GATTC_KNOWN_SR_MAX && !is_bg_conn; i++, p_bg_tck++) {
+ for (i = 0; i < BTM_GetWhiteListSize() && !is_bg_conn; i++, p_bg_tck++) {
if (p_bg_tck->in_use && (p_bg_tck->remote_bda == remote_bda ||
p_bg_tck->remote_bda.IsEmpty())) {
if (((p_bg_tck->cif_mask & (1 << (client_if - 1))) != 0) &&
diff --git a/bta/gatt/database.cc b/bta/gatt/database.cc
index 1486b08..58f7056 100644
--- a/bta/gatt/database.cc
+++ b/bta/gatt/database.cc
@@ -127,11 +127,12 @@
for (; it != nv_attr.cend(); ++it) {
const auto& attr = *it;
if (attr.type != PRIMARY_SERVICE && attr.type != SECONDARY_SERVICE) break;
- result.services.emplace_back(
- Service{.handle = attr.handle,
- .end_handle = attr.value.service.end_handle,
- .is_primary = (attr.type == PRIMARY_SERVICE),
- .uuid = attr.value.service.uuid});
+ result.services.emplace_back(Service{
+ .handle = attr.handle,
+ .uuid = attr.value.service.uuid,
+ .is_primary = (attr.type == PRIMARY_SERVICE),
+ .end_handle = attr.value.service.end_handle,
+ });
}
auto current_service_it = result.services.begin();
@@ -168,11 +169,12 @@
.end_handle = attr.value.included_service.end_handle,
});
} else if (attr.type == CHARACTERISTIC) {
- current_service_it->characteristics.emplace_back(
- Characteristic{.declaration_handle = attr.handle,
- .value_handle = attr.value.characteristic.value_handle,
- .properties = attr.value.characteristic.properties,
- .uuid = attr.value.characteristic.uuid});
+ current_service_it->characteristics.emplace_back(Characteristic{
+ .declaration_handle = attr.handle,
+ .uuid = attr.value.characteristic.uuid,
+ .value_handle = attr.value.characteristic.value_handle,
+ .properties = attr.value.characteristic.properties,
+ });
} else {
current_service_it->characteristics.back().descriptors.emplace_back(
diff --git a/bta/gatt/database_builder.cc b/bta/gatt/database_builder.cc
index ed065ab..98c0a27 100644
--- a/bta/gatt/database_builder.cc
+++ b/bta/gatt/database_builder.cc
@@ -32,10 +32,12 @@
// general case optimization - we add services in order
if (database.services.empty() ||
database.services.back().end_handle < handle) {
- database.services.emplace_back(Service{.handle = handle,
- .end_handle = end_handle,
- .is_primary = is_primary,
- .uuid = uuid});
+ database.services.emplace_back(Service{
+ .handle = handle,
+ .uuid = uuid,
+ .is_primary = is_primary,
+ .end_handle = end_handle,
+ });
} else {
auto& vec = database.services;
@@ -45,10 +47,12 @@
[](Service s, uint16_t handle) { return s.end_handle < handle; });
// Insert new service just before it
- vec.emplace(it, Service{.handle = handle,
- .end_handle = end_handle,
- .is_primary = is_primary,
- .uuid = uuid});
+ vec.emplace(it, Service{
+ .handle = handle,
+ .uuid = uuid,
+ .is_primary = is_primary,
+ .end_handle = end_handle,
+ });
}
services_to_discover.insert({handle, end_handle});
@@ -90,11 +94,12 @@
<< loghex(value_handle) << " is after service end_handle="
<< loghex(service->end_handle);
- service->characteristics.emplace_back(
- Characteristic{.declaration_handle = handle,
- .value_handle = value_handle,
- .properties = properties,
- .uuid = uuid});
+ service->characteristics.emplace_back(Characteristic{
+ .declaration_handle = handle,
+ .uuid = uuid,
+ .value_handle = value_handle,
+ .properties = properties,
+ });
return;
}
diff --git a/bta/hd/bta_hd_act.cc b/bta/hd/bta_hd_act.cc
index 0d677ee..a37a051 100644
--- a/bta/hd/bta_hd_act.cc
+++ b/bta/hd/bta_hd_act.cc
@@ -62,7 +62,7 @@
case 0x85: // Report ID
*has_report_id = TRUE;
-
+ [[fallthrough]];
default:
ptr += (item & 0x03);
break;
diff --git a/bta/hearing_aid/hearing_aid.cc b/bta/hearing_aid/hearing_aid.cc
index 465e45e..75116f4 100644
--- a/bta/hearing_aid/hearing_aid.cc
+++ b/bta/hearing_aid/hearing_aid.cc
@@ -232,7 +232,7 @@
uint16_t overwrite_min_ce_len;
public:
- virtual ~HearingAidImpl() = default;
+ ~HearingAidImpl() override = default;
HearingAidImpl(bluetooth::hearing_aid::HearingAidCallbacks* callbacks,
Closure initCb)
@@ -1012,13 +1012,16 @@
}
}
- void OnAudioSuspend() {
+ void OnAudioSuspend(const std::function<void()>& stop_audio_ticks) {
+ CHECK(stop_audio_ticks) << "stop_audio_ticks is empty";
+
if (!audio_running) {
LOG(WARNING) << __func__ << ": Unexpected audio suspend";
} else {
LOG(INFO) << __func__ << ": audio_running=" << audio_running;
}
audio_running = false;
+ stop_audio_ticks();
std::vector<uint8_t> stop({CONTROL_POINT_OP_STOP});
for (auto& device : hearingDevices.devices) {
@@ -1039,23 +1042,33 @@
}
}
- void OnAudioResume() {
+ void OnAudioResume(const std::function<void()>& start_audio_ticks) {
+ CHECK(start_audio_ticks) << "start_audio_ticks is empty";
+
if (audio_running) {
LOG(ERROR) << __func__ << ": Unexpected Audio Resume";
} else {
LOG(INFO) << __func__ << ": audio_running=" << audio_running;
}
- audio_running = true;
+
+ for (auto& device : hearingDevices.devices) {
+ if (!device.accepting_audio) continue;
+ audio_running = true;
+ SendStart(&device);
+ }
+
+ if (!audio_running) {
+ LOG(INFO) << __func__ << ": No device (0/" << GetDeviceCount()
+ << ") ready to start";
+ return;
+ }
// TODO: shall we also reset the encoder ?
encoder_state_release();
encoder_state_init();
seq_counter = 0;
- for (auto& device : hearingDevices.devices) {
- if (!device.accepting_audio) continue;
- SendStart(&device);
- }
+ start_audio_ticks();
}
uint8_t GetOtherSideStreamStatus(HearingDevice* this_side_device) {
@@ -1147,10 +1160,9 @@
}
if (left == nullptr && right == nullptr) {
- HearingAidAudioSource::Stop();
- audio_running = false;
- encoder_state_release();
- current_volume = VOLUME_UNKNOWN;
+ LOG(WARNING) << __func__ << ": No more (0/" << GetDeviceCount()
+ << ") devices ready";
+ DoDisconnectAudioStop();
return;
}
@@ -1463,8 +1475,17 @@
hearingDevices.Remove(address);
- if (connected)
- callbacks->OnConnectionState(ConnectionState::DISCONNECTED, address);
+ if (!connected) {
+ return;
+ }
+
+ callbacks->OnConnectionState(ConnectionState::DISCONNECTED, address);
+ for (const auto& device : hearingDevices.devices) {
+ if (device.accepting_audio) return;
+ }
+ LOG(INFO) << __func__ << ": No more (0/" << GetDeviceCount()
+ << ") devices ready";
+ DoDisconnectAudioStop();
}
void OnGattDisconnected(tGATT_STATUS status, uint16_t conn_id,
@@ -1486,7 +1507,16 @@
DoDisconnectCleanUp(hearingDevice);
+ // Keep this hearing aid in the list, and allow to reconnect back.
+
callbacks->OnConnectionState(ConnectionState::DISCONNECTED, remote_bda);
+
+ for (const auto& device : hearingDevices.devices) {
+ if (device.accepting_audio) return;
+ }
+ LOG(INFO) << __func__ << ": No more (0/" << GetDeviceCount()
+ << ") devices ready";
+ DoDisconnectAudioStop();
}
void DoDisconnectCleanUp(HearingDevice* hearingDevice) {
@@ -1519,6 +1549,13 @@
hearingDevice->command_acked = false;
}
+ void DoDisconnectAudioStop() {
+ HearingAidAudioSource::Stop();
+ audio_running = false;
+ encoder_state_release();
+ current_volume = VOLUME_UNKNOWN;
+ }
+
void SetVolume(int8_t volume) override {
VLOG(2) << __func__ << ": " << +volume;
current_volume = volume;
@@ -1730,14 +1767,11 @@
void OnAudioDataReady(const std::vector<uint8_t>& data) override {
if (instance) instance->OnAudioDataReady(data);
}
- void OnAudioSuspend(std::promise<void> do_suspend_promise) override {
- if (instance) instance->OnAudioSuspend();
- do_suspend_promise.set_value();
+ void OnAudioSuspend(const std::function<void()>& stop_audio_ticks) override {
+ if (instance) instance->OnAudioSuspend(stop_audio_ticks);
}
-
- void OnAudioResume(std::promise<void> do_resume_promise) override {
- if (instance) instance->OnAudioResume();
- do_resume_promise.set_value();
+ void OnAudioResume(const std::function<void()>& start_audio_ticks) override {
+ if (instance) instance->OnAudioResume(start_audio_ticks);
}
};
diff --git a/bta/hearing_aid/hearing_aid_audio_source.cc b/bta/hearing_aid/hearing_aid_audio_source.cc
index 3b92d41..0896e2b 100644
--- a/bta/hearing_aid/hearing_aid_audio_source.cc
+++ b/bta/hearing_aid/hearing_aid_audio_source.cc
@@ -97,12 +97,20 @@
}
void start_audio_ticks() {
+ if (data_interval_ms != HA_INTERVAL_10_MS &&
+ data_interval_ms != HA_INTERVAL_20_MS) {
+ LOG(FATAL) << " Unsupported data interval: " << data_interval_ms;
+ }
+
wakelock_acquire();
- audio_timer.SchedulePeriodic(get_main_thread()->GetWeakPtr(), FROM_HERE, base::Bind(&send_audio_data),
- base::TimeDelta::FromMilliseconds(data_interval_ms));
+ audio_timer.SchedulePeriodic(
+ get_main_thread()->GetWeakPtr(), FROM_HERE, base::Bind(&send_audio_data),
+ base::TimeDelta::FromMilliseconds(data_interval_ms));
+ LOG(INFO) << __func__ << ": running with data interval: " << data_interval_ms;
}
void stop_audio_ticks() {
+ LOG(INFO) << __func__ << ": stopped";
audio_timer.CancelAndWait();
wakelock_release();
}
@@ -121,17 +129,12 @@
UIPC_Ioctl(*uipc_hearing_aid, UIPC_CH_ID_AV_AUDIO, UIPC_SET_READ_POLL_TMO,
reinterpret_cast<void*>(0));
- if (data_interval_ms != HA_INTERVAL_10_MS &&
- data_interval_ms != HA_INTERVAL_20_MS) {
- LOG(FATAL) << " Unsupported data interval: " << data_interval_ms;
- }
-
- start_audio_ticks();
+ do_in_main_thread(FROM_HERE, base::BindOnce(start_audio_ticks));
break;
case UIPC_CLOSE_EVT:
LOG(INFO) << __func__ << ": UIPC_CLOSE_EVT";
hearing_aid_send_ack(HEARING_AID_CTRL_ACK_SUCCESS);
- stop_audio_ticks();
+ do_in_main_thread(FROM_HERE, base::BindOnce(stop_audio_ticks));
break;
default:
LOG(ERROR) << "Hearing Aid audio data event not recognized:" << event;
@@ -306,65 +309,52 @@
}
bool hearing_aid_on_resume_req(bool start_media_task) {
- // hearing_aid_recv_ctrl_data(HEARING_AID_CTRL_CMD_START)
- if (localAudioReceiver != nullptr) {
- // Call OnAudioResume and block till it returns.
- std::promise<void> do_resume_promise;
- std::future<void> do_resume_future = do_resume_promise.get_future();
- bt_status_t status = do_in_main_thread(
- FROM_HERE, base::BindOnce(&HearingAidAudioReceiver::OnAudioResume,
- base::Unretained(localAudioReceiver),
- std::move(do_resume_promise)));
- if (status == BT_STATUS_SUCCESS) {
- do_resume_future.wait();
- } else {
- LOG(ERROR) << __func__
- << ": HEARING_AID_CTRL_CMD_START: do_in_main_thread err="
- << status;
- return false;
- }
- } else {
+ if (localAudioReceiver == nullptr) {
LOG(ERROR) << __func__
<< ": HEARING_AID_CTRL_CMD_START: audio receiver not started";
return false;
}
-
- // hearing_aid_data_cb(UIPC_OPEN_EVT): start_media_task
+ bt_status_t status;
if (start_media_task) {
- if (data_interval_ms != HA_INTERVAL_10_MS &&
- data_interval_ms != HA_INTERVAL_20_MS) {
- LOG(FATAL) << " Unsupported data interval: " << data_interval_ms;
- data_interval_ms = HA_INTERVAL_10_MS;
- }
- start_audio_ticks();
+ status = do_in_main_thread(
+ FROM_HERE, base::BindOnce(&HearingAidAudioReceiver::OnAudioResume,
+ base::Unretained(localAudioReceiver),
+ start_audio_ticks));
+ } else {
+ auto start_dummy_ticks = []() {
+ LOG(INFO) << "start_audio_ticks: waiting for data path opened";
+ };
+ status = do_in_main_thread(
+ FROM_HERE, base::BindOnce(&HearingAidAudioReceiver::OnAudioResume,
+ base::Unretained(localAudioReceiver),
+ start_dummy_ticks));
+ }
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << __func__
+ << ": HEARING_AID_CTRL_CMD_START: do_in_main_thread err="
+ << status;
+ return false;
}
return true;
}
bool hearing_aid_on_suspend_req() {
- // hearing_aid_recv_ctrl_data(HEARING_AID_CTRL_CMD_SUSPEND): stop_media_task
- stop_audio_ticks();
- if (localAudioReceiver != nullptr) {
- // Call OnAudioSuspend and block till it returns.
- std::promise<void> do_suspend_promise;
- std::future<void> do_suspend_future = do_suspend_promise.get_future();
- bt_status_t status = do_in_main_thread(
- FROM_HERE, base::BindOnce(&HearingAidAudioReceiver::OnAudioSuspend,
- base::Unretained(localAudioReceiver),
- std::move(do_suspend_promise)));
- if (status == BT_STATUS_SUCCESS) {
- do_suspend_future.wait();
- return true;
- } else {
- LOG(ERROR) << __func__
- << ": HEARING_AID_CTRL_CMD_SUSPEND: do_in_main_thread err="
- << status;
- }
- } else {
+ if (localAudioReceiver == nullptr) {
LOG(ERROR) << __func__
<< ": HEARING_AID_CTRL_CMD_SUSPEND: audio receiver not started";
+ return false;
}
- return false;
+ bt_status_t status = do_in_main_thread(
+ FROM_HERE,
+ base::BindOnce(&HearingAidAudioReceiver::OnAudioSuspend,
+ base::Unretained(localAudioReceiver), stop_audio_ticks));
+ if (status != BT_STATUS_SUCCESS) {
+ LOG(ERROR) << __func__
+ << ": HEARING_AID_CTRL_CMD_SUSPEND: do_in_main_thread err="
+ << status;
+ return false;
+ }
+ return true;
}
} // namespace
diff --git a/bta/hf_client/bta_hf_client_at.cc b/bta/hf_client/bta_hf_client_at.cc
index 5bcc68e..6e4fe26 100644
--- a/bta/hf_client/bta_hf_client_at.cc
+++ b/bta/hf_client/bta_hf_client_at.cc
@@ -724,9 +724,7 @@
******************************************************************************/
void bta_hf_client_cnum(tBTA_HF_CLIENT_CB* client_cb, char* number,
uint16_t service) {
- tBTA_HF_CLIENT evt;
-
- memset(&evt, 0, sizeof(evt));
+ tBTA_HF_CLIENT evt = {};
evt.cnum.service = service;
strlcpy(evt.cnum.number, number, BTA_HF_CLIENT_NUMBER_LEN + 1);
@@ -736,6 +734,18 @@
bta_hf_client_app_callback(BTA_HF_CLIENT_CNUM_EVT, &evt);
}
+void bta_hf_client_unknown_response(tBTA_HF_CLIENT_CB* client_cb,
+ const char* evt_buffer) {
+ tBTA_HF_CLIENT evt = {};
+
+ strlcpy(evt.unknown.event_string, evt_buffer,
+ BTA_HF_CLIENT_UNKOWN_EVENT_LEN + 1);
+ evt.unknown.event_string[BTA_HF_CLIENT_UNKOWN_EVENT_LEN] = '\0';
+
+ evt.unknown.bd_addr = client_cb->peer_addr;
+ bta_hf_client_app_callback(BTA_HF_CLIENT_UNKNOWN_EVT, &evt);
+}
+
/*******************************************************************************
*
* Function bta_hf_client_binp
@@ -1436,6 +1446,36 @@
return buffer;
}
+static char* bta_hf_client_process_unknown(tBTA_HF_CLIENT_CB* client_cb,
+ char* buffer) {
+ char* start = strstr(buffer, "\r\n");
+ if (start == NULL) {
+ return NULL;
+ }
+ start += sizeof("\r\n") - 1;
+
+ char* end = strstr(start, "\r\n");
+ if (end == NULL) {
+ return NULL;
+ }
+
+ int evt_size = end - start + 1;
+
+ char tmp_buf[BTA_HF_CLIENT_UNKOWN_EVENT_LEN];
+ if (evt_size < BTA_HF_CLIENT_UNKOWN_EVENT_LEN) {
+ strlcpy(tmp_buf, start, evt_size);
+ bta_hf_client_unknown_response(client_cb, tmp_buf);
+ AT_CHECK_RN(end);
+ } else {
+ APPL_TRACE_ERROR("%s: exceed event buffer size. (%d, %d)", __func__,
+ evt_size, BTA_HF_CLIENT_UNKOWN_EVENT_LEN);
+ }
+
+ APPL_TRACE_DEBUG("%s: %s", __func__, buffer);
+
+ return end;
+}
+
/******************************************************************************
* SUPPORTED EVENT MESSAGES
******************************************************************************/
@@ -1461,7 +1501,7 @@
bta_hf_client_parse_cnum, bta_hf_client_parse_btrh,
bta_hf_client_parse_busy, bta_hf_client_parse_delayed,
bta_hf_client_parse_no_carrier, bta_hf_client_parse_no_answer,
- bta_hf_client_parse_blacklisted, bta_hf_client_skip_unknown};
+ bta_hf_client_parse_blacklisted, bta_hf_client_process_unknown};
/* calculate supported event list length */
static const uint16_t bta_hf_client_parser_cb_count =
@@ -1996,6 +2036,25 @@
bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_BIA, buf, at_len);
}
+void bta_hf_client_send_at_vendor_specific_cmd(tBTA_HF_CLIENT_CB* client_cb,
+ const char* str) {
+ char buf[BTA_HF_CLIENT_AT_MAX_LEN];
+
+ APPL_TRACE_DEBUG("%s", __func__);
+
+ int at_len = snprintf(buf, sizeof(buf), "AT%s", str);
+
+ if (at_len < 1) {
+ APPL_TRACE_ERROR("%s: AT command Framing error", __func__);
+ return;
+ }
+
+ buf[at_len - 1] = '\r';
+
+ bta_hf_client_send_at(client_cb, BTA_HF_CLIENT_AT_VENDOR_SPECIFIC, buf,
+ at_len);
+}
+
void bta_hf_client_at_init(tBTA_HF_CLIENT_CB* client_cb) {
alarm_free(client_cb->at_cb.resp_timer);
alarm_free(client_cb->at_cb.hold_timer);
@@ -2087,6 +2146,9 @@
case BTA_HF_CLIENT_AT_CMD_NREC:
bta_hf_client_send_at_nrec(client_cb);
break;
+ case BTA_HF_CLIENT_AT_CMD_VENDOR_SPECIFIC_CMD:
+ bta_hf_client_send_at_vendor_specific_cmd(client_cb, p_val->str);
+ break;
default:
APPL_TRACE_ERROR("Default case");
snprintf(buf, BTA_HF_CLIENT_AT_MAX_LEN,
diff --git a/bta/hf_client/bta_hf_client_int.h b/bta/hf_client/bta_hf_client_int.h
index 15ceec2..99967f7 100644
--- a/bta/hf_client/bta_hf_client_int.h
+++ b/bta/hf_client/bta_hf_client_int.h
@@ -97,6 +97,7 @@
BTA_HF_CLIENT_AT_CNUM,
BTA_HF_CLIENT_AT_NREC,
BTA_HF_CLIENT_AT_BINP,
+ BTA_HF_CLIENT_AT_VENDOR_SPECIFIC,
};
/*****************************************************************************
diff --git a/bta/hf_client/bta_hf_client_sco.cc b/bta/hf_client/bta_hf_client_sco.cc
index 50820bd..faf970d 100644
--- a/bta/hf_client/bta_hf_client_sco.cc
+++ b/bta/hf_client/bta_hf_client_sco.cc
@@ -305,6 +305,8 @@
case BTA_HF_CLIENT_SCO_LISTEN_E:
/* create SCO listen connection */
bta_hf_client_sco_create(client_cb, false);
+ /* TODO(b/143901894): Is this correct? */
+ [[fallthrough]];
case BTA_HF_CLIENT_SCO_OPEN_E:
/* remove listening connection */
diff --git a/bta/include/bta_hearing_aid_api.h b/bta/include/bta_hearing_aid_api.h
index 9026262..6c4954b 100644
--- a/bta/include/bta_hearing_aid_api.h
+++ b/bta/include/bta_hearing_aid_api.h
@@ -21,7 +21,6 @@
#include <base/callback_forward.h>
#include <hardware/bt_hearing_aid.h>
#include <deque>
-#include <future>
#include <vector>
constexpr uint16_t HEARINGAID_MAX_NUM_UUIDS = 1;
@@ -39,8 +38,22 @@
public:
virtual ~HearingAidAudioReceiver() = default;
virtual void OnAudioDataReady(const std::vector<uint8_t>& data) = 0;
- virtual void OnAudioSuspend(std::promise<void> do_suspend_promise) = 0;
- virtual void OnAudioResume(std::promise<void> do_resume_promise) = 0;
+
+ // API to stop our feeding timer, and notify hearing aid devices that the
+ // streaming would stop, too.
+ //
+ // @param stop_audio_ticks a callable function calls out to stop the media
+ // timer for reading data.
+ virtual void OnAudioSuspend(
+ const std::function<void()>& stop_audio_ticks) = 0;
+
+ // To notify hearing aid devices to be ready for streaming, and start the
+ // media timer to feed the audio data.
+ //
+ // @param start_audio_ticks a callable function calls out to start a periodic
+ // timer for feeding data from the audio HAL.
+ virtual void OnAudioResume(
+ const std::function<void()>& start_audio_ticks) = 0;
};
// Number of rssi reads to attempt when requested
diff --git a/bta/include/bta_hf_client_api.h b/bta/include/bta_hf_client_api.h
index 69dc109..897555d 100644
--- a/bta/include/bta_hf_client_api.h
+++ b/bta/include/bta_hf_client_api.h
@@ -119,6 +119,9 @@
*/
#define BTA_HF_CLIENT_BINP_EVT 20 /* binp number event */
#define BTA_HF_CLIENT_RING_INDICATION 21 /* HF Client ring indication */
+
+#define BTA_HF_CLIENT_UNKNOWN_EVT 22 /* Unknown or vendor specific Event */
+
#define BTA_HF_CLIENT_DISABLE_EVT 30 /* HF Client disabled */
typedef uint8_t tBTA_HF_CLIENT_EVT;
@@ -159,6 +162,7 @@
#define BTA_HF_CLIENT_AT_CMD_BINP 13
#define BTA_HF_CLIENT_AT_CMD_BLDN 14
#define BTA_HF_CLIENT_AT_CMD_NREC 15
+#define BTA_HF_CLIENT_AT_CMD_VENDOR_SPECIFIC_CMD 16
typedef uint8_t tBTA_HF_CLIENT_AT_CMD_TYPE;
@@ -234,6 +238,13 @@
uint16_t value;
} tBTA_HF_CLIENT_VAL;
+/* data associated with BTA_HF_CLIENT_UNKNOWN_EVT event */
+#define BTA_HF_CLIENT_UNKOWN_EVENT_LEN 32
+typedef struct {
+ RawAddress bd_addr;
+ char event_string[BTA_HF_CLIENT_UNKOWN_EVENT_LEN + 1];
+} tBTA_HF_CLIENT_UNKNOWN;
+
/* union of data associated with AG callback */
typedef union {
// Common BD ADDR field for all tyepdefs
@@ -248,6 +259,7 @@
tBTA_HF_CLIENT_AT_RESULT result;
tBTA_HF_CLIENT_CLCC clcc;
tBTA_HF_CLIENT_CNUM cnum;
+ tBTA_HF_CLIENT_UNKNOWN unknown;
} tBTA_HF_CLIENT;
typedef uint32_t tBTA_HF_CLIENT_FEAT;
diff --git a/bta/jv/bta_jv_act.cc b/bta/jv/bta_jv_act.cc
index 462ee9d..5cd8041 100644
--- a/bta/jv/bta_jv_act.cc
+++ b/bta/jv/bta_jv_act.cc
@@ -1885,16 +1885,16 @@
static tL2CAP_FIXED_CHNL_REG fcr = {
.pL2CA_FixedConn_Cb = fcchan_conn_chng_cbk,
.pL2CA_FixedData_Cb = fcchan_data_cbk,
- .default_idle_tout = 0xffff,
.fixed_chnl_opts =
{
.mode = L2CAP_FCR_BASIC_MODE,
+ .tx_win_sz = 1,
.max_transmit = 0xFF,
.rtrans_tout = 2000,
.mon_tout = 12000,
.mps = 670,
- .tx_win_sz = 1,
},
+ .default_idle_tout = 0xffff,
};
while (t && t->chan != chan) t = t->next;
diff --git a/btif/Android.bp b/btif/Android.bp
index f33d174..8e55de6 100644
--- a/btif/Android.bp
+++ b/btif/Android.bp
@@ -24,8 +24,8 @@
"system/bt/utils/include",
"system/bt/include",
"system/libhwbinder/include",
- "system/security/keystore/include",
- "hardware/interfaces/keymaster/4.0/support/include",
+ //"system/security/keystore/include",
+ //"hardware/interfaces/keymaster/4.0/support/include",
]
// libbtif static library for target
@@ -73,7 +73,7 @@
"src/btif_hf_client.cc",
"src/btif_hh.cc",
"src/btif_hd.cc",
- "src/btif_keystore.cc",
+ //"src/btif_keystore.cc",
"src/btif_mce.cc",
"src/btif_pan.cc",
"src/btif_profile_queue.cc",
@@ -92,6 +92,9 @@
"src/btif_util.cc",
"src/stack_manager.cc",
],
+ header_libs: [
+ "libmedia_headers",
+ ],
shared_libs: [
"libaudioclient",
"libcutils",
@@ -102,16 +105,14 @@
"android.hardware.bluetooth.a2dp@1.0",
"android.hardware.bluetooth.audio@2.0",
"libhidlbase",
- "libhidltransport",
- "libhwbinder",
"libutils",
"libcrypto",
- "android.hardware.keymaster@4.0",
- "android.hardware.keymaster@3.0",
- "libkeymaster4support",
- "libkeystore_aidl",
- "libkeystore_binder",
- "libkeystore_parcelables",
+ //"android.hardware.keymaster@4.0",
+ //"android.hardware.keymaster@3.0",
+ //"libkeymaster4support",
+ //"libkeystore_aidl",
+ //"libkeystore_binder",
+ //"libkeystore_parcelables",
],
whole_static_libs: [
"avrcp-target-service",
@@ -121,7 +122,6 @@
],
cflags: [
"-DBUILDCFG",
- "-Wno-implicit-fallthrough",
],
}
@@ -135,7 +135,7 @@
include_dirs: btifCommonIncludes,
srcs: [
"test/btif_storage_test.cc",
- "test/btif_keystore_test.cc"
+ //"test/btif_keystore_test.cc"
],
header_libs: ["libbluetooth_headers"],
shared_libs: [
@@ -144,20 +144,19 @@
"android.hardware.bluetooth.audio@2.0",
"libfmq",
"libhidlbase",
- "libhidltransport",
"liblog",
"libprotobuf-cpp-lite",
"libcutils",
"libprocessgroup",
"libutils",
"libcrypto",
- "android.hardware.keymaster@4.0",
- "android.hardware.keymaster@3.0",
- "libkeymaster4support",
- "libkeystore_aidl",
- "libkeystore_binder",
- "libkeystore_parcelables",
- "libbinder",
+ //"android.hardware.keymaster@4.0",
+ //"android.hardware.keymaster@3.0",
+ //"libkeymaster4support",
+ //"libkeystore_aidl",
+ //"libkeystore_binder",
+ //"libkeystore_parcelables",
+ //"libbinder",
],
static_libs: [
"libbt-bta",
@@ -194,8 +193,8 @@
test_suites: ["device-tests"],
include_dirs: btifCommonIncludes,
srcs: [
- "src/btif_profile_queue.cc",
- "test/btif_profile_queue_test.cc"
+ "src/btif_profile_queue.cc",
+ "test/btif_profile_queue_test.cc",
],
header_libs: ["libbluetooth_headers"],
shared_libs: [
diff --git a/btif/co/bta_av_co.cc b/btif/co/bta_av_co.cc
index 9f17d4a..f3d39e2 100644
--- a/btif/co/bta_av_co.cc
+++ b/btif/co/bta_av_co.cc
@@ -1005,6 +1005,11 @@
memcpy(p_codec_info, p_peer->codec_config, AVDT_CODEC_SIZE);
}
+ // report this peer selectable codecs after retrieved all its capabilities.
+ LOG(INFO) << __func__ << ": retrieved " << +p_peer->num_rx_sinks
+ << " capabilities from peer " << p_peer->addr;
+ ReportSourceCodecState(p_peer);
+
return A2DP_SUCCESS;
}
@@ -1385,12 +1390,24 @@
__func__, bta_av_handle, peer_address.ToString().c_str());
return;
}
+
+ if (p_peer->mtu == mtu) return;
+
p_peer->mtu = mtu;
+ if (active_peer_ == p_peer) {
+ LOG(INFO) << __func__ << ": update the codec encoder with peer "
+ << peer_address << " bta_av_handle: " << loghex(bta_av_handle)
+ << ", new MTU: " << mtu;
+ // Send a request with NONE config values to update only the MTU.
+ SetCodecAudioConfig(
+ {.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE,
+ .bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE,
+ .channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE});
+ }
}
bool BtaAvCo::SetActivePeer(const RawAddress& peer_address) {
- APPL_TRACE_DEBUG("%s: peer_address=%s", __func__,
- peer_address.ToString().c_str());
+ VLOG(1) << __func__ << ": peer_address=" << peer_address;
std::lock_guard<std::recursive_mutex> lock(codec_lock_);
@@ -1409,8 +1426,8 @@
active_peer_ = p_peer;
memcpy(codec_config_, active_peer_->codec_config, AVDT_CODEC_SIZE);
- APPL_TRACE_DEBUG("%s: codec = %s", __func__,
- A2DP_CodecInfoString(codec_config_).c_str());
+ LOG(INFO) << __func__ << ": codec = " << A2DP_CodecInfoString(codec_config_);
+ // report the selected codec configuration of this new active peer.
ReportSourceCodecState(active_peer_);
return true;
}
@@ -1463,14 +1480,22 @@
bool config_updated = false;
bool success = true;
- APPL_TRACE_DEBUG("%s: peer_address=%s codec_user_config=%s", __func__,
- peer_address.ToString().c_str(),
- codec_user_config.ToString().c_str());
+ VLOG(1) << __func__ << ": peer_address=" << peer_address
+ << " codec_user_config={" << codec_user_config.ToString() << "}";
BtaAvCoPeer* p_peer = FindPeer(peer_address);
if (p_peer == nullptr) {
- APPL_TRACE_ERROR("%s: cannot find peer %s to configure", __func__,
- peer_address.ToString().c_str());
+ LOG(ERROR) << __func__ << ": cannot find peer " << peer_address
+ << " to configure";
+ success = false;
+ goto done;
+ }
+
+ // Don't call BTA_AvReconfig() prior to retrieving all peer's capabilities
+ if ((p_peer->num_rx_sinks != p_peer->num_sinks) &&
+ (p_peer->num_sup_sinks != BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks))) {
+ LOG(WARNING) << __func__ << ": peer " << p_peer->addr
+ << " : not all peer's capabilities have been retrieved";
success = false;
goto done;
}
@@ -1483,10 +1508,9 @@
p_sink = p_peer->p_sink;
}
if (p_sink == nullptr) {
- APPL_TRACE_ERROR(
- "%s: peer %s : cannot find peer SEP to configure for codec type %d",
- __func__, p_peer->addr.ToString().c_str(),
- codec_user_config.codec_type);
+ LOG(ERROR) << __func__ << ": peer " << p_peer->addr
+ << " : cannot find peer SEP to configure for codec type "
+ << codec_user_config.codec_type;
success = false;
goto done;
}
@@ -1509,35 +1533,30 @@
p_sink = SelectSourceCodec(p_peer);
if (p_sink == nullptr) {
- APPL_TRACE_ERROR("%s: peer %s : cannot set up codec for the peer SINK",
- __func__, p_peer->addr.ToString().c_str());
- success = false;
- goto done;
- }
- // Don't call BTA_AvReconfig() prior to retrieving all peer's capabilities
- if ((p_peer->num_rx_sinks != p_peer->num_sinks) &&
- (p_peer->num_sup_sinks != BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks))) {
- APPL_TRACE_WARNING(
- "%s: peer %s : not all peer's capabilities have been retrieved",
- __func__, p_peer->addr.ToString().c_str());
+ LOG(ERROR) << __func__ << ": peer " << p_peer->addr
+ << " : cannot set up codec for the peer SINK";
success = false;
goto done;
}
p_peer->acceptor = false;
- APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(0x%x)", __func__,
- p_peer->BtaAvHandle());
+ VLOG(1) << __func__ << ": call BTA_AvReconfig("
+ << loghex(p_peer->BtaAvHandle()) << ")";
BTA_AvReconfig(p_peer->BtaAvHandle(), true, p_sink->sep_info_idx,
p_peer->codec_config, num_protect, bta_av_co_cp_scmst);
}
done:
- // NOTE: We unconditionally send the upcall even if there is no change
- // or the user config failed. Thus, the caller would always know whether the
- // request succeeded or failed.
+ // We send the upcall if there is no change or the user config failed for
+ // current active peer, so the caller would know it failed. If there is no
+ // error, the new selected codec configuration would be sent after we are
+ // ready to start a new session with the audio HAL.
+ // For none active peer, we unconditionally send the upcall, so the caller
+ // would always know the result.
// NOTE: Currently, the input is restarted by sending an upcall
// and informing the Media Framework about the change.
- if (p_peer != nullptr) {
+ if (p_peer != nullptr &&
+ (!restart_output || !success || p_peer != active_peer_)) {
return ReportSourceCodecState(p_peer);
}
@@ -1550,21 +1569,29 @@
bool restart_output = false;
bool config_updated = false;
- APPL_TRACE_DEBUG("%s: codec_audio_config: %s", __func__,
- codec_audio_config.ToString().c_str());
+ VLOG(1) << __func__
+ << ": codec_audio_config: " << codec_audio_config.ToString();
// Find the peer that is currently open
BtaAvCoPeer* p_peer = active_peer_;
if (p_peer == nullptr) {
- APPL_TRACE_ERROR("%s: no active peer to configure", __func__);
+ LOG(ERROR) << __func__ << ": no active peer to configure";
+ return false;
+ }
+
+ // Don't call BTA_AvReconfig() prior to retrieving all peer's capabilities
+ if ((p_peer->num_rx_sinks != p_peer->num_sinks) &&
+ (p_peer->num_sup_sinks != BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks))) {
+ LOG(WARNING) << __func__ << ": peer " << p_peer->addr
+ << " : not all peer's capabilities have been retrieved";
return false;
}
// Use the current sink codec
const BtaAvCoSep* p_sink = p_peer->p_sink;
if (p_sink == nullptr) {
- APPL_TRACE_ERROR("%s: peer %s : cannot find peer SEP to configure",
- __func__, p_peer->addr.ToString().c_str());
+ LOG(ERROR) << __func__ << ": peer " << p_peer->addr
+ << " : cannot find peer SEP to configure";
return false;
}
@@ -1585,24 +1612,16 @@
SaveNewCodecConfig(p_peer, result_codec_config, p_sink->num_protect,
p_sink->protect_info);
- // Don't call BTA_AvReconfig() prior to retrieving all peer's capabilities
- if ((p_peer->num_rx_sinks != p_peer->num_sinks) &&
- (p_peer->num_sup_sinks != BTA_AV_CO_NUM_ELEMENTS(p_peer->sinks))) {
- APPL_TRACE_WARNING(
- "%s: peer %s : not all peer's capabilities have been retrieved",
- __func__, p_peer->addr.ToString().c_str());
- } else {
- p_peer->acceptor = false;
- APPL_TRACE_DEBUG("%s: call BTA_AvReconfig(0x%x)", __func__,
- p_peer->BtaAvHandle());
- BTA_AvReconfig(p_peer->BtaAvHandle(), true, p_sink->sep_info_idx,
- p_peer->codec_config, num_protect, bta_av_co_cp_scmst);
- }
+ p_peer->acceptor = false;
+ VLOG(1) << __func__ << ": call BTA_AvReconfig("
+ << loghex(p_peer->BtaAvHandle()) << ")";
+ BTA_AvReconfig(p_peer->BtaAvHandle(), true, p_sink->sep_info_idx,
+ p_peer->codec_config, num_protect, bta_av_co_cp_scmst);
}
if (config_updated) {
// NOTE: Currently, the input is restarted by sending an upcall
- // and informing the Media Framework about the change.
+ // and informing the Media Framework about the change of selected codec.
return ReportSourceCodecState(p_peer);
}
@@ -1614,22 +1633,19 @@
std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities;
std::vector<btav_a2dp_codec_config_t> codecs_selectable_capabilities;
- APPL_TRACE_DEBUG("%s: peer_address=%s", __func__,
- p_peer->addr.ToString().c_str());
+ VLOG(1) << __func__ << ": peer_address=" << p_peer->addr;
A2dpCodecs* codecs = p_peer->GetCodecs();
CHECK(codecs != nullptr);
if (!codecs->getCodecConfigAndCapabilities(&codec_config,
&codecs_local_capabilities,
&codecs_selectable_capabilities)) {
- APPL_TRACE_WARNING(
- "%s: Peer %s : error reporting audio source codec state: "
- "cannot get codec config and capabilities",
- __func__, p_peer->addr.ToString().c_str());
+ LOG(WARNING) << __func__ << ": Peer " << p_peer->addr
+ << " : error reporting audio source codec state: cannot get "
+ "codec config and capabilities";
return false;
}
- APPL_TRACE_DEBUG("%s: peer %s codec_config=%s", __func__,
- p_peer->addr.ToString().c_str(),
- codec_config.ToString().c_str());
+ LOG(INFO) << __func__ << ": peer " << p_peer->addr << " codec_config={"
+ << codec_config.ToString() << "}";
btif_av_report_source_codec_state(p_peer->addr, codec_config,
codecs_local_capabilities,
codecs_selectable_capabilities);
@@ -1736,19 +1752,14 @@
// Select the codec
for (const auto& iter : p_peer->GetCodecs()->orderedSourceCodecs()) {
- APPL_TRACE_DEBUG("%s: trying codec %s", __func__, iter->name().c_str());
+ VLOG(1) << __func__ << ": trying codec " << iter->name();
p_sink = AttemptSourceCodecSelection(*iter, p_peer);
if (p_sink != nullptr) {
- APPL_TRACE_DEBUG("%s: selected codec %s", __func__, iter->name().c_str());
+ VLOG(1) << __func__ << ": selected codec " << iter->name();
break;
}
- APPL_TRACE_DEBUG("%s: cannot use codec %s", __func__, iter->name().c_str());
+ VLOG(1) << __func__ << ": cannot use codec " << iter->name();
}
-
- // NOTE: Unconditionally dispatch the event to make sure a callback with
- // the most recent codec info is generated.
- ReportSourceCodecState(p_peer);
-
return p_sink;
}
@@ -1988,10 +1999,8 @@
bool restart_output = false;
bool config_updated = false;
- APPL_TRACE_DEBUG("%s: peer_address=%s", __func__,
- p_peer->addr.ToString().c_str());
- APPL_TRACE_DEBUG("%s: codec: %s", __func__,
- A2DP_CodecInfoString(p_ota_codec_config).c_str());
+ LOG(INFO) << __func__ << ": peer_address=" << p_peer->addr
+ << ", codec: " << A2DP_CodecInfoString(p_ota_codec_config);
*p_restart_output = false;
@@ -2002,8 +2011,8 @@
// There are no peer SEPs if we didn't do the discovery procedure yet.
// We have all the information we need from the peer, so we can
// proceed with the OTA codec configuration.
- APPL_TRACE_ERROR("%s: peer %s : cannot find peer SEP to configure",
- __func__, p_peer->addr.ToString().c_str());
+ LOG(ERROR) << __func__ << ": peer " << p_peer->addr
+ << " : cannot find peer SEP to configure";
return false;
}
@@ -2012,15 +2021,14 @@
if (!p_peer->GetCodecs()->setCodecOtaConfig(
p_ota_codec_config, &peer_params, result_codec_config, &restart_input,
&restart_output, &config_updated)) {
- APPL_TRACE_ERROR("%s: peer %s : cannot set OTA config", __func__,
- p_peer->addr.ToString().c_str());
+ LOG(ERROR) << __func__ << ": peer " << p_peer->addr
+ << " : cannot set OTA config";
return false;
}
if (restart_output) {
- APPL_TRACE_DEBUG("%s: restart output", __func__);
- APPL_TRACE_DEBUG("%s: codec: %s", __func__,
- A2DP_CodecInfoString(result_codec_config).c_str());
+ VLOG(1) << __func__ << ": restart output for codec: "
+ << A2DP_CodecInfoString(result_codec_config);
*p_restart_output = true;
p_peer->p_sink = p_sink;
@@ -2030,7 +2038,7 @@
if (restart_input || config_updated) {
// NOTE: Currently, the input is restarted by sending an upcall
- // and informing the Media Framework about the change.
+ // and informing the Media Framework about the change of selected codec.
ReportSourceCodecState(p_peer);
}
diff --git a/btif/co/bta_hh_co.cc b/btif/co/bta_hh_co.cc
index 5a7cad8..cec3f69 100644
--- a/btif/co/bta_hh_co.cc
+++ b/btif/co/bta_hh_co.cc
@@ -163,7 +163,29 @@
APPL_TRACE_ERROR("%s: UHID_FEATURE: Invalid report type = %d", __func__,
ev.u.feature.rtype);
break;
+ case UHID_SET_REPORT:
+ if (ret < (ssize_t)(sizeof(ev.type) + sizeof(ev.u.set_report))) {
+ APPL_TRACE_ERROR("%s: Invalid size read from uhid-dev: %zd < %zu",
+ __func__, ret, sizeof(ev.type) + sizeof(ev.u.set_report));
+ return -EFAULT;
+ }
+ APPL_TRACE_DEBUG("UHID_SET_REPORT: Report type = %d, report_size = %d"
+ , ev.u.set_report.rtype, ev.u.set_report.size);
+
+ if (ev.u.set_report.rtype == UHID_FEATURE_REPORT)
+ btif_hh_setreport(p_dev, BTHH_FEATURE_REPORT,
+ ev.u.set_report.size, ev.u.set_report.data);
+ else if (ev.u.set_report.rtype == UHID_OUTPUT_REPORT)
+ btif_hh_setreport(p_dev, BTHH_OUTPUT_REPORT,
+ ev.u.set_report.size, ev.u.set_report.data);
+ else if(ev.u.set_report.rtype == UHID_INPUT_REPORT)
+ btif_hh_setreport(p_dev, BTHH_INPUT_REPORT,
+ ev.u.set_report.size, ev.u.set_report.data);
+ else
+ APPL_TRACE_ERROR("%s:UHID_SET_REPORT: Invalid Report type = %d"
+ , __func__, ev.u.set_report.rtype);
+ break;
default:
APPL_TRACE_DEBUG("Invalid event from uhid-dev: %u\n", ev.type);
}
@@ -571,7 +593,7 @@
}
// Send the HID report to the kernel.
- if (p_dev->fd >= 0 && p_dev->get_rpt_snt--) {
+ if (p_dev->fd >= 0 && p_dev->get_rpt_snt > 0 && p_dev->get_rpt_snt--) {
uint32_t* get_rpt_id =
(uint32_t*)fixed_queue_dequeue(p_dev->get_rpt_id_queue);
memset(&ev, 0, sizeof(ev));
diff --git a/btif/src/bluetooth.cc b/btif/src/bluetooth.cc
index 9dd4908..ae13843 100644
--- a/btif/src/bluetooth.cc
+++ b/btif/src/bluetooth.cc
@@ -65,6 +65,7 @@
#include "common/address_obfuscator.h"
#include "common/metrics.h"
#include "device/include/interop.h"
+#include "main/shim/shim.h"
#include "osi/include/alarm.h"
#include "osi/include/allocation_tracker.h"
#include "osi/include/log.h"
@@ -138,6 +139,12 @@
LOG_INFO(LOG_TAG, "%s: start restricted = %d ; single user = %d", __func__,
start_restricted, is_single_user_mode);
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ LOG_INFO(LOG_TAG, "%s Enable Gd bluetooth functionality", __func__);
+ } else {
+ LOG_INFO(LOG_TAG, "%s Preserving legacy bluetooth functionality", __func__);
+ }
+
if (interface_ready()) return BT_STATUS_DONE;
#ifdef BLUEDROID_DEBUG
diff --git a/btif/src/btif_a2dp_audio_interface.cc b/btif/src/btif_a2dp_audio_interface.cc
index 7e46818..026baa1 100644
--- a/btif/src/btif_a2dp_audio_interface.cc
+++ b/btif/src/btif_a2dp_audio_interface.cc
@@ -137,15 +137,15 @@
class BluetoothAudioHost : public IBluetoothAudioHost {
public:
- Return<void> startStream() {
+ Return<void> startStream() override {
btif_a2dp_audio_send_start_req();
return Void();
}
- Return<void> suspendStream() {
+ Return<void> suspendStream() override {
btif_a2dp_audio_send_suspend_req();
return Void();
}
- Return<void> stopStream() {
+ Return<void> stopStream() override {
btif_a2dp_audio_send_stop_req();
return Void();
}
@@ -160,9 +160,9 @@
class BluetoothAudioDeathRecipient : public hidl_death_recipient {
public:
- virtual void serviceDied(
+ void serviceDied(
uint64_t /*cookie*/,
- const wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
+ const wp<::android::hidl::base::V1_0::IBase>& /*who*/) override {
LOG_ERROR(LOG_TAG, "%s", __func__);
// Restart the session on the correct thread
do_in_main_thread(FROM_HERE,
diff --git a/btif/src/btif_a2dp_sink.cc b/btif/src/btif_a2dp_sink.cc
index bb1bc49..aa75d21 100644
--- a/btif/src/btif_a2dp_sink.cc
+++ b/btif/src/btif_a2dp_sink.cc
@@ -667,7 +667,6 @@
LOG_INFO(LOG_TAG, "%s: state=%d", __func__, state);
LockGuard lock(g_mutex);
- if (!btif_av_is_connected()) return;
APPL_TRACE_DEBUG("%s: setting focus state to %d", __func__, state);
btif_a2dp_sink_cb.rx_focus_state = state;
if (btif_a2dp_sink_cb.rx_focus_state == BTIF_A2DP_SINK_FOCUS_NOT_GRANTED) {
diff --git a/btif/src/btif_av.cc b/btif/src/btif_av.cc
index 24e32ec..8ab336a 100644
--- a/btif/src/btif_av.cc
+++ b/btif/src/btif_av.cc
@@ -2861,6 +2861,27 @@
BTIF_AV_START_STREAM_REQ_EVT);
}
+void src_do_suspend_in_main_thread(btif_av_sm_event_t event) {
+ if (event != BTIF_AV_SUSPEND_STREAM_REQ_EVT &&
+ event != BTIF_AV_STOP_STREAM_REQ_EVT)
+ return;
+ auto src_do_stream_suspend = [](btif_av_sm_event_t event) {
+ bool is_idle = true;
+ for (auto it : btif_av_source.Peers()) {
+ const BtifAvPeer* peer = it.second;
+ if (peer->StateMachine().StateId() == BtifAvStateMachine::kStateStarted) {
+ btif_av_source_dispatch_sm_event(peer->PeerAddress(), event);
+ is_idle = false;
+ }
+ }
+ if (is_idle) {
+ btif_a2dp_on_stopped(nullptr);
+ }
+ };
+ // switch to main thread to prevent a race condition of accessing peers
+ do_in_main_thread(FROM_HERE, base::Bind(src_do_stream_suspend, event));
+}
+
void btif_av_stream_stop(const RawAddress& peer_address) {
LOG_INFO(LOG_TAG, "%s peer %s", __func__, peer_address.ToString().c_str());
@@ -2870,23 +2891,15 @@
}
// The active peer might have changed and we might be in the process
- // of reconfiguring the stream. We need to stop the appopriate peer(s).
- for (auto it : btif_av_source.Peers()) {
- const BtifAvPeer* peer = it.second;
- btif_av_source_dispatch_sm_event(peer->PeerAddress(),
- BTIF_AV_STOP_STREAM_REQ_EVT);
- }
+ // of reconfiguring the stream. We need to stop the appropriate peer(s).
+ src_do_suspend_in_main_thread(BTIF_AV_STOP_STREAM_REQ_EVT);
}
void btif_av_stream_suspend(void) {
LOG_INFO(LOG_TAG, "%s", __func__);
// The active peer might have changed and we might be in the process
// of reconfiguring the stream. We need to suspend the appropriate peer(s).
- for (auto it : btif_av_source.Peers()) {
- const BtifAvPeer* peer = it.second;
- btif_av_source_dispatch_sm_event(peer->PeerAddress(),
- BTIF_AV_SUSPEND_STREAM_REQ_EVT);
- }
+ src_do_suspend_in_main_thread(BTIF_AV_SUSPEND_STREAM_REQ_EVT);
}
void btif_av_stream_start_offload(void) {
diff --git a/btif/src/btif_ble_advertiser.cc b/btif/src/btif_ble_advertiser.cc
index dcbe080..d1923bd 100644
--- a/btif/src/btif_ble_advertiser.cc
+++ b/btif/src/btif_ble_advertiser.cc
@@ -83,7 +83,7 @@
}
class BleAdvertiserInterfaceImpl : public BleAdvertiserInterface {
- ~BleAdvertiserInterfaceImpl(){};
+ ~BleAdvertiserInterfaceImpl() override{};
void RegisterAdvertiserCb(IdStatusCallback cb, uint8_t advertiser_id,
uint8_t status) {
diff --git a/btif/src/btif_ble_scanner.cc b/btif/src/btif_ble_scanner.cc
index fa6fd4c..b314993 100644
--- a/btif/src/btif_ble_scanner.cc
+++ b/btif/src/btif_ble_scanner.cc
@@ -203,7 +203,7 @@
void bta_cback(tBTA_GATTC_EVT, tBTA_GATTC*) {}
class BleScannerInterfaceImpl : public BleScannerInterface {
- ~BleScannerInterfaceImpl(){};
+ ~BleScannerInterfaceImpl() override{};
void RegisterScanner(RegisterCallback cb) override {
do_in_main_thread(FROM_HERE,
diff --git a/btif/src/btif_bqr.cc b/btif/src/btif_bqr.cc
index 17253c5..3f53e74 100644
--- a/btif/src/btif_bqr.cc
+++ b/btif/src/btif_bqr.cc
@@ -294,7 +294,7 @@
UINT32_TO_STREAM(p_param, bqr_config.quality_event_mask);
UINT16_TO_STREAM(p_param, bqr_config.minimum_report_interval_ms);
- BTM_VendorSpecificCommand(HCI_CONTROLLER_BQR_OPCODE_OCF, p_param - param,
+ BTM_VendorSpecificCommand(HCI_CONTROLLER_BQR, p_param - param,
param, BqrVscCompleteCallback);
}
diff --git a/btif/src/btif_config.cc b/btif/src/btif_config.cc
index be006ab..b1af0ba 100644
--- a/btif/src/btif_config.cc
+++ b/btif/src/btif_config.cc
@@ -38,7 +38,7 @@
#include "btif_api.h"
#include "btif_common.h"
#include "btif_config_transcode.h"
-#include "btif_keystore.h"
+//#include "btif_keystore.h"
#include "btif_util.h"
#include "common/address_obfuscator.h"
#include "osi/include/alarm.h"
@@ -58,15 +58,15 @@
#define DISABLED "disabled"
static const char* TIME_STRING_FORMAT = "%Y-%m-%d %H:%M:%S";
-constexpr int kBufferSize = 400 * 10; // initial file is ~400B
+// constexpr int kBufferSize = 400 * 10; // initial file is ~400B
-static bool use_key_attestation() {
+/*static bool use_key_attestation() {
return getuid() == AID_BLUETOOTH && is_single_user_mode();
-}
+}*/
#define BT_CONFIG_METRICS_SECTION "Metrics"
#define BT_CONFIG_METRICS_SALT_256BIT "Salt256Bit"
-using bluetooth::BtifKeystore;
+// using bluetooth::BtifKeystore;
using bluetooth::common::AddressObfuscator;
// TODO(armansito): Find a better way than searching by a hardcoded path.
@@ -93,9 +93,10 @@
static std::unique_ptr<config_t> btif_config_open(const char* filename, const char* checksum_filename);
// Key attestation
-static std::string hash_file(const char* filename);
-static std::string read_checksum_file(const char* filename);
-static void write_checksum_file(const char* filename, const std::string& hash);
+// static std::string hash_file(const char* filename);
+// static std::string read_checksum_file(const char* filename);
+// static void write_checksum_file(const char* filename, const std::string&
+// hash);
static enum ConfigSource {
NOT_LOADED,
@@ -176,7 +177,7 @@
static std::unique_ptr<config_t> config;
static alarm_t* config_timer;
-static BtifKeystore btif_keystore(new keystore::KeystoreClientImpl);
+// static BtifKeystore btif_keystore(new keystore::KeystoreClientImpl);
// Module lifecycle functions
@@ -184,6 +185,9 @@
std::unique_lock<std::recursive_mutex> lock(config_lock);
if (is_factory_reset()) delete_config_files();
+ /*if (is_factory_reset() ||
+ (use_key_attestation() && !btif_keystore.DoesKeyExist()))
+ delete_config_files();*/
std::string file_source;
@@ -262,7 +266,7 @@
}
static std::unique_ptr<config_t> btif_config_open(const char* filename, const char* checksum_filename) {
- // START KEY ATTESTATION
+ /*// START KEY ATTESTATION
// Get hash of current file
std::string current_hash = hash_file(filename);
// Get stored hash
@@ -278,7 +282,7 @@
if (current_hash != stored_hash) {
return nullptr;
}
- // END KEY ATTESTATION
+ // END KEY ATTESTATION*/
std::unique_ptr<config_t> config = config_new(filename);
if (!config) return nullptr;
@@ -512,11 +516,11 @@
bool ret = config_save(*config, CONFIG_FILE_PATH);
btif_config_source = RESET;
- // Save encrypted hash
+ /*// Save encrypted hash
std::string current_hash = hash_file(CONFIG_FILE_PATH);
if (!current_hash.empty()) {
write_checksum_file(CONFIG_FILE_CHECKSUM_PATH, current_hash);
- }
+ }*/
return ret;
}
@@ -539,11 +543,11 @@
std::unique_ptr<config_t> config_paired = config_new_clone(*config);
btif_config_remove_unpaired(config_paired.get());
config_save(*config_paired, CONFIG_FILE_PATH);
- // Save hash
+ /*// Save hash
std::string current_hash = hash_file(CONFIG_FILE_PATH);
if (!current_hash.empty()) {
write_checksum_file(CONFIG_FILE_CHECKSUM_PATH, current_hash);
- }
+ }*/
}
static void btif_config_remove_unpaired(config_t* conf) {
@@ -635,12 +639,12 @@
static void delete_config_files(void) {
remove(CONFIG_FILE_PATH);
remove(CONFIG_BACKUP_PATH);
- remove(CONFIG_FILE_CHECKSUM_PATH);
- remove(CONFIG_BACKUP_CHECKSUM_PATH);
+ // remove(CONFIG_FILE_CHECKSUM_PATH);
+ // remove(CONFIG_BACKUP_CHECKSUM_PATH);
osi_property_set("persist.bluetooth.factoryreset", "false");
}
-static std::string hash_file(const char* filename) {
+/*static std::string hash_file(const char* filename) {
if (!use_key_attestation()) {
LOG(INFO) << __func__ << ": Disabled for multi-user";
return DISABLED;
@@ -696,4 +700,4 @@
<< __func__ << ": Failed encrypting checksum";
CHECK(checksum_save(encrypted_checksum, checksum_filename))
<< __func__ << ": Failed to save checksum!";
-}
+}*/
diff --git a/btif/src/btif_dm.cc b/btif/src/btif_dm.cc
index 2a84aa9..5543988 100644
--- a/btif/src/btif_dm.cc
+++ b/btif/src/btif_dm.cc
@@ -1108,7 +1108,6 @@
LOG_WARN(LOG_TAG, "%s: Incoming HID Connection", __func__);
bt_property_t prop;
- RawAddress bd_addr;
Uuid uuid = Uuid::From16Bit(UUID_SERVCLASS_HUMAN_INTERFACE);
prop.type = BT_PROPERTY_UUIDS;
@@ -1179,6 +1178,7 @@
case HCI_ERR_AUTH_FAILURE:
case HCI_ERR_KEY_MISSING:
btif_storage_remove_bonded_device(&bd_addr);
+ [[fallthrough]];
case HCI_ERR_HOST_REJECT_SECURITY:
case HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE:
case HCI_ERR_UNIT_KEY_USED:
diff --git a/btif/src/btif_hearing_aid.cc b/btif/src/btif_hearing_aid.cc
index 943017e..52cce27 100644
--- a/btif/src/btif_hearing_aid.cc
+++ b/btif/src/btif_hearing_aid.cc
@@ -53,7 +53,7 @@
class HearingAidInterfaceImpl
: public bluetooth::hearing_aid::HearingAidInterface,
public HearingAidCallbacks {
- ~HearingAidInterfaceImpl() = default;
+ ~HearingAidInterfaceImpl() override = default;
void Init(HearingAidCallbacks* callbacks) override {
DVLOG(2) << __func__;
diff --git a/btif/src/btif_hf_client.cc b/btif/src/btif_hf_client.cc
index e84291d..e7181e9 100644
--- a/btif/src/btif_hf_client.cc
+++ b/btif/src/btif_hf_client.cc
@@ -747,7 +747,7 @@
}
static const bthf_client_interface_t bthfClientInterface = {
- sizeof(bthf_client_interface_t),
+ .size = sizeof(bthf_client_interface_t),
.init = init,
.connect = connect,
.disconnect = disconnect,
@@ -999,6 +999,10 @@
case BTA_HF_CLIENT_RING_INDICATION:
HAL_CBACK(bt_hf_client_callbacks, ring_indication_cb, &cb->peer_bda);
break;
+ case BTA_HF_CLIENT_UNKNOWN_EVT:
+ HAL_CBACK(bt_hf_client_callbacks, unknown_event_cb, &cb->peer_bda,
+ p_data->unknown.event_string);
+ break;
default:
BTIF_TRACE_WARNING("%s: Unhandled event: %d", __func__, event);
break;
diff --git a/btif/src/btif_rc.cc b/btif/src/btif_rc.cc
index 9919a7b..d8ea94c 100644
--- a/btif/src/btif_rc.cc
+++ b/btif/src/btif_rc.cc
@@ -2535,9 +2535,9 @@
BTIF_TRACE_DEBUG("%s: Peer supports absolute volume. newVolume: %d",
__func__, volume);
- tAVRC_COMMAND avrc_cmd = {.volume = {.opcode = AVRC_OP_VENDOR,
- .pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME,
+ tAVRC_COMMAND avrc_cmd = {.volume = {.pdu = AVRC_PDU_SET_ABSOLUTE_VOLUME,
.status = AVRC_STS_NO_ERROR,
+ .opcode = AVRC_OP_VENDOR,
.volume = volume}};
BT_HDR* p_msg = NULL;
@@ -3152,11 +3152,10 @@
break;
} else {
uint8_t* p_data = p_rsp->param.track;
- /* Update the UID for current track
- * Attributes will be fetched after the AVRCP procedure
- */
BE_STREAM_TO_UINT64(p_dev->rc_playing_uid, p_data);
get_play_status_cmd(p_dev);
+ get_element_attribute_cmd(AVRC_MAX_NUM_MEDIA_ATTR_ID, attr_list,
+ p_dev);
}
break;
@@ -3336,6 +3335,8 @@
rc_ctrl_procedure_complete(p_dev);
return;
}
+ p_dev->rc_app_settings.num_attrs = 0;
+ p_dev->rc_app_settings.num_ext_attrs = 0;
for (xx = 0; xx < p_rsp->num_attr; xx++) {
uint8_t st_index;
@@ -3809,6 +3810,10 @@
if (p_rsp->status == AVRC_STS_NO_ERROR) {
do_in_jni_thread(
FROM_HERE,
+ base::Bind(bt_rc_ctrl_callbacks->play_status_changed_cb, p_dev->rc_addr,
+ (btrc_play_status_t)p_rsp->play_status));
+ do_in_jni_thread(
+ FROM_HERE,
base::Bind(bt_rc_ctrl_callbacks->play_position_changed_cb,
p_dev->rc_addr, p_rsp->song_len, p_rsp->song_pos));
} else {
@@ -3907,6 +3912,12 @@
/* We want to make the ownership explicit in native */
btrc_items, item_count));
+ if (item_count > 0) {
+ if (btrc_items[0].item_type == AVRC_ITEM_PLAYER &&
+ (p_dev->rc_features & BTA_AV_FEAT_APP_SETTING)) {
+ list_player_app_setting_attrib_cmd(p_dev);
+ }
+ }
/* Release the memory block for items and attributes allocated here.
* Since the executor for do_in_jni_thread is a Single Thread Task Runner it
* is okay to queue up the cleanup of btrc_items */
diff --git a/btif/src/btif_sock.cc b/btif/src/btif_sock.cc
index 0c4f6f6..8c4c9c3 100644
--- a/btif/src/btif_sock.cc
+++ b/btif/src/btif_sock.cc
@@ -28,6 +28,7 @@
#include "bta_api.h"
#include "btif_common.h"
+#include "btif_config.h"
#include "btif_sock_l2cap.h"
#include "btif_sock_rfc.h"
#include "btif_sock_sco.h"
@@ -215,12 +216,24 @@
status = btsock_l2cap_connect(bd_addr, channel, sock_fd, flags, app_uid);
break;
- case BTSOCK_L2CAP_LE:
+ case BTSOCK_L2CAP_LE: {
flags |= BTSOCK_FLAG_LE_COC;
+
+ // Ensure device is in inquiry database
+ int addr_type = 0;
+ int device_type = 0;
+
+ if (btif_get_address_type(*bd_addr, &addr_type) &&
+ btif_get_device_type(*bd_addr, &device_type) &&
+ device_type != BT_DEVICE_TYPE_BREDR) {
+ BTA_DmAddBleDevice(*bd_addr, addr_type, device_type);
+ }
+
LOG_DEBUG(LOG_TAG, "%s: type=BTSOCK_L2CAP_LE, channel=0x%x, flags=0x%x",
__func__, channel, flags);
status = btsock_l2cap_connect(bd_addr, channel, sock_fd, flags, app_uid);
break;
+ }
case BTSOCK_SCO:
status = btsock_sco_connect(bd_addr, sock_fd, flags);
diff --git a/btif/src/btif_storage.cc b/btif/src/btif_storage.cc
index 2427493..e203d2f 100644
--- a/btif/src/btif_storage.cc
+++ b/btif/src/btif_storage.cc
@@ -1119,6 +1119,7 @@
break;
case BTIF_DM_LE_KEY_LID:
name = "LE_KEY_LID";
+ break;
default:
return BT_STATUS_FAIL;
}
diff --git a/build/Android.bp b/build/Android.bp
index cde9a36..32c0f31 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -29,9 +29,10 @@
},
}
+// Fuzzable defaults are the subset of defaults that are used in fuzzing, which
+// requires no shared libraries, and no explicit sanitization.
fluoride_defaults {
- name: "fluoride_types_defaults",
- defaults: ["libchrome_support_defaults"],
+ name: "fluoride_types_defaults_fuzzable",
cflags: [
"-DEXPORT_SYMBOL=__attribute__((visibility(\"default\")))",
"-fvisibility=hidden",
@@ -54,15 +55,22 @@
}
fluoride_defaults {
- name: "fluoride_defaults",
+ name: "fluoride_types_defaults",
+ defaults: [
+ "fluoride_types_defaults_fuzzable",
+ "libchrome_support_defaults"
+ ],
+}
+
+fluoride_defaults {
+ name: "fluoride_defaults_fuzzable",
target: {
android: {
test_config_template: ":BluetoothTestConfigTemplate",
- }
+ },
},
- defaults: ["fluoride_types_defaults"],
+ defaults: ["fluoride_types_defaults_fuzzable"],
header_libs: ["libbluetooth_headers"],
- shared_libs: ["libstatslog"],
static_libs: [
"libbluetooth-types",
"libbt-platform-protos-lite",
@@ -73,6 +81,15 @@
},
}
+fluoride_defaults {
+ name: "fluoride_defaults",
+ defaults: ["fluoride_defaults_fuzzable", "fluoride_types_defaults"],
+ shared_libs: ["libstatslog"],
+ sanitize: {
+ misc_undefined: ["bounds"],
+ },
+}
+
// Enables code coverage for a set of source files. Must be combined with
// "clang_coverage_bin" in order to work. See //test/gen_coverage.py for more information
// on generating code coverage.
diff --git a/common/Android.bp b/common/Android.bp
index 202559d..587b197 100644
--- a/common/Android.bp
+++ b/common/Android.bp
@@ -37,7 +37,7 @@
"system/bt",
"system/bt/stack/include",
],
- srcs : [
+ srcs: [
"address_obfuscator_unittest.cc",
"leaky_bonded_queue_unittest.cc",
"message_loop_thread_unittest.cc",
@@ -52,7 +52,7 @@
"libprotobuf-cpp-lite",
"libcrypto",
],
- static_libs : [
+ static_libs: [
"libgmock",
"libbt-common",
"libbt-protos-lite",
@@ -77,7 +77,7 @@
static_libs: [
"libgmock",
"libosi",
- "libbt-common"
+ "libbt-common",
],
}
@@ -97,7 +97,7 @@
],
static_libs: [
"libosi",
- "libbt-common"
+ "libbt-common",
],
}
diff --git a/common/leaky_bonded_queue_unittest.cc b/common/leaky_bonded_queue_unittest.cc
index fcd55cd..b2ff35b 100644
--- a/common/leaky_bonded_queue_unittest.cc
+++ b/common/leaky_bonded_queue_unittest.cc
@@ -42,7 +42,7 @@
class MockItem : public Item {
public:
MockItem(int i) : Item(i) {}
- ~MockItem() { Destruct(); }
+ ~MockItem() override { Destruct(); }
MOCK_METHOD0(Destruct, void());
};
diff --git a/common/metrics_unittest.cc b/common/metrics_unittest.cc
index 03a427a..a46c896 100644
--- a/common/metrics_unittest.cc
+++ b/common/metrics_unittest.cc
@@ -400,12 +400,12 @@
bt_log_->Clear();
}
- void SetUp() {
+ void SetUp() override {
bt_log_ = new BluetoothLog();
// Clear existing metrics entries, if any
BluetoothMetricsLogger::GetInstance()->Reset();
}
- void TearDown() {
+ void TearDown() override {
// Clear remaining metrics entries, if any
BluetoothMetricsLogger::GetInstance()->Reset();
ClearLog();
diff --git a/common/test/thread_performance_test.cc b/common/test/thread_performance_test.cc
index dc6a53f..4c38fed 100644
--- a/common/test/thread_performance_test.cc
+++ b/common/test/thread_performance_test.cc
@@ -265,6 +265,7 @@
std::chrono::milliseconds duration =
std::chrono::duration_cast<std::chrono::milliseconds>(end_time -
start_time);
+ fixed_queue_unregister_dequeue(bt_msg_queue_);
LOG(INFO) << "ReactorPerformanceTest, " << duration.count() << " ms, "
<< NUM_MESSAGES_TO_SEND << " messages";
diff --git a/device/include/controller.h b/device/include/controller.h
index c1fe337..a15f57b 100644
--- a/device/include/controller.h
+++ b/device/include/controller.h
@@ -89,6 +89,12 @@
} controller_t;
+namespace bluetooth {
+namespace legacy {
+const controller_t* controller_get_interface();
+} // namespace legacy
+} // namespace bluetooth
+
const controller_t* controller_get_interface();
const controller_t* controller_get_test_interface(
diff --git a/device/include/interop.h b/device/include/interop.h
index a9bf586..d7ca917 100644
--- a/device/include/interop.h
+++ b/device/include/interop.h
@@ -94,6 +94,12 @@
// Set a very low initial sniff subrating for HID devices that do not
// set their own sniff interval.
INTEROP_HID_HOST_LIMIT_SNIFF_INTERVAL,
+
+ // Disable remote name requst for some devices.
+ // The public address of these devices are same as the Random address in ADV.
+ // Then will get name by LE_Create_connection, actually fails,
+ // but will block pairing.
+ INTEROP_DISABLE_NAME_REQUEST
} interop_feature_t;
// Check if a given |addr| matches a known interoperability workaround as
diff --git a/device/include/interop_database.h b/device/include/interop_database.h
index d7425c9..b4b1b07 100644
--- a/device/include/interop_database.h
+++ b/device/include/interop_database.h
@@ -143,6 +143,13 @@
// AirPods 2 - unacceptably loud volume
{{{0x94, 0x16, 0x25, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+ // AirPods 2 - unacceptably loud volume
+ {{{0x9c, 0x64, 0x8b, 0, 0, 0}}, 3, INTEROP_DISABLE_ABSOLUTE_VOLUME},
+
+ // for skip name request,
+ // because BR/EDR address and ADV random address are the same
+ {{{0xd4, 0x7a, 0xe2, 0, 0, 0}}, 3, INTEROP_DISABLE_NAME_REQUEST},
};
typedef struct {
@@ -170,7 +177,8 @@
// Kenwood KMM-BT518HD - no audio when A2DP codec sample rate is changed
{"KMM-BT51*HD", 11, INTEROP_DISABLE_AVDTP_RECONFIGURE},
- // Nintendo Switch Pro Controller - does not set sniff interval dynamically.
- // Requires custom HID report command to change mode.
+ // Nintendo Switch Pro Controller and Joy Con - do not set sniff interval
+ // dynamically. They require custom HID report command to change mode.
{"Pro Controller", 14, INTEROP_HID_HOST_LIMIT_SNIFF_INTERVAL},
+ {"Joy-Con", 7, INTEROP_HID_HOST_LIMIT_SNIFF_INTERVAL},
};
diff --git a/device/src/controller.cc b/device/src/controller.cc
index 34c8afd..537216b 100644
--- a/device/src/controller.cc
+++ b/device/src/controller.cc
@@ -27,6 +27,8 @@
#include "btcore/include/module.h"
#include "btcore/include/version.h"
#include "hcimsgs.h"
+#include "main/shim/controller.h"
+#include "main/shim/shim.h"
#include "osi/include/future.h"
#include "stack/include/btm_ble_api.h"
@@ -582,7 +584,7 @@
get_local_supported_codecs,
get_le_all_initiating_phys};
-const controller_t* controller_get_interface() {
+const controller_t* bluetooth::legacy::controller_get_interface() {
static bool loaded = false;
if (!loaded) {
loaded = true;
@@ -595,6 +597,14 @@
return &interface;
}
+const controller_t* controller_get_interface() {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::controller_get_interface();
+ } else {
+ return bluetooth::legacy::controller_get_interface();
+ }
+}
+
const controller_t* controller_get_test_interface(
const hci_t* hci_interface,
const hci_packet_factory_t* packet_factory_interface,
diff --git a/device/src/interop.cc b/device/src/interop.cc
index e4bce56..9a701b1 100644
--- a/device/src/interop.cc
+++ b/device/src/interop.cc
@@ -50,7 +50,7 @@
if (interop_match_fixed_(feature, addr) ||
interop_match_dynamic_(feature, addr)) {
- LOG_WARN(LOG_TAG, "%s() Device %s is a match for interop workaround %s.",
+ LOG_INFO(LOG_TAG, "%s() Device %s is a match for interop workaround %s.",
__func__, addr->ToString().c_str(),
interop_feature_string_(feature));
return true;
@@ -69,6 +69,8 @@
strlen(name) >= interop_name_database[i].length &&
strncmp(name, interop_name_database[i].name,
interop_name_database[i].length) == 0) {
+ LOG_INFO(LOG_TAG, "%s() Device %s is a match for interop workaround %s.",
+ __func__, name, interop_feature_string_(feature));
return true;
}
}
@@ -129,6 +131,7 @@
CASE_RETURN_STR(INTEROP_DYNAMIC_ROLE_SWITCH)
CASE_RETURN_STR(INTEROP_DISABLE_ROLE_SWITCH)
CASE_RETURN_STR(INTEROP_HID_HOST_LIMIT_SNIFF_INTERVAL)
+ CASE_RETURN_STR(INTEROP_DISABLE_NAME_REQUEST)
}
return "UNKNOWN";
diff --git a/embdrv/g722/Android.bp b/embdrv/g722/Android.bp
index cc635d8..fbac145 100644
--- a/embdrv/g722/Android.bp
+++ b/embdrv/g722/Android.bp
@@ -1,12 +1,11 @@
-
cc_library_static {
name: "libg722codec",
defaults: ["fluoride_defaults"],
cflags: [
- "-DG722_SUPPORT_MALLOC"
+ "-DG722_SUPPORT_MALLOC",
],
srcs: [
"g722_decode.cc",
"g722_encode.cc",
],
-}
\ No newline at end of file
+}
diff --git a/embdrv/sbc/decoder/srce/decoder-sbc.c b/embdrv/sbc/decoder/srce/decoder-sbc.c
index 20c5b67..50168b5 100644
--- a/embdrv/sbc/decoder/srce/decoder-sbc.c
+++ b/embdrv/sbc/decoder/srce/decoder-sbc.c
@@ -33,6 +33,12 @@
#define SPECIALIZE_READ_SAMPLES_JOINT
+#if __has_attribute(fallthrough)
+#define __fallthrough __attribute__((__fallthrough__))
+#else
+#define __fallthrough
+#endif
+
/**
* Scans through a buffer looking for a codec syncword. If the decoder has been
* set for enhanced operation using OI_CODEC_SBC_DecoderReset(), it will search
@@ -413,7 +419,7 @@
case SBC_DUAL_CHANNEL:
frameLen *= 2;
- /* fall through */
+ __fallthrough;
default:
if (mode == SBC_MONO) {
diff --git a/gd/.gitignore b/gd/.gitignore
new file mode 100644
index 0000000..106fe1e
--- /dev/null
+++ b/gd/.gitignore
@@ -0,0 +1,2 @@
+**/default.profraw
+**/__pycache__/
diff --git a/gd/Android.bp b/gd/Android.bp
index e0b8d5d..46108c6 100644
--- a/gd/Android.bp
+++ b/gd/Android.bp
@@ -8,15 +8,18 @@
"-DOS_LINUX_GENERIC",
],
shared_libs: [
- "liblog"
- ]
+ "liblog",
+ ],
},
host: {
cflags: [
"-DOS_LINUX",
"-DOS_LINUX_GENERIC",
- ]
- }
+ ],
+ },
+ darwin: {
+ enabled: false,
+ },
},
cpp_std: "c++17",
cflags: [
@@ -24,6 +27,8 @@
"-fvisibility=hidden",
"-DLOG_NDEBUG=1",
"-DGOOGLE_PROTOBUF_NO_RTTI",
+ "-Wno-unused-parameter",
+ "-Wno-unused-result",
],
conlyflags: [
"-std=c99",
@@ -77,13 +82,131 @@
linux: {
srcs: [
":BluetoothOsSources_linux_generic",
- ]
- }
+ ],
+ },
+ host: {
+ srcs: [
+ ":BluetoothHalSources_hci_rootcanal",
+ ],
+ },
+ android: {
+ srcs: [
+ ":BluetoothHalSources_hci_android_hidl",
+ ],
+ shared_libs: [
+ "android.hardware.bluetooth@1.0",
+ "libhidlbase",
+ "libutils",
+ ],
+ },
},
srcs: [
+ "stack_manager.cc",
+ "module.cc",
":BluetoothCommonSources",
+ ":BluetoothCryptoToolboxSources",
+ ":BluetoothHalSources",
+ ":BluetoothHciSources",
+ ":BluetoothL2capSources",
+ ":BluetoothNeighborSources",
":BluetoothPacketSources",
- ]
+ ":BluetoothShimSources",
+ ":BluetoothSecuritySources",
+ ],
+ generated_headers: [
+ "BluetoothGeneratedPackets_h",
+ ],
+ shared_libs: [
+ "libchrome",
+ ],
+}
+
+cc_binary {
+ name: "bluetooth_stack_with_facade",
+ defaults: [
+ "gd_defaults",
+ ],
+ host_supported: true,
+ srcs: [
+ "facade/facade_main.cc",
+ "facade/grpc_root_server.cc",
+ "facade/read_only_property_server.cc",
+ "grpc/grpc_module.cc",
+ ":BluetoothFacade_hci_hal",
+ ":BluetoothFacade_hci_layer",
+ ":BluetoothFacade_l2cap_layer",
+ ],
+ generated_headers: [
+ "BluetoothGeneratedPackets_h",
+ "BluetoothFacadeGeneratedStub_h",
+ ],
+ generated_sources: [
+ "BluetoothFacadeGeneratedStub_cc",
+ ],
+ static_libs: [
+ "libbluetooth_gd",
+ ],
+ shared_libs: [
+ "libchrome",
+ "libgrpc++_unsecure",
+ "libprotobuf-cpp-full",
+ ],
+ target: {
+ android: {
+ shared_libs: [
+ "android.hardware.bluetooth@1.0",
+ "libhidlbase",
+ "libutils",
+ ],
+ },
+ },
+ sanitize: {
+ address: true,
+ },
+}
+
+cc_binary {
+ name: "bluetooth_cert_stack",
+ defaults: [
+ "gd_defaults",
+ ],
+ host_supported: true,
+ srcs: [
+ "cert/cert_main.cc",
+ "cert/grpc_root_server.cc",
+ "cert/read_only_property_server.cc",
+ "grpc/grpc_module.cc",
+ ":BluetoothCertSource_hci_hal",
+ ":BluetoothCertSource_hci_layer",
+ ":BluetoothCertSource_l2cap_layer",
+ ],
+ generated_headers: [
+ "BluetoothGeneratedPackets_h",
+ "BluetoothCertStackGeneratedStub_h",
+ ],
+ generated_sources: [
+ "BluetoothCertStackGeneratedStub_cc",
+ ],
+ static_libs: [
+ "libbluetooth_gd",
+ ],
+ shared_libs: [
+ "libchrome",
+ "libgrpc++_unsecure",
+ "libprotobuf-cpp-full",
+ ],
+ target: {
+ android: {
+ shared_libs: [
+ "android.hardware.bluetooth@1.0",
+ "libhidlbase",
+ "libutils",
+ ],
+ },
+ },
+ sanitize: {
+ address: true,
+ },
}
cc_test {
@@ -98,21 +221,101 @@
linux: {
srcs: [
":BluetoothOsTestSources_linux_generic",
- ]
- }
+ ],
+ },
+ host: {
+ srcs: [
+ ":BluetoothHalTestSources_hci_rootcanal",
+ ],
+ },
+ android: {
+ srcs: [
+ ":BluetoothHalTestSources_hci_android_hidl",
+ ],
+ shared_libs: [
+ "android.hardware.bluetooth@1.0",
+ "libhidlbase",
+ "libutils",
+ ],
+ },
},
srcs: [
+ "module_unittest.cc",
+ "stack_manager_unittest.cc",
":BluetoothCommonTestSources",
+ ":BluetoothCryptoToolboxTestSources",
+ ":BluetoothHciTestSources",
+ ":BluetoothL2capTestSources",
+ ":BluetoothNeighborTestSources",
":BluetoothPacketTestSources",
+ ":BluetoothSecurityTestSources",
+ ":BluetoothShimTestSources",
],
- static_libs : [
+ generated_headers: [
+ "BluetoothGeneratedPackets_h",
+ ],
+ static_libs: [
"libbluetooth_gd",
+ "libgmock",
+ ],
+ shared_libs: [
+ "libchrome",
],
sanitize: {
- cfi: false,
+ address: true,
},
}
+cc_test {
+ name: "bluetooth_packet_parser_test",
+ test_suites: ["device-tests"],
+ defaults: [
+ "gd_defaults",
+ "gd_clang_coverage_bin",
+ ],
+ host_supported: true,
+ srcs: [
+ ":BluetoothPacketSources",
+ ":BluetoothPacketParserTestPacketTestSources",
+ ],
+ generated_headers: [
+ "BluetoothPacketParserTestPacketPdlGen_h",
+ ],
+ sanitize: {
+ address: true,
+ cfi: true,
+ },
+}
+
+cc_fuzz {
+ name: "bluetooth_gd_fuzz_test",
+ defaults: ["gd_defaults"],
+ srcs: [
+ "fuzz_test.cc",
+ ":BluetoothHciFuzzTestSources",
+ ":BluetoothL2capFuzzTestSources",
+ ],
+ static_libs: [
+ "libbluetooth_gd",
+ "libchrome",
+ "libgmock",
+ "libgtest",
+ ],
+ host_supported: true,
+ generated_headers: [
+ "BluetoothGeneratedPackets_h",
+ ],
+ target: {
+ android: {
+ shared_libs: [
+ "android.hardware.bluetooth@1.0",
+ "libhidlbase",
+ "libutils",
+ ],
+ },
+ },
+}
+
cc_benchmark {
name: "bluetooth_benchmark_gd",
defaults: ["gd_defaults"],
@@ -121,7 +324,323 @@
"benchmark.cc",
":BluetoothOsBenchmarkSources",
],
- static_libs : [
- "libbluetooth_gd",
+ static_libs: [
+ "libbluetooth_gd",
],
+ shared_libs: [
+ "libchrome",
+ ],
+}
+
+filegroup {
+ name: "BluetoothHciClassSources",
+ srcs: [
+ "hci/address.cc",
+ "hci/class_of_device.cc",
+ ],
+}
+
+genrule {
+ name: "BluetoothGeneratedPackets_h",
+ tools: [
+ "bluetooth_packetgen",
+ ],
+ cmd: "$(location bluetooth_packetgen) --include=system/bt/gd --out=$(genDir) $(in)",
+ srcs: [
+ "hci/hci_packets.pdl",
+ "l2cap/l2cap_packets.pdl",
+ "security/smp_packets.pdl",
+ ],
+ out: [
+ "hci/hci_packets.h",
+ "l2cap/l2cap_packets.h",
+ "security/smp_packets.h",
+ ],
+}
+
+genrule {
+ name: "BluetoothGeneratedPackets_python3_cc",
+ tools: [
+ "bluetooth_packetgen",
+ ],
+ cmd: "$(location bluetooth_packetgen) --include=system/bt/gd --out=$(genDir) --num_shards=5 $(in)",
+ srcs: [
+ "hci/hci_packets.pdl",
+ "l2cap/l2cap_packets.pdl",
+ "security/smp_packets.pdl",
+ ],
+ out: [
+ "hci/hci_packets_python3.cc",
+ "hci/hci_packets_python3_shard_0.cc",
+ "hci/hci_packets_python3_shard_1.cc",
+ "hci/hci_packets_python3_shard_2.cc",
+ "hci/hci_packets_python3_shard_3.cc",
+ "hci/hci_packets_python3_shard_4.cc",
+ "l2cap/l2cap_packets_python3.cc",
+ "l2cap/l2cap_packets_python3_shard_0.cc",
+ "l2cap/l2cap_packets_python3_shard_1.cc",
+ "l2cap/l2cap_packets_python3_shard_2.cc",
+ "l2cap/l2cap_packets_python3_shard_3.cc",
+ "l2cap/l2cap_packets_python3_shard_4.cc",
+ "security/smp_packets_python3.cc",
+ "security/smp_packets_python3_shard_0.cc",
+ "security/smp_packets_python3_shard_1.cc",
+ "security/smp_packets_python3_shard_2.cc",
+ "security/smp_packets_python3_shard_3.cc",
+ "security/smp_packets_python3_shard_4.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothFacadeProto",
+ srcs: [
+ "facade/common.proto",
+ "facade/rootservice.proto",
+ "hal/facade.proto",
+ "hci/facade.proto",
+ "l2cap/classic/facade.proto",
+ ],
+}
+
+genrule {
+ name: "BluetoothFacadeGeneratedStub_h",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-cpp-plugin",
+ ],
+ cmd: "$(location aprotoc) -Isystem/bt/gd -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ srcs: [
+ ":BluetoothFacadeProto",
+ ],
+ out: [
+ "facade/common.grpc.pb.h",
+ "facade/common.pb.h",
+ "facade/rootservice.grpc.pb.h",
+ "facade/rootservice.pb.h",
+ "hal/facade.grpc.pb.h",
+ "hal/facade.pb.h",
+ "hci/facade.grpc.pb.h",
+ "hci/facade.pb.h",
+ "l2cap/classic/facade.grpc.pb.h",
+ "l2cap/classic/facade.pb.h",
+ ],
+}
+
+genrule {
+ name: "BluetoothFacadeGeneratedStub_cc",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-cpp-plugin",
+ ],
+ cmd: "$(location aprotoc) -Isystem/bt/gd -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ srcs: [
+ ":BluetoothFacadeProto",
+ ],
+ out: [
+ "facade/common.grpc.pb.cc",
+ "facade/common.pb.cc",
+ "facade/rootservice.grpc.pb.cc",
+ "facade/rootservice.pb.cc",
+ "hal/facade.grpc.pb.cc",
+ "hal/facade.pb.cc",
+ "hci/facade.grpc.pb.cc",
+ "hci/facade.pb.cc",
+ "l2cap/classic/facade.grpc.pb.cc",
+ "l2cap/classic/facade.pb.cc",
+ ],
+}
+
+genrule {
+ name: "BluetoothFacadeAndCertGeneratedStub_py",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-python-plugin",
+ ],
+ cmd: "$(location aprotoc) -Isystem/bt/gd -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-python-plugin) $(in) --grpc_out=$(genDir) --python_out=$(genDir); " +
+ "touch $(genDir)/facade/__init__.py; " +
+ "touch $(genDir)/hal/__init__.py; " +
+ "touch $(genDir)/hal/cert/__init__.py; " +
+ "touch $(genDir)/hci/__init__.py; " +
+ "touch $(genDir)/hci/cert/__init__.py; " +
+ "touch $(genDir)/l2cap/classic/__init__.py; " +
+ "touch $(genDir)/l2cap/classic/cert/__init__.py; ",
+ srcs: [
+ ":BluetoothFacadeProto",
+ ":BluetoothCertStackProto",
+ ],
+ out: [
+ "cert/rootservice_pb2_grpc.py",
+ "cert/rootservice_pb2.py",
+ "facade/__init__.py",
+ "facade/common_pb2_grpc.py",
+ "facade/common_pb2.py",
+ "facade/rootservice_pb2_grpc.py",
+ "facade/rootservice_pb2.py",
+ "hal/__init__.py",
+ "hal/facade_pb2_grpc.py",
+ "hal/facade_pb2.py",
+ "hci/__init__.py",
+ "hci/facade_pb2_grpc.py",
+ "hci/facade_pb2.py",
+ "l2cap/classic/__init__.py",
+ "l2cap/classic/facade_pb2_grpc.py",
+ "l2cap/classic/facade_pb2.py",
+ "hal/cert/__init__.py",
+ "hal/cert/api_pb2_grpc.py",
+ "hal/cert/api_pb2.py",
+ "hci/cert/__init__.py",
+ "hci/cert/api_pb2_grpc.py",
+ "hci/cert/api_pb2.py",
+ "l2cap/classic/cert/__init__.py",
+ "l2cap/classic/cert/api_pb2_grpc.py",
+ "l2cap/classic/cert/api_pb2.py",
+ ],
+}
+
+filegroup {
+ name: "BluetoothCertStackProto",
+ srcs: [
+ "cert/rootservice.proto",
+ "hal/cert/api.proto",
+ "hci/cert/api.proto",
+ "l2cap/classic/cert/api.proto",
+ ],
+}
+
+genrule {
+ name: "BluetoothCertStackGeneratedStub_h",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-cpp-plugin",
+ ],
+ cmd: "$(location aprotoc) -Isystem/bt/gd -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ srcs: [
+ ":BluetoothCertStackProto",
+ ":BluetoothFacadeProto", // we need to use facade/common.proto
+ ],
+ out: [
+ "cert/rootservice.grpc.pb.h",
+ "cert/rootservice.pb.h",
+ "facade/common.grpc.pb.h",
+ "facade/common.pb.h",
+ "hal/cert/api.grpc.pb.h",
+ "hal/cert/api.pb.h",
+ "hci/cert/api.grpc.pb.h",
+ "hci/cert/api.pb.h",
+ "l2cap/classic/cert/api.grpc.pb.h",
+ "l2cap/classic/cert/api.pb.h",
+ ],
+}
+
+genrule {
+ name: "BluetoothCertStackGeneratedStub_cc",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-cpp-plugin",
+ ],
+ cmd: "$(location aprotoc) -Isystem/bt/gd -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ srcs: [
+ ":BluetoothCertStackProto",
+ ":BluetoothFacadeProto", // we need to use facade/common.proto
+ ],
+ out: [
+ "cert/rootservice.grpc.pb.cc",
+ "cert/rootservice.pb.cc",
+ "facade/common.grpc.pb.cc",
+ "facade/common.pb.cc",
+ "hal/cert/api.grpc.pb.cc",
+ "hal/cert/api.pb.cc",
+ "hci/cert/api.grpc.pb.cc",
+ "hci/cert/api.pb.cc",
+ "l2cap/classic/cert/api.grpc.pb.cc",
+ "l2cap/classic/cert/api.pb.cc",
+ ],
+}
+
+cc_defaults {
+ name: "bluetooth_py3_native_extension_defaults",
+ include_dirs: [
+ "external/python/cpython3/Include",
+ ],
+ target: {
+ android: {
+ include_dirs: ["external/python/cpython3/android/bionic/pyconfig"],
+ },
+ android_arm: {
+ cflags: ["-DSOABI=\"cpython-38android-arm-android-bionic\""],
+ suffix: ".cpython-38android-arm-android-bionic",
+ },
+ android_arm64: {
+ cflags: ["-DSOABI=\"cpython-38android-arm64-android-bionic\""],
+ suffix: ".cpython-38android-arm64-android-bionic",
+ },
+ android_x86: {
+ cflags: ["-DSOABI=\"cpython-38android-x86-android-bionic\""],
+ suffix: ".cpython-38android-x86-android-bionic",
+ },
+ android_x86_64: {
+ cflags: ["-DSOABI=\"cpython-38android-x86_64-android-bionic\""],
+ suffix: ".cpython-38android-x86_64-android-bionic",
+ },
+ // Regenerate include dirs with android_regen.sh
+ darwin_x86_64: {
+ include_dirs: ["external/python/cpython3/android/darwin_x86_64/pyconfig"],
+ cflags: [
+ "-Wno-deprecated-declarations",
+ "-Wno-pointer-arith",
+ "-DSOABI=\"cpython-38android-x86_64-darwin\"",
+ ],
+ suffix: ".cpython-38android-x86_64-darwin",
+ },
+ linux_bionic: {
+ // NB linux_bionic is a 'host' architecture but it uses the bionic libc like 'android'
+ // targets so use the android pyconfig.
+ include_dirs: ["external/python/cpython3/android/bionic/pyconfig"],
+ cflags: ["-DSOABI=\"cpython-38android-x86_64-linux-bionic\""],
+ suffix: ".cpython-38android-x86_64-linux-bionic",
+ },
+ linux_glibc_x86: {
+ enabled: false,
+ },
+ linux_glibc_x86_64: {
+ include_dirs: ["external/python/cpython3/android/linux_x86_64/pyconfig"],
+ cflags: ["-DSOABI=\"cpython-38android-x86_64-linux-gnu\""],
+ // Commenting out the Linux suffix so that cpython-38-x86_64-linux-gnu
+ // Python 3.8 can also import the untagged .so library per PEP 3149
+ // Keep this change until Android py3-cmd can run ACTS, gRPC and can
+ // Export Python native symbols such as PyType_Type
+ // suffix: ".cpython-38android-x86_64-linux-gnu",
+ },
+ windows: {
+ enabled: false,
+ },
+ },
+ allow_undefined_symbols: true,
+}
+
+cc_library{
+ name: "bluetooth_packets_python3",
+ defaults: [
+ "gd_defaults",
+ "bluetooth_py3_native_extension_defaults"
+ ],
+ host_supported: true,
+ srcs: [
+ "packet/python3_module.cc",
+ "l2cap/fcs.cc",
+ ":BluetoothPacketSources",
+ ],
+ generated_headers: [
+ "BluetoothGeneratedPackets_h",
+ ],
+ generated_sources: [
+ "BluetoothGeneratedPackets_python3_cc",
+ ],
+ header_libs: [
+ "pybind11_headers",
+ ],
+ cflags: [
+ "-fexceptions",
+ ],
+ rtti: true,
}
diff --git a/gd/TEST_MAPPING b/gd/TEST_MAPPING
index 471210b..f0ddeaf 100644
--- a/gd/TEST_MAPPING
+++ b/gd/TEST_MAPPING
@@ -3,6 +3,10 @@
{
"name" : "bluetooth_test_gd",
"host" : true
+ },
+ {
+ "name" : "bluetooth_packet_parser_test",
+ "host" : true
}
]
}
diff --git a/gd/cert/android_devices_config.json b/gd/cert/android_devices_config.json
new file mode 100644
index 0000000..2bcbf9d
--- /dev/null
+++ b/gd/cert/android_devices_config.json
@@ -0,0 +1,54 @@
+{ "_description": "Bluetooth cert testing",
+ "testbed":
+ [
+ {
+ "_description": "Two Android devices cert testbed",
+ "name": "AndroidDeviceCert",
+ "GdDevice":
+ [
+ {
+ "grpc_port": "8899",
+ "grpc_root_server_port": "8897",
+ "signal_port": "8895",
+ "label": "stack_under_test",
+ "serial_number": "DUT",
+ "cmd":
+ [
+ "adb",
+ "-s",
+ "$(serial_number)",
+ "shell",
+ "/system/bin/bluetooth_stack_with_facade",
+ "--grpc-port=$(grpc_port)",
+ "--root-server-port=$(grpc_root_server_port)",
+ "--btsnoop=data/misc/bluetooth/logs/btsnoop_hci.log",
+ "--signal-port=$(signal_port)"
+ ]
+ }
+ ],
+ "GdCertDevice":
+ [
+ {
+ "grpc_port": "8898",
+ "grpc_root_server_port": "8896",
+ "signal_port": "8894",
+ "label": "cert_stack",
+ "serial_number": "CERT",
+ "cmd":
+ [
+ "adb",
+ "-s",
+ "$(serial_number)",
+ "shell",
+ "/system/bin/bluetooth_cert_stack",
+ "--grpc-port=$(grpc_port)",
+ "--root-server-port=$(grpc_root_server_port)",
+ "--btsnoop=data/misc/bluetooth/logs/btsnoop_hci.log",
+ "--signal-port=$(signal_port)"
+ ]
+ }
+ ]
+ }
+ ],
+ "logpath": "/tmp/logs"
+}
diff --git a/gd/cert/bluetooth_packets_python3_setup.py b/gd/cert/bluetooth_packets_python3_setup.py
new file mode 100644
index 0000000..bce14f0
--- /dev/null
+++ b/gd/cert/bluetooth_packets_python3_setup.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 - 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.
+
+
+# Usage:
+# 1. Run envsetup and lunch first in an Android checkout
+# 2. Make target bluetooth_packets_python3 that will generate C++ sources for the
+# Extension
+# 3. Build only:
+# python3 bluetooth_packets_python3_setup.py build_ext
+# Then Find the .so file in build/lib.linux-x86_64-3.X
+# 4. Install:
+# python3 bluetooth_packets_python3_setup.py install --user
+
+
+import os
+import glob
+from setuptools import setup, Extension
+
+ANDROID_BUILD_TOP = os.getenv("ANDROID_BUILD_TOP")
+PYBIND11_INCLUDE_DIR = os.path.join(ANDROID_BUILD_TOP,
+ "external/python/pybind11/include")
+GD_DIR = os.path.join(ANDROID_BUILD_TOP, "system/bt/gd")
+BT_PACKETS_GEN_DIR = os.path.join(ANDROID_BUILD_TOP,
+ "out/soong/.intermediates/system/bt/gd/BluetoothGeneratedPackets_h/gen")
+BT_PACKETS_PY3_GEN_DIR = os.path.join(ANDROID_BUILD_TOP,
+ "out/soong/.intermediates/system/bt/gd/BluetoothGeneratedPackets_python3_cc/gen")
+
+BT_PACKETS_BASE_SRCS = [
+ os.path.join(GD_DIR, "l2cap/fcs.cc"),
+ os.path.join(GD_DIR, "packet/bit_inserter.cc"),
+ os.path.join(GD_DIR, "packet/byte_inserter.cc"),
+ os.path.join(GD_DIR, "packet/byte_observer.cc"),
+ os.path.join(GD_DIR, "packet/iterator.cc"),
+ os.path.join(GD_DIR, "packet/fragmenting_inserter.cc"),
+ os.path.join(GD_DIR, "packet/packet_view.cc"),
+ os.path.join(GD_DIR, "packet/raw_builder.cc"),
+ os.path.join(GD_DIR, "packet/view.cc"),
+]
+
+BT_PACKETS_PY3_SRCs = \
+ [os.path.join(GD_DIR, "packet/python3_module.cc")] \
+ + glob.glob(os.path.join(BT_PACKETS_PY3_GEN_DIR, "hci", "*.cc")) \
+ + glob.glob(os.path.join(BT_PACKETS_PY3_GEN_DIR, "l2cap", "*.cc")) \
+ + glob.glob(os.path.join(BT_PACKETS_PY3_GEN_DIR, "security", "*.cc"))
+
+bluetooth_packets_python3_module = Extension('bluetooth_packets_python3',
+ sources=BT_PACKETS_BASE_SRCS + BT_PACKETS_PY3_SRCs,
+ include_dirs=[GD_DIR,
+ BT_PACKETS_GEN_DIR,
+ BT_PACKETS_PY3_GEN_DIR,
+ PYBIND11_INCLUDE_DIR],
+ extra_compile_args=['-std=c++17']
+ )
+
+setup(name='bluetooth_packets_python3',
+ version='1.0',
+ author="Android Open Source Project",
+ description="""Bluetooth Packet Library""",
+ ext_modules=[bluetooth_packets_python3_module],
+ py_modules=["bluetooth_packets_python3"],
+ )
diff --git a/gd/cert/cert_main.cc b/gd/cert/cert_main.cc
new file mode 100644
index 0000000..3111b70
--- /dev/null
+++ b/gd/cert/cert_main.cc
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2019 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 "stack_manager.h"
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <csignal>
+#include <cstring>
+#include <string>
+#include <thread>
+
+#include "cert/grpc_root_server.h"
+#include "grpc/grpc_module.h"
+#include "hal/cert/cert.h"
+#include "hal/hci_hal.h"
+#include "hal/hci_hal_host_rootcanal.h"
+#include "hal/snoop_logger.h"
+
+using ::bluetooth::Module;
+using ::bluetooth::ModuleList;
+using ::bluetooth::StackManager;
+using ::bluetooth::grpc::GrpcModule;
+using ::bluetooth::os::Thread;
+
+namespace {
+::bluetooth::cert::GrpcRootServer grpc_root_server;
+
+void interrupt_handler(int) {
+ grpc_root_server.StopServer();
+}
+} // namespace
+
+int main(int argc, const char** argv) {
+ int root_server_port = 8896;
+ int grpc_port = 8898;
+ int signal_port = 8894;
+
+ const std::string arg_grpc_root_server_port = "--root-server-port=";
+ const std::string arg_grpc_server_port = "--grpc-port=";
+ const std::string arg_rootcanal_port = "--rootcanal-port=";
+ const std::string arg_signal_port = "--signal-port=";
+ const std::string arg_btsnoop_path = "--btsnoop=";
+ std::string btsnoop_path;
+ for (int i = 1; i < argc; i++) {
+ std::string arg = argv[i];
+ if (arg.find(arg_grpc_root_server_port) == 0) {
+ auto port_number = arg.substr(arg_grpc_root_server_port.size());
+ root_server_port = std::stoi(port_number);
+ }
+ if (arg.find(arg_grpc_server_port) == 0) {
+ auto port_number = arg.substr(arg_grpc_server_port.size());
+ grpc_port = std::stoi(port_number);
+ }
+ if (arg.find(arg_rootcanal_port) == 0) {
+ auto port_number = arg.substr(arg_rootcanal_port.size());
+ ::bluetooth::hal::HciHalHostRootcanalConfig::Get()->SetPort(std::stoi(port_number));
+ }
+ if (arg.find(arg_btsnoop_path) == 0) {
+ btsnoop_path = arg.substr(arg_btsnoop_path.size());
+ ::bluetooth::hal::SnoopLogger::SetFilePath(btsnoop_path);
+ }
+ if (arg.find(arg_signal_port) == 0) {
+ auto port_number = arg.substr(arg_signal_port.size());
+ signal_port = std::stoi(port_number);
+ }
+ }
+
+ signal(SIGINT, interrupt_handler);
+ grpc_root_server.StartServer("0.0.0.0", root_server_port, grpc_port);
+ int tester_signal_socket = socket(AF_INET, SOCK_STREAM, 0);
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(signal_port);
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ connect(tester_signal_socket, (sockaddr*)&addr, sizeof(addr));
+ close(tester_signal_socket);
+ auto wait_thread = std::thread([] { grpc_root_server.RunGrpcLoop(); });
+ wait_thread.join();
+
+ return 0;
+}
diff --git a/gd/cert/cert_testcases b/gd/cert/cert_testcases
new file mode 100644
index 0000000..2d59aa7
--- /dev/null
+++ b/gd/cert/cert_testcases
@@ -0,0 +1,3 @@
+SimpleHalTest
+SimpleHciTest
+SimpleL2capTest
\ No newline at end of file
diff --git a/gd/cert/event_stream.py b/gd/cert/event_stream.py
new file mode 100644
index 0000000..543438e
--- /dev/null
+++ b/gd/cert/event_stream.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 - 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.
+
+from acts import asserts
+
+from facade import common_pb2
+from datetime import datetime
+from datetime import timedelta
+from grpc import RpcError
+from grpc import StatusCode
+
+class EventStream(object):
+
+ def __init__(self, stream_stub_fn):
+ self.stream_stub_fn = stream_stub_fn
+ self.event_buffer = []
+
+ self.subscribe_request = common_pb2.EventStreamRequest(
+ subscription_mode=common_pb2.SUBSCRIBE,
+ fetch_mode=common_pb2.NONE
+ )
+
+ self.unsubscribe_request = common_pb2.EventStreamRequest(
+ subscription_mode=common_pb2.UNSUBSCRIBE,
+ fetch_mode=common_pb2.NONE
+ )
+
+ self.fetch_all_current_request = common_pb2.EventStreamRequest(
+ subscription_mode=common_pb2.UNCHANGED,
+ fetch_mode=common_pb2.ALL_CURRENT
+ )
+
+ self.fetch_at_least_one_request = lambda expiration_time : common_pb2.EventStreamRequest(
+ subscription_mode=common_pb2.UNCHANGED,
+ fetch_mode=common_pb2.AT_LEAST_ONE,
+ timeout_ms = int((expiration_time - datetime.now()).total_seconds() * 1000)
+ )
+
+ def clear_event_buffer(self):
+ self.event_buffer.clear()
+
+ def subscribe(self):
+ rpc = self.stream_stub_fn(self.subscribe_request)
+ return rpc.result()
+
+ def unsubscribe(self):
+ rpc = self.stream_stub_fn(self.unsubscribe_request)
+ return rpc.result()
+
+ def assert_none(self):
+ response = self.stream_stub_fn(self.fetch_all_current_request)
+
+ try:
+ for event in response:
+ self.event_buffer.append(event)
+ except RpcError:
+ pass
+
+ if len(self.event_buffer) != 0:
+ asserts.fail("event_buffer is not empty \n%s" % self.event_buffer)
+
+ def assert_none_matching(self, match_fn):
+ response = self.stream_stub_fn(self.fetch_all_current_request)
+
+ try:
+ for event in response:
+ self.event_buffer.append(event)
+ except RpcError:
+ pass
+
+ for event in self.event_buffer:
+ if match_fn(event):
+ asserts.fail("event %s occurs" % event)
+
+ def assert_event_occurs(self, match_fn, timeout=timedelta(seconds=3)):
+ expiration_time = datetime.now() + timeout
+
+ while len(self.event_buffer):
+ element = self.event_buffer.pop(0)
+ if match_fn(element):
+ return
+
+ while (True):
+ if datetime.now() > expiration_time:
+ asserts.fail("timeout of %s exceeded" % str(timeout))
+
+ response = self.stream_stub_fn(self.fetch_at_least_one_request(expiration_time))
+
+ try:
+ for event in response:
+ if (match_fn(event)):
+ for remain_event in response:
+ self.event_buffer.append(remain_event)
+ return
+ except RpcError:
+ if response.code() == StatusCode.DEADLINE_EXCEEDED:
+ continue
+ raise
diff --git a/gd/cert/gd_base_test.py b/gd/cert/gd_base_test.py
new file mode 100644
index 0000000..45c2077
--- /dev/null
+++ b/gd/cert/gd_base_test.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 - 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.
+
+from acts.base_test import BaseTestClass
+
+import importlib
+import logging
+import os
+import signal
+import sys
+import subprocess
+
+ANDROID_BUILD_TOP = os.environ.get('ANDROID_BUILD_TOP')
+
+sys.path.append(ANDROID_BUILD_TOP + '/out/soong/.intermediates/system/bt/gd/BluetoothFacadeAndCertGeneratedStub_py/gen')
+
+ANDROID_HOST_OUT = os.environ.get('ANDROID_HOST_OUT')
+ROOTCANAL = ANDROID_HOST_OUT + "/nativetest64/root-canal/root-canal"
+
+class GdBaseTestClass(BaseTestClass):
+ def __init__(self, configs):
+ BaseTestClass.__init__(self, configs)
+
+ log_path_base = configs.get('log_path', '/tmp/logs')
+ rootcanal_logpath = os.path.join(log_path_base, 'rootcanal_logs.txt')
+ self.rootcanal_logs = open(rootcanal_logpath, 'w')
+ gd_devices = self.testbed_configs.get("GdDevice")
+ gd_cert_devices = self.testbed_configs.get("GdCertDevice")
+
+ self.rootcanal_running = False
+ if 'rootcanal' in configs["testbed_configs"]:
+ self.rootcanal_running = True
+ rootcanal_config = configs["testbed_configs"]['rootcanal']
+ rootcanal_hci_port = str(rootcanal_config.get("hci_port", "6402"))
+ self.rootcanal_process = subprocess.Popen(
+ [
+ ROOTCANAL,
+ str(rootcanal_config.get("test_port", "6401")),
+ rootcanal_hci_port,
+ str(rootcanal_config.get("link_layer_port", "6403"))
+ ],
+ cwd=ANDROID_BUILD_TOP,
+ env=os.environ.copy(),
+ stdout=self.rootcanal_logs,
+ stderr=self.rootcanal_logs
+ )
+ for gd_device in gd_devices:
+ gd_device["rootcanal_port"] = rootcanal_hci_port
+ for gd_cert_device in gd_cert_devices:
+ gd_cert_device["rootcanal_port"] = rootcanal_hci_port
+
+ self.register_controller(
+ importlib.import_module('cert.gd_device'),
+ builtin=True)
+ self.register_controller(
+ importlib.import_module('cert.gd_cert_device'),
+ builtin=True)
+
+ def teardown_class(self):
+ if self.rootcanal_running:
+ self.rootcanal_process.send_signal(signal.SIGINT)
+ rootcanal_return_code = self.rootcanal_process.wait()
+ self.rootcanal_logs.close()
+ if rootcanal_return_code != 0 and\
+ rootcanal_return_code != -signal.SIGINT:
+ logging.error("rootcanal stopped with code: %d" %
+ rootcanal_return_code)
+ return False
diff --git a/gd/cert/gd_cert_device.py b/gd/cert/gd_cert_device.py
new file mode 100644
index 0000000..b579258
--- /dev/null
+++ b/gd/cert/gd_cert_device.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 - 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.
+
+from gd_device_base import GdDeviceBase
+from gd_device_base import replace_vars
+
+from cert.event_stream import EventStream
+from cert import rootservice_pb2_grpc as cert_rootservice_pb2_grpc
+from hal.cert import api_pb2_grpc as hal_cert_pb2_grpc
+from hci.cert import api_pb2_grpc as hci_cert_pb2_grpc
+from l2cap.classic.cert import api_pb2_grpc as l2cap_cert_pb2_grpc
+
+ACTS_CONTROLLER_CONFIG_NAME = "GdCertDevice"
+ACTS_CONTROLLER_REFERENCE_NAME = "gd_cert_devices"
+
+def create(configs):
+ if not configs:
+ raise GdDeviceConfigError("Configuration is empty")
+ elif not isinstance(configs, list):
+ raise GdDeviceConfigError("Configuration should be a list")
+ return get_instances_with_configs(configs)
+
+
+def destroy(devices):
+ for device in devices:
+ try:
+ device.clean_up()
+ except:
+ device.log.exception("Failed to clean up properly.")
+
+
+def get_info(devices):
+ return []
+
+
+def get_instances_with_configs(configs):
+ print(configs)
+ devices = []
+ for config in configs:
+ resolved_cmd = []
+ for entry in config["cmd"]:
+ resolved_cmd.append(replace_vars(entry, config))
+ devices.append(GdCertDevice(config["grpc_port"],
+ config["grpc_root_server_port"],
+ config["signal_port"],
+ resolved_cmd, config["label"]))
+ return devices
+
+class GdCertDevice(GdDeviceBase):
+ def __init__(self, grpc_port, grpc_root_server_port, signal_port, cmd, label):
+ super().__init__(grpc_port, grpc_root_server_port, signal_port, cmd,
+ label, ACTS_CONTROLLER_CONFIG_NAME)
+
+ # Cert stubs
+ self.rootservice = cert_rootservice_pb2_grpc.RootCertStub(self.grpc_root_server_channel)
+ self.hal = hal_cert_pb2_grpc.HciHalCertStub(self.grpc_channel)
+ self.controller_read_only_property = cert_rootservice_pb2_grpc.ReadOnlyPropertyStub(self.grpc_channel)
+ self.hci = hci_cert_pb2_grpc.AclManagerCertStub(self.grpc_channel)
+ self.l2cap = l2cap_cert_pb2_grpc.L2capClassicModuleCertStub(self.grpc_channel)
+
+ # Event streams
+ self.hal.hci_event_stream = EventStream(self.hal.FetchHciEvent)
+ self.hal.hci_acl_stream = EventStream(self.hal.FetchHciAcl)
+ self.hal.hci_sco_stream = EventStream(self.hal.FetchHciSco)
+ self.hci.connection_complete_stream = EventStream(self.hci.FetchConnectionComplete)
+ self.hci.disconnection_stream = EventStream(self.hci.FetchDisconnection)
+ self.hci.connection_failed_stream = EventStream(self.hci.FetchConnectionFailed)
+ self.hci.acl_stream = EventStream(self.hci.FetchAclData)
diff --git a/gd/cert/gd_device.py b/gd/cert/gd_device.py
new file mode 100644
index 0000000..17454f3
--- /dev/null
+++ b/gd/cert/gd_device.py
@@ -0,0 +1,85 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 - 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.
+
+from gd_device_base import GdDeviceBase
+from gd_device_base import replace_vars
+
+from cert.event_stream import EventStream
+from facade import rootservice_pb2_grpc as facade_rootservice_pb2_grpc
+from hal import facade_pb2_grpc as hal_facade_pb2_grpc
+from hci import facade_pb2_grpc as hci_facade_pb2_grpc
+from l2cap.classic import facade_pb2_grpc as l2cap_facade_pb2_grpc
+
+ACTS_CONTROLLER_CONFIG_NAME = "GdDevice"
+ACTS_CONTROLLER_REFERENCE_NAME = "gd_devices"
+
+def create(configs):
+ if not configs:
+ raise GdDeviceConfigError("Configuration is empty")
+ elif not isinstance(configs, list):
+ raise GdDeviceConfigError("Configuration should be a list")
+ return get_instances_with_configs(configs)
+
+
+def destroy(devices):
+ for device in devices:
+ try:
+ device.clean_up()
+ except:
+ device.log.exception("Failed to clean up properly.")
+
+
+def get_info(devices):
+ return []
+
+
+def get_instances_with_configs(configs):
+ print(configs)
+ devices = []
+ for config in configs:
+ resolved_cmd = []
+ for entry in config["cmd"]:
+ resolved_cmd.append(replace_vars(entry, config))
+ devices.append(GdDevice(config["grpc_port"],
+ config["grpc_root_server_port"],
+ config["signal_port"],
+ resolved_cmd, config["label"]))
+ return devices
+
+class GdDevice(GdDeviceBase):
+ def __init__(self, grpc_port, grpc_root_server_port, signal_port, cmd, label):
+ super().__init__(grpc_port, grpc_root_server_port, signal_port, cmd,
+ label, ACTS_CONTROLLER_CONFIG_NAME)
+
+ # Facade stubs
+ self.rootservice = facade_rootservice_pb2_grpc.RootFacadeStub(self.grpc_root_server_channel)
+ self.hal = hal_facade_pb2_grpc.HciHalFacadeStub(self.grpc_channel)
+ self.controller_read_only_property = facade_rootservice_pb2_grpc.ReadOnlyPropertyStub(self.grpc_channel)
+ self.hci = hci_facade_pb2_grpc.AclManagerFacadeStub(self.grpc_channel)
+ self.hci_classic_security = hci_facade_pb2_grpc.ClassicSecurityManagerFacadeStub(self.grpc_channel)
+ self.l2cap = l2cap_facade_pb2_grpc.L2capClassicModuleFacadeStub(self.grpc_channel)
+
+ # Event streams
+ self.hal.hci_event_stream = EventStream(self.hal.FetchHciEvent)
+ self.hal.hci_acl_stream = EventStream(self.hal.FetchHciAcl)
+ self.hal.hci_sco_stream = EventStream(self.hal.FetchHciSco)
+ self.hci.connection_complete_stream = EventStream(self.hci.FetchConnectionComplete)
+ self.hci.disconnection_stream = EventStream(self.hci.FetchDisconnection)
+ self.hci.connection_failed_stream = EventStream(self.hci.FetchConnectionFailed)
+ self.hci.acl_stream = EventStream(self.hci.FetchAclData)
+ self.hci_classic_security.command_complete_stream = EventStream(self.hci_classic_security.FetchCommandCompleteEvent)
+ self.l2cap.packet_stream = EventStream(self.l2cap.FetchL2capData)
+ self.l2cap.connection_complete_stream = EventStream(self.l2cap.FetchConnectionComplete)
diff --git a/gd/cert/gd_device_base.py b/gd/cert/gd_device_base.py
new file mode 100644
index 0000000..df5f9f2
--- /dev/null
+++ b/gd/cert/gd_device_base.py
@@ -0,0 +1,121 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 - 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.
+
+import logging
+import os
+from builtins import open
+import json
+import signal
+import socket
+import subprocess
+import time
+
+from acts import error
+from acts import tracelogger
+
+import grpc
+
+ANDROID_BUILD_TOP = os.environ.get('ANDROID_BUILD_TOP')
+ANDROID_HOST_OUT = os.environ.get('ANDROID_HOST_OUT')
+WAIT_CHANNEL_READY_TIMEOUT = 10
+
+def replace_vars(string, config):
+ serial_number = config.get("serial_number")
+ if serial_number is None:
+ serial_number = ""
+ rootcanal_port = config.get("rootcanal_port")
+ if rootcanal_port is None:
+ rootcanal_port = ""
+ return string.replace("$ANDROID_HOST_OUT", ANDROID_HOST_OUT) \
+ .replace("$(grpc_port)", config.get("grpc_port")) \
+ .replace("$(grpc_root_server_port)", config.get("grpc_root_server_port")) \
+ .replace("$(rootcanal_port)", rootcanal_port) \
+ .replace("$(signal_port)", config.get("signal_port")) \
+ .replace("$(serial_number)", serial_number)
+
+class GdDeviceBase:
+ def __init__(self, grpc_port, grpc_root_server_port, signal_port, cmd,
+ label, type_identifier):
+ self.label = label if label is not None else grpc_port
+ # logging.log_path only exists when this is used in an ACTS test run.
+ log_path_base = getattr(logging, 'log_path', '/tmp/logs')
+ self.log = tracelogger.TraceLogger(
+ GdDeviceBaseLoggerAdapter(logging.getLogger(), {
+ 'device': label,
+ 'type_identifier' : type_identifier
+ }))
+
+ backing_process_logpath = os.path.join(
+ log_path_base, '%s_%s_backing_logs.txt' % (type_identifier, label))
+ self.backing_process_logs = open(backing_process_logpath, 'w')
+
+ cmd_str = json.dumps(cmd)
+ if "--btsnoop=" not in cmd_str:
+ btsnoop_path = os.path.join(log_path_base, '%s_btsnoop_hci.log' % label)
+ cmd.append("--btsnoop=" + btsnoop_path)
+
+ tester_signal_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ tester_signal_socket.setsockopt(
+ socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+ socket_address = ('localhost', int(signal_port))
+ tester_signal_socket.bind(socket_address)
+ tester_signal_socket.listen(1)
+
+ self.backing_process = subprocess.Popen(
+ cmd,
+ cwd=ANDROID_BUILD_TOP,
+ env=os.environ.copy(),
+ stdout=self.backing_process_logs,
+ stderr=self.backing_process_logs)
+ tester_signal_socket.accept()
+ tester_signal_socket.close()
+
+ self.grpc_root_server_channel = grpc.insecure_channel("localhost:" + grpc_root_server_port)
+ self.grpc_port = int(grpc_port)
+ self.grpc_channel = grpc.insecure_channel("localhost:" + grpc_port)
+
+ def clean_up(self):
+ self.grpc_channel.close()
+ self.grpc_root_server_channel.close()
+ self.backing_process.send_signal(signal.SIGINT)
+ backing_process_return_code = self.backing_process.wait()
+ self.backing_process_logs.close()
+ if backing_process_return_code != 0:
+ logging.error("backing process %s stopped with code: %d" %
+ (self.label, backing_process_return_code))
+ return False
+
+ def wait_channel_ready(self):
+ future = grpc.channel_ready_future(self.grpc_channel)
+ try:
+ future.result(timeout = WAIT_CHANNEL_READY_TIMEOUT)
+ except grpc.FutureTimeoutError:
+ logging.error("wait channel ready timeout")
+
+
+
+class GdDeviceBaseLoggerAdapter(logging.LoggerAdapter):
+ def process(self, msg, kwargs):
+ msg = "[%s|%s] %s" % (self.extra["type_identifier"], self.extra["device"], msg)
+ return (msg, kwargs)
+
+class GdDeviceConfigError(Exception):
+ """Raised when GdDevice configs are malformatted."""
+
+
+class GdDeviceError(error.ActsError):
+ """Raised when there is an error in GdDevice."""
+
diff --git a/gd/cert/grpc_root_server.cc b/gd/cert/grpc_root_server.cc
new file mode 100644
index 0000000..48b2d5a
--- /dev/null
+++ b/gd/cert/grpc_root_server.cc
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2019 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 "cert/grpc_root_server.h"
+
+#include <string>
+
+#include "cert/read_only_property_server.h"
+#include "cert/rootservice.grpc.pb.h"
+#include "grpc/grpc_module.h"
+#include "hal/cert/cert.h"
+#include "hci/cert/cert.h"
+#include "l2cap/classic/cert/cert.h"
+#include "os/log.h"
+#include "os/thread.h"
+#include "stack_manager.h"
+
+namespace bluetooth {
+namespace cert {
+
+using ::bluetooth::grpc::GrpcModule;
+using ::bluetooth::os::Thread;
+
+namespace {
+class RootCertService : public ::bluetooth::cert::RootCert::Service {
+ public:
+ RootCertService(int grpc_port) : grpc_port_(grpc_port) {}
+
+ ::grpc::Status StartStack(::grpc::ServerContext* context, const ::bluetooth::cert::StartStackRequest* request,
+ ::bluetooth::cert::StartStackResponse* response) override {
+ if (is_running_) {
+ return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "stack is running");
+ }
+
+ ModuleList modules;
+ modules.add<::bluetooth::grpc::GrpcModule>();
+
+ BluetoothModule module_to_test = request->module_to_test();
+ switch (module_to_test) {
+ case BluetoothModule::HAL:
+ modules.add<::bluetooth::hal::cert::HalCertModule>();
+ break;
+ case BluetoothModule::HCI:
+ modules.add<::bluetooth::cert::ReadOnlyPropertyServerModule>();
+ modules.add<::bluetooth::hci::cert::AclManagerCertModule>();
+ break;
+ case BluetoothModule::L2CAP:
+ modules.add<::bluetooth::cert::ReadOnlyPropertyServerModule>();
+ modules.add<::bluetooth::l2cap::classic::cert::L2capClassicModuleCertModule>();
+ break;
+ default:
+ return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "invalid module under test");
+ }
+
+ stack_thread_ = new Thread("stack_thread", Thread::Priority::NORMAL);
+ stack_manager_.StartUp(&modules, stack_thread_);
+
+ GrpcModule* grpc_module = stack_manager_.GetInstance<GrpcModule>();
+ grpc_module->StartServer("0.0.0.0", grpc_port_);
+
+ grpc_loop_thread_ = new std::thread([grpc_module] { grpc_module->RunGrpcLoop(); });
+ is_running_ = true;
+
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status StopStack(::grpc::ServerContext* context, const ::bluetooth::cert::StopStackRequest* request,
+ ::bluetooth::cert::StopStackResponse* response) override {
+ if (!is_running_) {
+ return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "stack is not running");
+ }
+
+ stack_manager_.GetInstance<GrpcModule>()->StopServer();
+ grpc_loop_thread_->join();
+ delete grpc_loop_thread_;
+
+ stack_manager_.ShutDown();
+ delete stack_thread_;
+ is_running_ = false;
+ return ::grpc::Status::OK;
+ }
+
+ private:
+ Thread* stack_thread_ = nullptr;
+ bool is_running_ = false;
+ std::thread* grpc_loop_thread_ = nullptr;
+ StackManager stack_manager_;
+ int grpc_port_ = 8898;
+};
+
+RootCertService* root_cert_service;
+} // namespace
+
+void GrpcRootServer::StartServer(const std::string& address, int grpc_root_server_port, int grpc_port) {
+ ASSERT(!started_);
+ started_ = true;
+
+ std::string listening_port = address + ":" + std::to_string(grpc_root_server_port);
+ ::grpc::ServerBuilder builder;
+ root_cert_service = new RootCertService(grpc_port);
+ builder.RegisterService(root_cert_service);
+ builder.AddListeningPort(listening_port, ::grpc::InsecureServerCredentials());
+ server_ = builder.BuildAndStart();
+
+ ASSERT(server_ != nullptr);
+}
+
+void GrpcRootServer::StopServer() {
+ ASSERT(started_);
+ server_->Shutdown();
+ started_ = false;
+ server_.reset();
+ delete root_cert_service;
+}
+
+void GrpcRootServer::RunGrpcLoop() {
+ ASSERT(started_);
+ server_->Wait();
+}
+
+} // namespace cert
+} // namespace bluetooth
diff --git a/gd/cert/grpc_root_server.h b/gd/cert/grpc_root_server.h
new file mode 100644
index 0000000..2ebfe79
--- /dev/null
+++ b/gd/cert/grpc_root_server.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include <grpc++/grpc++.h>
+
+namespace bluetooth {
+namespace cert {
+
+class GrpcRootServer {
+ public:
+ void StartServer(const std::string& address, int grpc_root_server_port, int grpc_port);
+
+ void StopServer();
+
+ void RunGrpcLoop();
+
+ private:
+ bool started_ = false;
+ std::unique_ptr<::grpc::Server> server_ = nullptr;
+};
+
+} // namespace cert
+} // namespace bluetooth
diff --git a/gd/cert/host_only_config.json b/gd/cert/host_only_config.json
new file mode 100644
index 0000000..75e459c
--- /dev/null
+++ b/gd/cert/host_only_config.json
@@ -0,0 +1,50 @@
+{ "_description": "Bluetooth cert testing",
+ "testbed":
+ [
+ {
+ "_description": "Host only cert testbed",
+ "name": "HostOnlyCert",
+ "rootcanal":
+ {
+ "test_port": 6401,
+ "hci_port": 6402,
+ "link_layer_port": 6403
+ },
+ "GdDevice":
+ [
+ {
+ "grpc_port": "8899",
+ "grpc_root_server_port": "8897",
+ "signal_port": "8895",
+ "label": "stack_under_test",
+ "cmd":
+ [
+ "$ANDROID_HOST_OUT/bin/bluetooth_stack_with_facade",
+ "--grpc-port=$(grpc_port)",
+ "--root-server-port=$(grpc_root_server_port)",
+ "--rootcanal-port=$(rootcanal_port)",
+ "--signal-port=$(signal_port)"
+ ]
+ }
+ ],
+ "GdCertDevice":
+ [
+ {
+ "grpc_port": "8898",
+ "grpc_root_server_port": "8896",
+ "signal_port": "8894",
+ "label": "cert_stack",
+ "cmd":
+ [
+ "$ANDROID_HOST_OUT/bin/bluetooth_cert_stack",
+ "--grpc-port=$(grpc_port)",
+ "--root-server-port=$(grpc_root_server_port)",
+ "--rootcanal-port=$(rootcanal_port)",
+ "--signal-port=$(signal_port)"
+ ]
+ }
+ ]
+ }
+ ],
+ "logpath": "/tmp/logs"
+}
diff --git a/gd/cert/read_only_property_server.cc b/gd/cert/read_only_property_server.cc
new file mode 100644
index 0000000..d67c33e
--- /dev/null
+++ b/gd/cert/read_only_property_server.cc
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019 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 "cert/read_only_property_server.h"
+#include "hci/controller.h"
+
+namespace bluetooth {
+namespace cert {
+
+class ReadOnlyPropertyService : public ReadOnlyProperty::Service {
+ public:
+ ReadOnlyPropertyService(hci::Controller* controller) : controller_(controller) {}
+ ::grpc::Status ReadLocalAddress(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+ ::bluetooth::facade::BluetoothAddress* response) override {
+ auto address = controller_->GetControllerMacAddress().ToString();
+ response->set_address(address);
+ return ::grpc::Status::OK;
+ }
+
+ private:
+ hci::Controller* controller_;
+};
+
+void ReadOnlyPropertyServerModule::ListDependencies(ModuleList* list) {
+ GrpcFacadeModule::ListDependencies(list);
+ list->add<hci::Controller>();
+}
+void ReadOnlyPropertyServerModule::Start() {
+ GrpcFacadeModule::Start();
+ service_ = std::make_unique<ReadOnlyPropertyService>(GetDependency<hci::Controller>());
+}
+void ReadOnlyPropertyServerModule::Stop() {
+ service_.reset();
+ GrpcFacadeModule::Stop();
+}
+::grpc::Service* ReadOnlyPropertyServerModule::GetService() const {
+ return service_.get();
+}
+
+const ModuleFactory ReadOnlyPropertyServerModule::Factory =
+ ::bluetooth::ModuleFactory([]() { return new ReadOnlyPropertyServerModule(); });
+
+} // namespace cert
+} // namespace bluetooth
diff --git a/gd/cert/read_only_property_server.h b/gd/cert/read_only_property_server.h
new file mode 100644
index 0000000..e367537
--- /dev/null
+++ b/gd/cert/read_only_property_server.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <grpc++/grpc++.h>
+
+#include "cert/rootservice.grpc.pb.h"
+#include "grpc/grpc_module.h"
+
+namespace bluetooth {
+namespace cert {
+
+class ReadOnlyPropertyService;
+
+class ReadOnlyPropertyServerModule : public ::bluetooth::grpc::GrpcFacadeModule {
+ public:
+ static const ModuleFactory Factory;
+
+ void ListDependencies(ModuleList* list) override;
+ void Start() override;
+ void Stop() override;
+ ::grpc::Service* GetService() const override;
+
+ private:
+ std::unique_ptr<ReadOnlyPropertyService> service_;
+};
+
+} // namespace cert
+} // namespace bluetooth
diff --git a/gd/cert/rootservice.proto b/gd/cert/rootservice.proto
new file mode 100644
index 0000000..4472bfe
--- /dev/null
+++ b/gd/cert/rootservice.proto
@@ -0,0 +1,32 @@
+syntax = "proto3";
+
+package bluetooth.cert;
+
+import "google/protobuf/empty.proto";
+import "facade/common.proto";
+
+service RootCert {
+ rpc StartStack(StartStackRequest) returns (StartStackResponse) {}
+ rpc StopStack(StopStackRequest) returns (StopStackResponse) {}
+}
+
+enum BluetoothModule {
+ HAL = 0;
+ HCI = 1;
+ L2CAP = 2;
+ SECURITY = 3;
+}
+
+message StartStackRequest {
+ BluetoothModule module_to_test = 1;
+}
+
+message StartStackResponse {}
+
+message StopStackRequest {}
+
+message StopStackResponse {}
+
+service ReadOnlyProperty {
+ rpc ReadLocalAddress(google.protobuf.Empty) returns (facade.BluetoothAddress) {}
+}
diff --git a/gd/cert/run_cert.sh b/gd/cert/run_cert.sh
new file mode 100755
index 0000000..a85b994
--- /dev/null
+++ b/gd/cert/run_cert.sh
@@ -0,0 +1,5 @@
+#! /bin/bash
+
+# For bluetooth_packets_python3
+export PYTHONPATH=$PYTHONPATH:$ANDROID_BUILD_TOP/out/host/linux-x86/lib64
+python3.8 `which act.py` -c $ANDROID_BUILD_TOP/system/bt/gd/cert/host_only_config.json -tf $ANDROID_BUILD_TOP/system/bt/gd/cert/cert_testcases -tp $ANDROID_BUILD_TOP/system/bt/gd
diff --git a/gd/cert/run_device_cert.sh b/gd/cert/run_device_cert.sh
new file mode 100755
index 0000000..7566f65
--- /dev/null
+++ b/gd/cert/run_device_cert.sh
@@ -0,0 +1,5 @@
+#! /bin/bash
+
+# For bluetooth_packets_python3
+export PYTHONPATH=$PYTHONPATH:$ANDROID_BUILD_TOP/out/host/linux-x86/lib64
+python3.8 `which act.py` -c $ANDROID_BUILD_TOP/system/bt/gd/cert/android_devices_config.json -tf $ANDROID_BUILD_TOP/system/bt/gd/cert/cert_testcases -tp $ANDROID_BUILD_TOP/system/bt/gd
diff --git a/gd/cert/set_up_acts.sh b/gd/cert/set_up_acts.sh
new file mode 100755
index 0000000..ad4e775
--- /dev/null
+++ b/gd/cert/set_up_acts.sh
@@ -0,0 +1,110 @@
+#! /bin/bash
+#
+# Script to setup environment to execute bluetooth certification stack
+#
+# for more info, see go/acts
+
+## Android build main build setup script relative to top level android source root
+BUILD_SETUP=./build/envsetup.sh
+
+function UsageAndroidTree {
+ cat<<EOF
+Ensure invoked from within the android source tree
+EOF
+}
+
+function UsageSourcedNotExecuted {
+ cat<<EOF
+Ensure script is SOURCED and not executed to persist the build setup
+e.g.
+source $0
+EOF
+}
+
+function UpFind {
+ while [[ $PWD != / ]] ; do
+ rc=$(find "$PWD" -maxdepth 1 "$@")
+ if [ -n "$rc" ]; then
+ echo $(dirname "$rc")
+ return
+ fi
+ cd ..
+ done
+}
+
+function SetUpAndroidBuild {
+ pushd .
+ android_root=$(UpFind -name out -type d)
+ if [[ -z $android_root ]] ; then
+ UsageAndroidTree
+ return
+ fi
+ echo "Found android root $android_root"
+ cd $android_root && . $BUILD_SETUP
+ echo "Sourced build setup rules"
+ cd $android_root && lunch
+ popd
+}
+
+function SetupPython38 {
+ echo "Setting up python3.8"
+ sudo apt-get install python3.8-dev
+}
+
+function CompileBluetoothPacketsPython3 {
+ echo "bluetooth_packets_python3 is not found, compiling"
+ croot
+ make -j bluetooth_packets_python3
+}
+
+if [[ "${BASH_SOURCE[0]}" == "${0}" ]] ; then
+ UsageSourcedNotExecuted
+ exit 1
+fi
+
+if [[ -z "$ANDROID_BUILD_TOP" ]] ; then
+ SetUpAndroidBuild
+fi
+
+## Check python3.8 is installed properly
+## Need Python 3.8 because bluetooth_packets_python3 is compiled against
+## Python 3.8 headers
+dpkg -l python3.8-dev > /dev/null 2>&1
+if [[ $? -ne 0 ]] ; then
+ SetupPython38
+fi
+
+## Check bluetooth_packets_python3 is compiled succssfully
+export PYTHONPATH=$PYTHONPATH:$ANDROID_BUILD_TOP/out/host/linux-x86/lib64
+python3.8 -c "
+import bluetooth_packets_python3 as bp3
+bp3.BaseStruct
+"
+if [[ $? -ne 0 ]] ; then
+ pushd .
+ CompileBluetoothPacketsPython3
+ popd
+ python3.8 -c "
+import bluetooth_packets_python3 as bp3
+bp3.BaseStruct
+"
+ if [[ $? -ne 0 ]] ; then
+ echo "Setup failed as bluetooth_packets_python3 cannot be found"
+ else
+ echo "Found bluetooth_packets_python3 after compilation"
+ fi
+else
+ echo "Found bluetooth_packets_python3"
+fi
+
+## All is good now so go ahead with the acts setup
+pushd .
+cd $ANDROID_BUILD_TOP/tools/test/connectivity/acts/framework/
+sudo python3.8 setup.py develop
+if [[ $? -eq 0 ]] ; then
+ echo "cert setup complete"
+else
+ echo "cert setup failed"
+fi
+popd
+
diff --git a/gd/common/Android.bp b/gd/common/Android.bp
index 9d8c16d..c923427 100644
--- a/gd/common/Android.bp
+++ b/gd/common/Android.bp
@@ -1,15 +1,16 @@
filegroup {
name: "BluetoothCommonSources",
srcs: [
- "address.cc",
- "class_of_device.cc",
- ]
+ "link_key.cc",
+ ],
}
filegroup {
name: "BluetoothCommonTestSources",
srcs: [
- "address_unittest.cc",
- "class_of_device_unittest.cc",
- ]
+ "blocking_queue_unittest.cc",
+ "bidi_queue_unittest.cc",
+ "observer_registry_test.cc",
+ "link_key_unittest.cc",
+ ],
}
diff --git a/gd/common/address.cc b/gd/common/address.cc
deleted file mode 100644
index cd8101a..0000000
--- a/gd/common/address.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2019 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 "address.h"
-
-#include <stdint.h>
-#include <algorithm>
-#include <sstream>
-#include <vector>
-
-namespace bluetooth {
-namespace common {
-
-static_assert(sizeof(Address) == 6, "Address must be 6 bytes long!");
-
-const Address Address::kAny{{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};
-const Address Address::kEmpty{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
-
-Address::Address(const uint8_t (&addr)[6]) {
- std::copy(addr, addr + kLength, address);
-};
-
-std::string Address::ToString() const {
- char buffer[] = "00:00:00:00:00:00";
- std::snprintf(&buffer[0], sizeof(buffer),
- "%02x:%02x:%02x:%02x:%02x:%02x", address[5], address[4], address[3], address[2], address[1], address[0]);
- std::string str(buffer);
- return str;
-}
-
-bool Address::FromString(const std::string& from, Address& to) {
- Address new_addr;
- if (from.length() != 17) {
- return false;
- }
-
- std::istringstream stream(from);
- std::string token;
- int index = 0;
- while (getline(stream, token, ':')) {
- if (index >= 6) {
- return false;
- }
-
- if (token.length() != 2) {
- return false;
- }
-
- char* temp = nullptr;
- new_addr.address[5 - index] = strtol(token.c_str(), &temp, 16);
- if (*temp != '\0') {
- return false;
- }
-
- index++;
- }
-
- if (index != 6) {
- return false;
- }
-
- to = new_addr;
- return true;
-}
-
-size_t Address::FromOctets(const uint8_t* from) {
- std::copy(from, from + kLength, address);
- return kLength;
-};
-
-bool Address::IsValidAddress(const std::string& address) {
- Address tmp;
- return Address::FromString(address, tmp);
-}
-
-} // namespace common
-} // namespace bluetooth
diff --git a/gd/common/address.h b/gd/common/address.h
deleted file mode 100644
index 0036a59..0000000
--- a/gd/common/address.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2019 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.
- *
- ******************************************************************************/
-
-#pragma once
-
-#include <string>
-
-namespace bluetooth {
-namespace common {
-
-class Address final {
- public:
- static constexpr unsigned int kLength = 6;
-
- uint8_t address[kLength];
-
- Address() = default;
- Address(const uint8_t (&addr)[6]);
-
- bool operator<(const Address& rhs) const {
- return (std::memcmp(address, rhs.address, sizeof(address)) < 0);
- }
- bool operator==(const Address& rhs) const {
- return (std::memcmp(address, rhs.address, sizeof(address)) == 0);
- }
- bool operator>(const Address& rhs) const {
- return (rhs < *this);
- }
- bool operator<=(const Address& rhs) const {
- return !(*this > rhs);
- }
- bool operator>=(const Address& rhs) const {
- return !(*this < rhs);
- }
- bool operator!=(const Address& rhs) const {
- return !(*this == rhs);
- }
-
- bool IsEmpty() const {
- return *this == kEmpty;
- }
-
- std::string ToString() const;
-
- // Converts |string| to Address and places it in |to|. If |from| does
- // not represent a Bluetooth address, |to| is not modified and this function
- // returns false. Otherwise, it returns true.
- static bool FromString(const std::string& from, Address& to);
-
- // Copies |from| raw Bluetooth address octets to the local object.
- // Returns the number of copied octets - should be always Address::kLength
- size_t FromOctets(const uint8_t* from);
-
- static bool IsValidAddress(const std::string& address);
-
- static const Address kEmpty; // 00:00:00:00:00:00
- static const Address kAny; // FF:FF:FF:FF:FF:FF
-};
-
-inline std::ostream& operator<<(std::ostream& os, const Address& a) {
- os << a.ToString();
- return os;
-}
-
-} // namespace common
-} // namespace bluetooth
diff --git a/gd/common/address_unittest.cc b/gd/common/address_unittest.cc
deleted file mode 100644
index cdecce3..0000000
--- a/gd/common/address_unittest.cc
+++ /dev/null
@@ -1,199 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2019 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 <gtest/gtest.h>
-
-#include "common/address.h"
-
-using bluetooth::common::Address;
-
-static const char* test_addr = "bc:9a:78:56:34:12";
-static const char* test_addr2 = "21:43:65:87:a9:cb";
-
-TEST(AddressUnittest, test_constructor_array) {
- Address bdaddr({0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc});
-
- ASSERT_EQ(0x12, bdaddr.address[0]);
- ASSERT_EQ(0x34, bdaddr.address[1]);
- ASSERT_EQ(0x56, bdaddr.address[2]);
- ASSERT_EQ(0x78, bdaddr.address[3]);
- ASSERT_EQ(0x9A, bdaddr.address[4]);
- ASSERT_EQ(0xBC, bdaddr.address[5]);
-
- std::string ret = bdaddr.ToString();
-
- ASSERT_STREQ(test_addr, ret.c_str());
-}
-
-TEST(AddressUnittest, test_is_empty) {
- Address empty;
- Address::FromString("00:00:00:00:00:00", empty);
- ASSERT_TRUE(empty.IsEmpty());
-
- Address not_empty;
- Address::FromString("00:00:00:00:00:01", not_empty);
- ASSERT_FALSE(not_empty.IsEmpty());
-}
-
-TEST(AddressUnittest, test_to_from_str) {
- Address bdaddr;
- Address::FromString(test_addr, bdaddr);
-
- ASSERT_EQ(0x12, bdaddr.address[0]);
- ASSERT_EQ(0x34, bdaddr.address[1]);
- ASSERT_EQ(0x56, bdaddr.address[2]);
- ASSERT_EQ(0x78, bdaddr.address[3]);
- ASSERT_EQ(0x9A, bdaddr.address[4]);
- ASSERT_EQ(0xBC, bdaddr.address[5]);
-
- std::string ret = bdaddr.ToString();
-
- ASSERT_STREQ(test_addr, ret.c_str());
-}
-
-TEST(AddressUnittest, test_from_octets) {
- static const uint8_t test_addr_array[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc};
-
- Address bdaddr;
- size_t expected_result = Address::kLength;
- ASSERT_EQ(expected_result, bdaddr.FromOctets(test_addr_array));
-
- ASSERT_EQ(0x12, bdaddr.address[0]);
- ASSERT_EQ(0x34, bdaddr.address[1]);
- ASSERT_EQ(0x56, bdaddr.address[2]);
- ASSERT_EQ(0x78, bdaddr.address[3]);
- ASSERT_EQ(0x9A, bdaddr.address[4]);
- ASSERT_EQ(0xBC, bdaddr.address[5]);
-
- std::string ret = bdaddr.ToString();
-
- ASSERT_STREQ(test_addr, ret.c_str());
-}
-
-TEST(AddressTest, test_equals) {
- Address bdaddr1;
- Address bdaddr2;
- Address bdaddr3;
- Address::FromString(test_addr, bdaddr1);
- Address::FromString(test_addr, bdaddr2);
- EXPECT_TRUE(bdaddr1 == bdaddr2);
- EXPECT_FALSE(bdaddr1 != bdaddr2);
- EXPECT_TRUE(bdaddr1 == bdaddr1);
- EXPECT_FALSE(bdaddr1 != bdaddr1);
-
- Address::FromString(test_addr2, bdaddr3);
- EXPECT_FALSE(bdaddr2 == bdaddr3);
- EXPECT_TRUE(bdaddr2 != bdaddr3);
-}
-
-TEST(AddressTest, test_less_than) {
- Address bdaddr1;
- Address bdaddr2;
- Address bdaddr3;
- Address::FromString(test_addr, bdaddr1);
- Address::FromString(test_addr, bdaddr2);
- EXPECT_FALSE(bdaddr1 < bdaddr2);
- EXPECT_FALSE(bdaddr1 < bdaddr1);
-
- Address::FromString(test_addr2, bdaddr3);
- EXPECT_TRUE(bdaddr2 < bdaddr3);
- EXPECT_FALSE(bdaddr3 < bdaddr2);
-}
-
-TEST(AddressTest, test_more_than) {
- Address bdaddr1;
- Address bdaddr2;
- Address bdaddr3;
- Address::FromString(test_addr, bdaddr1);
- Address::FromString(test_addr, bdaddr2);
- EXPECT_FALSE(bdaddr1 > bdaddr2);
- EXPECT_FALSE(bdaddr1 > bdaddr1);
-
- Address::FromString(test_addr2, bdaddr3);
- EXPECT_FALSE(bdaddr2 > bdaddr3);
- EXPECT_TRUE(bdaddr3 > bdaddr2);
-}
-
-TEST(AddressTest, test_less_than_or_equal) {
- Address bdaddr1;
- Address bdaddr2;
- Address bdaddr3;
- Address::FromString(test_addr, bdaddr1);
- Address::FromString(test_addr, bdaddr2);
- EXPECT_TRUE(bdaddr1 <= bdaddr2);
- EXPECT_TRUE(bdaddr1 <= bdaddr1);
-
- Address::FromString(test_addr2, bdaddr3);
- EXPECT_TRUE(bdaddr2 <= bdaddr3);
- EXPECT_FALSE(bdaddr3 <= bdaddr2);
-}
-
-TEST(AddressTest, test_more_than_or_equal) {
- Address bdaddr1;
- Address bdaddr2;
- Address bdaddr3;
- Address::FromString(test_addr, bdaddr1);
- Address::FromString(test_addr, bdaddr2);
- EXPECT_TRUE(bdaddr1 >= bdaddr2);
- EXPECT_TRUE(bdaddr1 >= bdaddr1);
-
- Address::FromString(test_addr2, bdaddr3);
- EXPECT_FALSE(bdaddr2 >= bdaddr3);
- EXPECT_TRUE(bdaddr3 >= bdaddr2);
-}
-
-TEST(AddressTest, test_copy) {
- Address bdaddr1;
- Address bdaddr2;
- Address::FromString(test_addr, bdaddr1);
- bdaddr2 = bdaddr1;
-
- EXPECT_TRUE(bdaddr1 == bdaddr2);
-}
-
-TEST(AddressTest, IsValidAddress) {
- EXPECT_FALSE(Address::IsValidAddress(""));
- EXPECT_FALSE(Address::IsValidAddress("000000000000"));
- EXPECT_FALSE(Address::IsValidAddress("00:00:00:00:0000"));
- EXPECT_FALSE(Address::IsValidAddress("00:00:00:00:00:0"));
- EXPECT_FALSE(Address::IsValidAddress("00:00:00:00:00:0;"));
- EXPECT_TRUE(Address::IsValidAddress("00:00:00:00:00:00"));
- EXPECT_TRUE(Address::IsValidAddress("AB:cd:00:00:00:00"));
- EXPECT_FALSE(Address::IsValidAddress("aB:cD:eF:Gh:iJ:Kl"));
-}
-
-TEST(AddressTest, BdAddrFromString) {
- Address addr;
- memset(&addr, 0, sizeof(addr));
-
- EXPECT_TRUE(Address::FromString("00:00:00:00:00:00", addr));
- const Address result0 = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
- EXPECT_EQ(0, memcmp(&addr, &result0, sizeof(addr)));
-
- EXPECT_TRUE(Address::FromString("ab:01:4C:d5:21:9f", addr));
- const Address result1 = {{0x9f, 0x21, 0xd5, 0x4c, 0x01, 0xab}};
- EXPECT_EQ(0, memcmp(&addr, &result1, sizeof(addr)));
-}
-
-TEST(AddressTest, BdAddrFromStringToStringEquivalent) {
- std::string address = "c1:c2:c3:d1:d2:d3";
- Address addr;
-
- EXPECT_TRUE(Address::FromString(address, addr));
- EXPECT_EQ(addr.ToString(), address);
-}
diff --git a/gd/common/bidi_queue.h b/gd/common/bidi_queue.h
new file mode 100644
index 0000000..c108588
--- /dev/null
+++ b/gd/common/bidi_queue.h
@@ -0,0 +1,90 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "common/callback.h"
+#include "os/queue.h"
+
+namespace bluetooth {
+namespace common {
+
+template <typename TENQUEUE, typename TDEQUEUE>
+class BidiQueueEnd
+ : public ::bluetooth::os::IQueueEnqueue<TENQUEUE>,
+ public ::bluetooth::os::IQueueDequeue<TDEQUEUE> {
+ public:
+ using EnqueueCallback = Callback<std::unique_ptr<TENQUEUE>()>;
+ using DequeueCallback = Callback<void()>;
+
+ BidiQueueEnd(::bluetooth::os::IQueueEnqueue<TENQUEUE>* tx, ::bluetooth::os::IQueueDequeue<TDEQUEUE>* rx)
+ : tx_(tx), rx_(rx) {
+ }
+
+ void RegisterEnqueue(::bluetooth::os::Handler* handler, EnqueueCallback callback) override {
+ tx_->RegisterEnqueue(handler, callback);
+ }
+
+ void UnregisterEnqueue() override {
+ tx_->UnregisterEnqueue();
+ }
+
+ void RegisterDequeue(::bluetooth::os::Handler* handler, DequeueCallback callback) override {
+ rx_->RegisterDequeue(handler, callback);
+ }
+
+ void UnregisterDequeue() override {
+ rx_->UnregisterDequeue();
+ }
+
+ std::unique_ptr<TDEQUEUE> TryDequeue() override {
+ return rx_->TryDequeue();
+ }
+
+ private:
+ ::bluetooth::os::IQueueEnqueue<TENQUEUE>* tx_;
+ ::bluetooth::os::IQueueDequeue<TDEQUEUE>* rx_;
+};
+
+template <typename TUP, typename TDOWN>
+class BidiQueue {
+ public:
+ explicit BidiQueue(size_t capacity)
+ : up_queue_(capacity),
+ down_queue_(capacity),
+ up_end_(&down_queue_, &up_queue_),
+ down_end_(&up_queue_, &down_queue_) {
+ }
+
+ BidiQueueEnd<TDOWN, TUP>* GetUpEnd() {
+ return &up_end_;
+ }
+
+ BidiQueueEnd<TUP, TDOWN>* GetDownEnd() {
+ return &down_end_;
+ }
+
+ private:
+ ::bluetooth::os::Queue<TUP> up_queue_;
+ ::bluetooth::os::Queue<TDOWN> down_queue_;
+ BidiQueueEnd<TDOWN, TUP> up_end_;
+ BidiQueueEnd<TUP, TDOWN> down_end_;
+};
+
+} // namespace common
+} // namespace bluetooth
diff --git a/gd/common/bidi_queue_unittest.cc b/gd/common/bidi_queue_unittest.cc
new file mode 100644
index 0000000..7a5503c
--- /dev/null
+++ b/gd/common/bidi_queue_unittest.cc
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2019 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 "common/bidi_queue.h"
+
+#include <future>
+
+#include "common/bind.h"
+#include "gtest/gtest.h"
+#include "os/handler.h"
+#include "os/thread.h"
+
+using ::bluetooth::os::Thread;
+using ::bluetooth::os::Handler;
+
+namespace bluetooth {
+namespace common {
+namespace {
+
+class BidiQueueTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ up_thread_ = new Thread("up_thread", Thread::Priority::NORMAL);
+ up_handler_ = new Handler(up_thread_);
+ down_thread_ = new Thread("down_thread", Thread::Priority::NORMAL);
+ down_handler_ = new Handler(down_thread_);
+ }
+
+ void TearDown() override {
+ delete up_handler_;
+ delete up_thread_;
+ delete down_handler_;
+ delete down_thread_;
+ }
+
+ Thread* up_thread_;
+ Handler* up_handler_;
+ Thread* down_thread_;
+ Handler* down_handler_;
+};
+
+class A {
+};
+
+class B {
+};
+
+template <typename TA, typename TB>
+class TestBidiQueueEnd {
+ public:
+ explicit TestBidiQueueEnd(BidiQueueEnd<TA, TB>* end, Handler* handler)
+ : handler_(handler), end_(end) {}
+
+ ~TestBidiQueueEnd() {
+ handler_->Clear();
+ }
+
+ std::promise<void>* Send(TA* value) {
+ std::promise<void>* promise = new std::promise<void>();
+ handler_->Post(BindOnce(&TestBidiQueueEnd<TA, TB>::handle_send, common::Unretained(this), common::Unretained(value),
+ common::Unretained(promise)));
+ return promise;
+ }
+
+ std::promise<TB*>* Receive() {
+ std::promise<TB*>* promise = new std::promise<TB*>();
+ handler_->Post(
+ BindOnce(&TestBidiQueueEnd<TA, TB>::handle_receive, common::Unretained(this), common::Unretained(promise)));
+
+ return promise;
+ }
+
+ void handle_send(TA* value, std::promise<void>* promise) {
+ end_->RegisterEnqueue(handler_, Bind(&TestBidiQueueEnd<TA, TB>::handle_register_enqueue, common::Unretained(this),
+ common::Unretained(value), common::Unretained(promise)));
+ }
+
+ std::unique_ptr<TA> handle_register_enqueue(TA* value, std::promise<void>* promise) {
+ end_->UnregisterEnqueue();
+ promise->set_value();
+ return std::unique_ptr<TA>(value);
+ }
+
+ void handle_receive(std::promise<TB*>* promise) {
+ end_->RegisterDequeue(handler_, Bind(&TestBidiQueueEnd<TA, TB>::handle_register_dequeue, common::Unretained(this),
+ common::Unretained(promise)));
+ }
+
+ void handle_register_dequeue(std::promise<TB*>* promise) {
+ end_->UnregisterDequeue();
+ promise->set_value(end_->TryDequeue().get());
+ }
+
+ private:
+ Handler* handler_;
+ BidiQueueEnd<TA, TB>* end_;
+};
+
+TEST_F(BidiQueueTest, simple_test) {
+ BidiQueue<A, B> queue(100);
+ TestBidiQueueEnd<B, A> test_up(queue.GetUpEnd(), up_handler_);
+ TestBidiQueueEnd<A, B> test_down(queue.GetDownEnd(), down_handler_);
+
+ auto sending_b = new B();
+ auto promise_sending_b = test_up.Send(sending_b);
+ promise_sending_b->get_future().wait();
+ auto promise_receive_b = test_down.Receive();
+ EXPECT_EQ(promise_receive_b->get_future().get(), sending_b);
+ delete promise_receive_b;
+ delete promise_sending_b;
+
+ auto sending_a = new A();
+ auto promise_sending_a = test_down.Send(sending_a);
+ promise_sending_a->get_future().wait();
+ auto promise_receive_a = test_up.Receive();
+ EXPECT_EQ(promise_receive_a->get_future().get(), sending_a);
+ delete promise_receive_a;
+ delete promise_sending_a;
+}
+
+} // namespace
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/common/bind.h b/gd/common/bind.h
new file mode 100644
index 0000000..1adf16c
--- /dev/null
+++ b/gd/common/bind.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "base/bind.h"
+
+namespace bluetooth {
+namespace common {
+
+using base::Bind;
+using base::BindOnce;
+using base::ConstRef;
+using base::IgnoreResult;
+using base::Owned;
+using base::Passed;
+using base::RetainedRef;
+using base::Unretained;
+
+} // namespace common
+} // namespace bluetooth
diff --git a/gd/common/blocking_queue.h b/gd/common/blocking_queue.h
new file mode 100644
index 0000000..622ca08
--- /dev/null
+++ b/gd/common/blocking_queue.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+#include <queue>
+
+namespace bluetooth {
+namespace common {
+
+template <typename T>
+class BlockingQueue {
+ public:
+ void push(T data) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ queue_.push(std::move(data));
+ if (queue_.size() == 1) {
+ not_empty_.notify_all();
+ }
+ };
+
+ T take() {
+ std::unique_lock<std::mutex> lock(mutex_);
+ while (queue_.empty()) {
+ not_empty_.wait(lock);
+ }
+ T data = queue_.front();
+ queue_.pop();
+ return data;
+ };
+
+ // Returns true if take() will not block within a time period
+ bool wait_to_take(std::chrono::milliseconds time) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ while (queue_.empty()) {
+ if (not_empty_.wait_for(lock, time) == std::cv_status::timeout) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool empty() const {
+ std::unique_lock<std::mutex> lock(mutex_);
+ return queue_.empty();
+ };
+
+ void clear() {
+ std::unique_lock<std::mutex> lock(mutex_);
+ std::queue<T> empty;
+ std::swap(queue_, empty);
+ };
+
+ private:
+ std::queue<T> queue_;
+ mutable std::mutex mutex_;
+ std::condition_variable not_empty_;
+};
+
+} // namespace common
+} // namespace bluetooth
diff --git a/gd/common/blocking_queue_unittest.cc b/gd/common/blocking_queue_unittest.cc
new file mode 100644
index 0000000..57a6245
--- /dev/null
+++ b/gd/common/blocking_queue_unittest.cc
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2019 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 "common/blocking_queue.h"
+
+#include <thread>
+
+#include <gtest/gtest.h>
+
+namespace bluetooth {
+namespace common {
+namespace {
+class BlockingQueueTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ EXPECT_TRUE(queue_.empty());
+ }
+
+ // Postcondition for each test case: clear the blocking queue
+ void TearDown() override {
+ EXPECT_TRUE(queue_.empty());
+ }
+
+ BlockingQueue<int> queue_;
+};
+
+TEST_F(BlockingQueueTest, initial_empty) {
+ EXPECT_TRUE(queue_.empty());
+}
+
+TEST_F(BlockingQueueTest, same_thread_push_and_pop) {
+ int data = 1;
+ queue_.push(data);
+ EXPECT_FALSE(queue_.empty());
+ EXPECT_EQ(queue_.take(), data);
+ EXPECT_TRUE(queue_.empty());
+}
+
+TEST_F(BlockingQueueTest, same_thread_push_and_pop_sequential) {
+ for (int data = 0; data < 10; data++) {
+ queue_.push(data);
+ EXPECT_FALSE(queue_.empty());
+ EXPECT_EQ(queue_.take(), data);
+ EXPECT_TRUE(queue_.empty());
+ }
+}
+
+TEST_F(BlockingQueueTest, same_thread_push_and_pop_batch) {
+ for (int data = 0; data < 10; data++) {
+ queue_.push(data);
+ }
+ EXPECT_FALSE(queue_.empty());
+ for (int data = 0; data < 10; data++) {
+ EXPECT_EQ(queue_.take(), data);
+ }
+ EXPECT_TRUE(queue_.empty());
+}
+
+TEST_F(BlockingQueueTest, clear_queue) {
+ for (int data = 0; data < 10; data++) {
+ queue_.push(data);
+ }
+ EXPECT_FALSE(queue_.empty());
+ queue_.clear();
+ EXPECT_TRUE(queue_.empty());
+}
+
+TEST_F(BlockingQueueTest, wait_for_non_empty) {
+ int data = 1;
+ std::thread waiter_thread([this, data] { EXPECT_EQ(queue_.take(), data); });
+ queue_.push(data);
+ waiter_thread.join();
+ EXPECT_TRUE(queue_.empty());
+}
+
+TEST_F(BlockingQueueTest, wait_to_take_fail) {
+ EXPECT_FALSE(queue_.wait_to_take(std::chrono::milliseconds(3)));
+}
+
+TEST_F(BlockingQueueTest, wait_to_take_after_non_empty) {
+ int data = 1;
+ queue_.push(data);
+ EXPECT_TRUE(queue_.wait_to_take(std::chrono::milliseconds(3)));
+ queue_.clear();
+}
+
+TEST_F(BlockingQueueTest, wait_to_take_before_non_empty) {
+ int data = 1;
+ std::thread waiter_thread([this] { EXPECT_TRUE(queue_.wait_to_take(std::chrono::milliseconds(3))); });
+ queue_.push(data);
+ waiter_thread.join();
+ queue_.clear();
+}
+
+TEST_F(BlockingQueueTest, wait_for_non_empty_batch) {
+ std::thread waiter_thread([this] {
+ for (int data = 0; data < 10; data++) {
+ EXPECT_EQ(queue_.take(), data);
+ }
+ });
+ for (int data = 0; data < 10; data++) {
+ queue_.push(data);
+ }
+ waiter_thread.join();
+ EXPECT_TRUE(queue_.empty());
+}
+
+class VectorBlockingQueueTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ EXPECT_TRUE(queue_.empty());
+ }
+
+ // Postcondition for each test case: clear the blocking queue
+ void TearDown() override {
+ EXPECT_TRUE(queue_.empty());
+ }
+
+ BlockingQueue<std::vector<uint8_t>> queue_;
+};
+
+TEST_F(VectorBlockingQueueTest, same_thread_push_and_pop) {
+ std::vector<uint8_t> data = {1, 2, 3, 4, 5, 6};
+ queue_.push(data);
+ EXPECT_FALSE(queue_.empty());
+ EXPECT_EQ(queue_.take(), data);
+ EXPECT_TRUE(queue_.empty());
+}
+
+} // namespace
+} // namespace common
+} // namespace bluetooth
diff --git a/gd/common/callback.h b/gd/common/callback.h
new file mode 100644
index 0000000..b8be642
--- /dev/null
+++ b/gd/common/callback.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "base/callback.h"
+
+namespace bluetooth {
+namespace common {
+
+using base::Callback;
+using base::Closure;
+using base::OnceCallback;
+using base::OnceClosure;
+
+} // namespace common
+} // namespace bluetooth
diff --git a/gd/common/callback_list.h b/gd/common/callback_list.h
new file mode 100644
index 0000000..857b0c7
--- /dev/null
+++ b/gd/common/callback_list.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <utility>
+#include "base/callback_list.h"
+#include "os/handler.h"
+
+/* This file contains CallbackList implementation that will execute callback on provided Handler thread
+
+Example usage inside your class:
+
+private:
+ common::CallbackList<void(int)> callbacks_list_;
+public:
+ std::unique_ptr<common::CallbackList<void(int)>::Subscription> RegisterCallback(
+ const base::RepeatingCallback<void(int)>& cb, os::Handler* handler) {
+ return callbacks_list_.Add({cb, handler});
+ }
+
+ void NotifyAllCallbacks(int value) {
+ callbacks_list_.Notify(value);
+ }
+*/
+
+namespace bluetooth {
+namespace common {
+
+namespace {
+template <typename CallbackType>
+struct CallbackWithHandler {
+ CallbackWithHandler(base::RepeatingCallback<CallbackType> callback, os::Handler* handler)
+ : callback(callback), handler(handler) {}
+
+ bool is_null() const {
+ return callback.is_null();
+ }
+
+ void Reset() {
+ callback.Reset();
+ }
+
+ base::RepeatingCallback<CallbackType> callback;
+ os::Handler* handler;
+};
+
+} // namespace
+
+template <typename Sig>
+class CallbackList;
+template <typename... Args>
+class CallbackList<void(Args...)> : public base::internal::CallbackListBase<CallbackWithHandler<void(Args...)>> {
+ public:
+ using CallbackType = CallbackWithHandler<void(Args...)>;
+ CallbackList() = default;
+ template <typename... RunArgs>
+ void Notify(RunArgs&&... args) {
+ auto it = this->GetIterator();
+ CallbackType* cb;
+ while ((cb = it.GetNext()) != nullptr) {
+ cb->handler->Post(base::Bind(cb->callback, args...));
+ }
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CallbackList);
+};
+
+} // namespace common
+} // namespace bluetooth
diff --git a/gd/common/class_of_device.cc b/gd/common/class_of_device.cc
deleted file mode 100644
index 8d7ff68..0000000
--- a/gd/common/class_of_device.cc
+++ /dev/null
@@ -1,98 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2019 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 "class_of_device.h"
-
-#include <stdint.h>
-#include <algorithm>
-#include <sstream>
-#include <vector>
-
-#include "os/log.h"
-
-namespace bluetooth {
-namespace common {
-
-static_assert(sizeof(ClassOfDevice) == ClassOfDevice::kLength, "ClassOfDevice must be 3 bytes long!");
-
-ClassOfDevice::ClassOfDevice(const uint8_t (&class_of_device)[kLength]) {
- std::copy(class_of_device, class_of_device + kLength, cod);
-};
-
-std::string ClassOfDevice::ToString() const {
- char buffer[] = "000-0-00";
- std::snprintf(&buffer[0], sizeof(buffer),
- "%03x-%01x-%02x", (static_cast<uint16_t>(cod[2]) << 4) | cod[1] >> 4, cod[1] & 0x0f, cod[0]);
- std::string str(buffer);
- return str;
-
-}
-
-bool ClassOfDevice::FromString(const std::string& from, ClassOfDevice& to) {
- ClassOfDevice new_cod;
- if (from.length() != 8) return false;
-
- std::istringstream stream(from);
- std::string token;
- int index = 0;
- uint16_t values[3];
-
- while (getline(stream, token, '-')) {
- if (index >= 3) {
- return false;
- }
-
- if (index == 0 && token.length() != 3) {
- return false;
- } else if (index == 1 && token.length() != 1) {
- return false;
- } else if (index == 2 && token.length() != 2) {
- return false;
- }
- char* temp = nullptr;
- values[index] = strtol(token.c_str(), &temp, 16);
- if (*temp != '\0') {
- return false;
- }
-
- index++;
- }
-
- if (index != 3) {
- return false;
- }
-
- new_cod.cod[0] = values[2];
- new_cod.cod[1] = values[1] | ((values[0] & 0xf) << 4);
- new_cod.cod[2] = values[0] >> 4;
-
- to = new_cod;
- return true;
-}
-
-size_t ClassOfDevice::FromOctets(const uint8_t* from) {
- std::copy(from, from + kLength, cod);
- return kLength;
-};
-
-bool ClassOfDevice::IsValid(const std::string& cod) {
- ClassOfDevice tmp;
- return ClassOfDevice::FromString(cod, tmp);
-}
-} // namespace common
-} // namespace bluetooth
diff --git a/gd/common/class_of_device.h b/gd/common/class_of_device.h
deleted file mode 100644
index 983f128..0000000
--- a/gd/common/class_of_device.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2019 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.
- *
- ******************************************************************************/
-
-#pragma once
-
-#include <string>
-
-namespace bluetooth {
-namespace common {
-
-class ClassOfDevice final {
- public:
- static constexpr unsigned int kLength = 3;
-
- uint8_t cod[kLength];
-
- ClassOfDevice() = default;
- ClassOfDevice(const uint8_t (&class_of_device)[kLength]);
-
- bool operator==(const ClassOfDevice& rhs) const {
- return (std::memcmp(cod, rhs.cod, sizeof(cod)) == 0);
- }
-
- std::string ToString() const;
-
- // Converts |string| to ClassOfDevice and places it in |to|. If |from| does
- // not represent a Class of Device, |to| is not modified and this function
- // returns false. Otherwise, it returns true.
- static bool FromString(const std::string& from, ClassOfDevice& to);
-
- // Copies |from| raw Class of Device octets to the local object.
- // Returns the number of copied octets (always ClassOfDevice::kLength)
- size_t FromOctets(const uint8_t* from);
-
- static bool IsValid(const std::string& class_of_device);
-};
-
-inline std::ostream& operator<<(std::ostream& os, const ClassOfDevice& c) {
- os << c.ToString();
- return os;
-}
-
-} // namespace common
-} // namespace bluetooth
diff --git a/gd/common/class_of_device_unittest.cc b/gd/common/class_of_device_unittest.cc
deleted file mode 100644
index abd4a59..0000000
--- a/gd/common/class_of_device_unittest.cc
+++ /dev/null
@@ -1,98 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2019 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 <gtest/gtest.h>
-
-#include "common/class_of_device.h"
-
-using bluetooth::common::ClassOfDevice;
-
-static const char* test_class = "efc-d-ab";
-static const uint8_t test_bytes[]{0xab, 0xcd, 0xef};
-
-TEST(ClassOfDeviceUnittest, test_constructor_array) {
- ClassOfDevice cod(test_bytes);
-
- ASSERT_EQ(test_bytes[0], cod.cod[0]);
- ASSERT_EQ(test_bytes[1], cod.cod[1]);
- ASSERT_EQ(test_bytes[2], cod.cod[2]);
-
- std::string ret = cod.ToString();
-
- ASSERT_STREQ(test_class, ret.c_str());
-}
-
-TEST(ClassOfDeviceUnittest, test_to_from_str) {
- ClassOfDevice cod;
- ClassOfDevice::FromString(test_class, cod);
-
- ASSERT_EQ(test_bytes[0], cod.cod[0]);
- ASSERT_EQ(test_bytes[1], cod.cod[1]);
- ASSERT_EQ(test_bytes[2], cod.cod[2]);
-
- std::string ret = cod.ToString();
-
- ASSERT_STREQ(test_class, ret.c_str());
-}
-
-TEST(ClassOfDeviceUnittest, test_from_octets) {
- ClassOfDevice cod;
- size_t expected_result = ClassOfDevice::kLength;
- ASSERT_EQ(expected_result, cod.FromOctets(test_bytes));
-
- ASSERT_EQ(test_bytes[0], cod.cod[0]);
- ASSERT_EQ(test_bytes[1], cod.cod[1]);
- ASSERT_EQ(test_bytes[2], cod.cod[2]);
-
- std::string ret = cod.ToString();
-
- ASSERT_STREQ(test_class, ret.c_str());
-}
-
-TEST(ClassOfDeviceTest, test_copy) {
- ClassOfDevice cod1;
- ClassOfDevice cod2;
- ClassOfDevice::FromString(test_class, cod1);
- cod2 = cod1;
-
- ASSERT_EQ(cod1.cod[0], cod2.cod[0]);
- ASSERT_EQ(cod1.cod[1], cod2.cod[1]);
- ASSERT_EQ(cod1.cod[2], cod2.cod[2]);
-}
-
-TEST(ClassOfDeviceTest, IsValid) {
- EXPECT_FALSE(ClassOfDevice::IsValid(""));
- EXPECT_FALSE(ClassOfDevice::IsValid("000000"));
- EXPECT_FALSE(ClassOfDevice::IsValid("00-00-00"));
- EXPECT_FALSE(ClassOfDevice::IsValid("000-0-0"));
- EXPECT_TRUE(ClassOfDevice::IsValid("000-0-00"));
- EXPECT_TRUE(ClassOfDevice::IsValid("ABc-d-00"));
- EXPECT_TRUE(ClassOfDevice::IsValid("aBc-D-eF"));
-}
-
-TEST(ClassOfDeviceTest, classOfDeviceFromString) {
- ClassOfDevice cod;
-
- EXPECT_TRUE(ClassOfDevice::FromString("000-0-00", cod));
- const ClassOfDevice result0 = {{0x00, 0x00, 0x00}};
- EXPECT_EQ(0, memcmp(&cod, &result0, sizeof(cod)));
-
- EXPECT_TRUE(ClassOfDevice::FromString("ab2-1-4C", cod));
- const ClassOfDevice result1 = {{0x4c, 0x21, 0xab}};
- EXPECT_EQ(0, memcmp(&cod, &result1, sizeof(cod)));
-}
diff --git a/gd/common/link_key.cc b/gd/common/link_key.cc
new file mode 100644
index 0000000..12b60cd
--- /dev/null
+++ b/gd/common/link_key.cc
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "link_key.h"
+
+namespace bluetooth {
+namespace common {
+
+const LinkKey LinkKey::kExample{
+ {0x4C, 0x68, 0x38, 0x41, 0x39, 0xf5, 0x74, 0xd8, 0x36, 0xbc, 0xf3, 0x4e, 0x9d, 0xfb, 0x01, 0xbf}};
+
+LinkKey::LinkKey(const uint8_t (&data)[16]) {
+ std::copy(data, data + kLength, link_key);
+}
+
+std::string LinkKey::ToString() const {
+ char buffer[33] = "";
+ for (int i = 0; i < 16; i++) {
+ std::snprintf(&buffer[i * 2], 3, "%02x", link_key[i]);
+ }
+ std::string str(buffer);
+ return str;
+}
+
+bool LinkKey::FromString(const std::string& from, bluetooth::common::LinkKey& to) {
+ LinkKey new_link_key;
+
+ if (from.length() != 32) {
+ return false;
+ }
+
+ char* temp = nullptr;
+ for (int i = 0; i < 16; i++) {
+ new_link_key.link_key[i] = strtol(from.substr(i * 2, 2).c_str(), &temp, 16);
+ }
+
+ to = new_link_key;
+ return true;
+}
+
+} // namespace common
+} // namespace bluetooth
diff --git a/gd/common/link_key.h b/gd/common/link_key.h
new file mode 100644
index 0000000..b2bf394
--- /dev/null
+++ b/gd/common/link_key.h
@@ -0,0 +1,41 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <string>
+
+namespace bluetooth {
+namespace common {
+
+class LinkKey final {
+ public:
+ LinkKey() = default;
+ LinkKey(const uint8_t (&data)[16]);
+
+ static constexpr unsigned int kLength = 16;
+ uint8_t link_key[kLength];
+
+ std::string ToString() const;
+ static bool FromString(const std::string& from, LinkKey& to);
+
+ static const LinkKey kExample;
+};
+
+} // namespace common
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/common/link_key_unittest.cc b/gd/common/link_key_unittest.cc
new file mode 100644
index 0000000..6529564
--- /dev/null
+++ b/gd/common/link_key_unittest.cc
@@ -0,0 +1,50 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "common/link_key.h"
+#include <gtest/gtest.h>
+#include "os/log.h"
+
+using bluetooth::common::LinkKey;
+
+static const char* test_link_key = "4c68384139f574d836bcf34e9dfb01bf\0";
+
+TEST(LinkKeyUnittest, test_constructor_array) {
+ uint8_t data[LinkKey::kLength] = {0x4c, 0x87, 0x49, 0xe1, 0x2e, 0x55, 0x0f, 0x7f,
+ 0x60, 0x8b, 0x4f, 0x96, 0xd7, 0xc5, 0xbc, 0x2a};
+
+ LinkKey link_key(data);
+
+ for (int i = 0; i < LinkKey::kLength; i++) {
+ ASSERT_EQ(data[i], link_key.link_key[i]);
+ }
+}
+
+TEST(LinkKeyUnittest, test_from_str) {
+ LinkKey link_key;
+ LinkKey::FromString(test_link_key, link_key);
+
+ for (int i = 0; i < LinkKey::kLength; i++) {
+ ASSERT_EQ(LinkKey::kExample.link_key[i], link_key.link_key[i]);
+ }
+}
+
+TEST(LinkKeyUnittest, test_to_str) {
+ std::string str = LinkKey::kExample.ToString();
+ ASSERT_STREQ(str.c_str(), test_link_key);
+}
\ No newline at end of file
diff --git a/gd/common/observer_registry.h b/gd/common/observer_registry.h
new file mode 100644
index 0000000..99de57f
--- /dev/null
+++ b/gd/common/observer_registry.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <array>
+
+#include "common/bind.h"
+#include "common/callback.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace common {
+
+// Tracks an observer registration on client (observer) code. Register() returns a wrapped callback object which can
+// be passed to server's register API. Unregister() invalidates the wrapped callback so all callbacks that are posted
+// to the client handler after the client called Unregister() call and before the server processed the Unregister()
+// call on its handler, are dropped.
+// Note: Register() invalidates the previous registration.
+class SingleObserverRegistry {
+ public:
+ template <typename R, typename... T>
+ decltype(auto) Register(Callback<R(T...)> callback) {
+ session_++;
+ return Bind(&SingleObserverRegistry::callback_wrapper<R, T...>, Unretained(this), session_, callback);
+ }
+
+ void Unregister() {
+ session_++;
+ }
+
+ private:
+ template <typename R, typename... T>
+ void callback_wrapper(int session, Callback<R(T...)> callback, T... t) {
+ if (session == session_) {
+ callback.Run(std::forward<T>(t)...);
+ }
+ }
+
+ uint8_t session_ = 0;
+};
+
+// Tracks observer registration for multiple event type. Each event type is represented as an integer in [0, Capacity).
+template <int Capacity = 10>
+class MultipleObserverRegistry {
+ public:
+ template <typename R, typename... T>
+ decltype(auto) Register(int event_type, Callback<R(T...)> callback) {
+ ASSERT(event_type < Capacity);
+ return registry_[event_type].Register(callback);
+ }
+
+ void Unregister(int event_type) {
+ ASSERT(event_type < Capacity);
+ registry_[event_type].Unregister();
+ }
+
+ std::array<SingleObserverRegistry, Capacity> registry_;
+};
+
+} // namespace common
+} // namespace bluetooth
diff --git a/gd/common/observer_registry_test.cc b/gd/common/observer_registry_test.cc
new file mode 100644
index 0000000..f1233a8
--- /dev/null
+++ b/gd/common/observer_registry_test.cc
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2019 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 "common/observer_registry.h"
+
+#include "common/bind.h"
+#include "gtest/gtest.h"
+
+namespace bluetooth {
+namespace common {
+
+class SingleObserverRegistryTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ registry_ = new SingleObserverRegistry;
+ }
+
+ void TearDown() override {
+ delete registry_;
+ }
+
+ SingleObserverRegistry* registry_;
+};
+
+void Increment(int* count) {
+ (*count)++;
+}
+
+void IncrementBy(int* count, int n) {
+ (*count) += n;
+}
+
+TEST_F(SingleObserverRegistryTest, wrapped_callback) {
+ int count = 0;
+ auto wrapped_callback = registry_->Register(Bind(&Increment, Unretained(&count)));
+ wrapped_callback.Run();
+ EXPECT_EQ(count, 1);
+ wrapped_callback.Run();
+ EXPECT_EQ(count, 2);
+ wrapped_callback.Run();
+ EXPECT_EQ(count, 3);
+ registry_->Unregister();
+}
+
+TEST_F(SingleObserverRegistryTest, unregister) {
+ int count = 0;
+ auto wrapped_callback = registry_->Register(Bind(&Increment, Unretained(&count)));
+ registry_->Unregister();
+ wrapped_callback.Run();
+ EXPECT_EQ(count, 0);
+}
+
+TEST_F(SingleObserverRegistryTest, second_register) {
+ int count = 0;
+ auto wrapped_callback = registry_->Register(Bind(&Increment, Unretained(&count)));
+ registry_->Unregister();
+ auto wrapped_callback2 = registry_->Register(Bind(&Increment, Unretained(&count)));
+ wrapped_callback.Run();
+ EXPECT_EQ(count, 0);
+ wrapped_callback2.Run();
+ EXPECT_EQ(count, 1);
+}
+
+class MultipleObserverRegistryTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ registry_ = new MultipleObserverRegistry<2>;
+ }
+
+ void TearDown() override {
+ delete registry_;
+ }
+
+ MultipleObserverRegistry<2>* registry_;
+};
+
+TEST_F(MultipleObserverRegistryTest, single_wrapped_callback) {
+ int count = 0;
+ auto wrapped_callback = registry_->Register(0, Bind(&Increment, Unretained(&count)));
+ wrapped_callback.Run();
+ EXPECT_EQ(count, 1);
+ wrapped_callback.Run();
+ EXPECT_EQ(count, 2);
+ wrapped_callback.Run();
+ EXPECT_EQ(count, 3);
+ registry_->Unregister(0);
+}
+
+TEST_F(MultipleObserverRegistryTest, multiple_wrapped_callback) {
+ int count = 0;
+ auto wrapped_callback0 = registry_->Register(0, Bind(&Increment, Unretained(&count)));
+ auto wrapped_callback1 = registry_->Register(1, Bind(&IncrementBy, Unretained(&count), 10));
+ wrapped_callback0.Run();
+ EXPECT_EQ(count, 1);
+ wrapped_callback1.Run();
+ EXPECT_EQ(count, 11);
+ registry_->Unregister(0);
+ wrapped_callback0.Run();
+ EXPECT_EQ(count, 11);
+ wrapped_callback1.Run();
+ EXPECT_EQ(count, 21);
+ registry_->Unregister(1);
+ EXPECT_EQ(count, 21);
+}
+
+} // namespace common
+} // namespace bluetooth
diff --git a/gd/common/testing/bind_test_util.h b/gd/common/testing/bind_test_util.h
new file mode 100644
index 0000000..7db9204
--- /dev/null
+++ b/gd/common/testing/bind_test_util.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "base/test/bind_test_util.h"
+
+namespace bluetooth {
+namespace common {
+namespace testing {
+
+using base::BindLambdaForTesting;
+
+} // namespace testing
+} // namespace common
+} // namespace bluetooth
diff --git a/gd/common/testing/wired_pair_of_bidi_queues.h b/gd/common/testing/wired_pair_of_bidi_queues.h
new file mode 100644
index 0000000..92c6a1f
--- /dev/null
+++ b/gd/common/testing/wired_pair_of_bidi_queues.h
@@ -0,0 +1,97 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <memory>
+
+#include "common/bidi_queue.h"
+#include "os/handler.h"
+#include "packet/base_packet_builder.h"
+#include "packet/bit_inserter.h"
+#include "packet/packet_view.h"
+
+namespace bluetooth {
+namespace common {
+namespace testing {
+
+/* This class is a pair of BiDiQueues, that have down ends "wired" together. It can be used i.e. to mock L2cap
+ * interface, and provide two queues, where each sends packets of type A, and receives packets of type B */
+template <class A, class B, std::unique_ptr<B> (*A_TO_B)(std::unique_ptr<A>)>
+class WiredPairOfBiDiQueues {
+ void dequeue_callback_a() {
+ auto down_thing = queue_a_.GetDownEnd()->TryDequeue();
+ if (!down_thing) LOG_ERROR("Received dequeue, but no data ready...");
+
+ down_buffer_b_.Enqueue(A_TO_B(std::move(down_thing)), handler_);
+ }
+
+ void dequeue_callback_b() {
+ auto down_thing = queue_b_.GetDownEnd()->TryDequeue();
+ if (!down_thing) LOG_ERROR("Received dequeue, but no data ready...");
+
+ down_buffer_a_.Enqueue(A_TO_B(std::move(down_thing)), handler_);
+ }
+
+ os::Handler* handler_;
+ common::BidiQueue<B, A> queue_a_{10};
+ common::BidiQueue<B, A> queue_b_{10};
+ os::EnqueueBuffer<B> down_buffer_a_{queue_a_.GetDownEnd()};
+ os::EnqueueBuffer<B> down_buffer_b_{queue_b_.GetDownEnd()};
+
+ public:
+ WiredPairOfBiDiQueues(os::Handler* handler) : handler_(handler) {
+ queue_a_.GetDownEnd()->RegisterDequeue(
+ handler_, common::Bind(&WiredPairOfBiDiQueues::dequeue_callback_a, common::Unretained(this)));
+ queue_b_.GetDownEnd()->RegisterDequeue(
+ handler_, common::Bind(&WiredPairOfBiDiQueues::dequeue_callback_b, common::Unretained(this)));
+ }
+
+ ~WiredPairOfBiDiQueues() {
+ queue_a_.GetDownEnd()->UnregisterDequeue();
+ queue_b_.GetDownEnd()->UnregisterDequeue();
+ }
+
+ /* This methd returns the UpEnd of queue A */
+ common::BidiQueueEnd<A, B>* GetQueueAUpEnd() {
+ return queue_a_.GetUpEnd();
+ }
+
+ /* This methd returns the UpEnd of queue B */
+ common::BidiQueueEnd<A, B>* GetQueueBUpEnd() {
+ return queue_b_.GetUpEnd();
+ }
+};
+
+namespace {
+std::unique_ptr<packet::PacketView<packet::kLittleEndian>> BuilderToView(
+ std::unique_ptr<packet::BasePacketBuilder> up_thing) {
+ auto bytes = std::make_shared<std::vector<uint8_t>>();
+ bluetooth::packet::BitInserter i(*bytes);
+ bytes->reserve(up_thing->size());
+ up_thing->Serialize(i);
+ return std::make_unique<packet::PacketView<packet::kLittleEndian>>(bytes);
+}
+} // namespace
+
+using WiredPairOfL2capQueues =
+ WiredPairOfBiDiQueues<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>, BuilderToView>;
+
+} // namespace testing
+} // namespace common
+} // namespace bluetooth
diff --git a/gd/crypto_toolbox/Android.bp b/gd/crypto_toolbox/Android.bp
new file mode 100644
index 0000000..fd2e6ed
--- /dev/null
+++ b/gd/crypto_toolbox/Android.bp
@@ -0,0 +1,15 @@
+filegroup {
+ name: "BluetoothCryptoToolboxSources",
+ srcs: [
+ "aes.cc",
+ "aes_cmac.cc",
+ "crypto_toolbox.cc",
+ ]
+}
+
+filegroup {
+ name: "BluetoothCryptoToolboxTestSources",
+ srcs: [
+ "crypto_toolbox_test.cc",
+ ]
+}
\ No newline at end of file
diff --git a/gd/crypto_toolbox/aes.cc b/gd/crypto_toolbox/aes.cc
new file mode 100644
index 0000000..f53894e
--- /dev/null
+++ b/gd/crypto_toolbox/aes.cc
@@ -0,0 +1,950 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+ 1. source code distributions include the above copyright notice, this
+ list of conditions and the following disclaimer;
+
+ 2. binary distributions include the above copyright notice, this list
+ of conditions and the following disclaimer in their documentation;
+
+ 3. the name of the copyright holder is not used to endorse products
+ built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue 09/09/2006
+
+ This is an AES implementation that uses only 8-bit byte operations on the
+ cipher state (there are options to use 32-bit types if available).
+
+ The combination of mix columns and byte substitution used here is based on
+ that developed by Karl Malbrain. His contribution is acknowledged.
+ */
+
+/* define if you have a fast memcpy function on your system */
+#if 1
+#define HAVE_MEMCPY
+#include <string.h>
+#if 0
+#if defined(_MSC_VER)
+#include <intrin.h>
+#pragma intrinsic(memcpy)
+#endif
+#endif
+#endif
+
+#include <stdint.h>
+#include <stdlib.h>
+
+/* define if you have fast 32-bit types on your system */
+#if 1
+#define HAVE_UINT_32T
+#endif
+
+/* define if you don't want any tables */
+#if 1
+#define USE_TABLES
+#endif
+
+/* On Intel Core 2 duo VERSION_1 is faster */
+
+/* alternative versions (test for performance on your system) */
+#if 1
+#define VERSION_1
+#endif
+
+#include "aes.h"
+
+#if defined(HAVE_UINT_32T)
+typedef uint32_t uint_32t;
+#endif
+
+/* functions for finite field multiplication in the AES Galois field */
+
+#define WPOLY 0x011b
+#define BPOLY 0x1b
+#define DPOLY 0x008d
+
+#define f1(x) (x)
+#define f2(x) (((x) << 1) ^ ((((x) >> 7) & 1) * WPOLY))
+#define f4(x) \
+ (((x) << 2) ^ ((((x) >> 6) & 1) * WPOLY) ^ ((((x) >> 6) & 2) * WPOLY))
+#define f8(x) \
+ (((x) << 3) ^ ((((x) >> 5) & 1) * WPOLY) ^ ((((x) >> 5) & 2) * WPOLY) ^ \
+ ((((x) >> 5) & 4) * WPOLY))
+#define d2(x) (((x) >> 1) ^ ((x)&1 ? DPOLY : 0))
+
+#define f3(x) (f2(x) ^ (x))
+#define f9(x) (f8(x) ^ (x))
+#define fb(x) (f8(x) ^ f2(x) ^ (x))
+#define fd(x) (f8(x) ^ f4(x) ^ (x))
+#define fe(x) (f8(x) ^ f4(x) ^ f2(x))
+
+#if defined(USE_TABLES)
+
+#define sb_data(w) \
+ { /* S Box data values */ \
+ w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5), \
+ w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), \
+ w(0x76), w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), \
+ w(0x47), w(0xf0), w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), \
+ w(0xa4), w(0x72), w(0xc0), w(0xb7), w(0xfd), w(0x93), w(0x26), \
+ w(0x36), w(0x3f), w(0xf7), w(0xcc), w(0x34), w(0xa5), w(0xe5), \
+ w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15), w(0x04), w(0xc7), \
+ w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a), w(0x07), \
+ w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75), \
+ w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), \
+ w(0xa0), w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), \
+ w(0x2f), w(0x84), w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), \
+ w(0xfc), w(0xb1), w(0x5b), w(0x6a), w(0xcb), w(0xbe), w(0x39), \
+ w(0x4a), w(0x4c), w(0x58), w(0xcf), w(0xd0), w(0xef), w(0xaa), \
+ w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85), w(0x45), w(0xf9), \
+ w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8), w(0x51), \
+ w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5), \
+ w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), \
+ w(0xd2), w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), \
+ w(0x44), w(0x17), w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), \
+ w(0x5d), w(0x19), w(0x73), w(0x60), w(0x81), w(0x4f), w(0xdc), \
+ w(0x22), w(0x2a), w(0x90), w(0x88), w(0x46), w(0xee), w(0xb8), \
+ w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb), w(0xe0), w(0x32), \
+ w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c), w(0xc2), \
+ w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79), \
+ w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), \
+ w(0xa9), w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), \
+ w(0xae), w(0x08), w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), \
+ w(0xa6), w(0xb4), w(0xc6), w(0xe8), w(0xdd), w(0x74), w(0x1f), \
+ w(0x4b), w(0xbd), w(0x8b), w(0x8a), w(0x70), w(0x3e), w(0xb5), \
+ w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e), w(0x61), w(0x35), \
+ w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e), w(0xe1), \
+ w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94), \
+ w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), \
+ w(0xdf), w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), \
+ w(0x42), w(0x68), w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), \
+ w(0x54), w(0xbb), w(0x16) \
+ }
+
+#define isb_data(w) \
+ { /* inverse S Box data values */ \
+ w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38), \
+ w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), \
+ w(0xfb), w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), \
+ w(0xff), w(0x87), w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), \
+ w(0xde), w(0xe9), w(0xcb), w(0x54), w(0x7b), w(0x94), w(0x32), \
+ w(0xa6), w(0xc2), w(0x23), w(0x3d), w(0xee), w(0x4c), w(0x95), \
+ w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e), w(0x08), w(0x2e), \
+ w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2), w(0x76), \
+ w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25), \
+ w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), \
+ w(0x16), w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), \
+ w(0xb6), w(0x92), w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), \
+ w(0xed), w(0xb9), w(0xda), w(0x5e), w(0x15), w(0x46), w(0x57), \
+ w(0xa7), w(0x8d), w(0x9d), w(0x84), w(0x90), w(0xd8), w(0xab), \
+ w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a), w(0xf7), w(0xe4), \
+ w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06), w(0xd0), \
+ w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02), \
+ w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), \
+ w(0x6b), w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), \
+ w(0xdc), w(0xea), w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), \
+ w(0xb4), w(0xe6), w(0x73), w(0x96), w(0xac), w(0x74), w(0x22), \
+ w(0xe7), w(0xad), w(0x35), w(0x85), w(0xe2), w(0xf9), w(0x37), \
+ w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e), w(0x47), w(0xf1), \
+ w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89), w(0x6f), \
+ w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b), \
+ w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), \
+ w(0x20), w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), \
+ w(0x5a), w(0xf4), w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), \
+ w(0x07), w(0xc7), w(0x31), w(0xb1), w(0x12), w(0x10), w(0x59), \
+ w(0x27), w(0x80), w(0xec), w(0x5f), w(0x60), w(0x51), w(0x7f), \
+ w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d), w(0x2d), w(0xe5), \
+ w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef), w(0xa0), \
+ w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0), \
+ w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), \
+ w(0x61), w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), \
+ w(0xd6), w(0x26), w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), \
+ w(0x21), w(0x0c), w(0x7d) \
+ }
+
+#define mm_data(w) \
+ { /* basic data for forming finite field tables */ \
+ w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07), \
+ w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), \
+ w(0x0f), w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), \
+ w(0x16), w(0x17), w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), \
+ w(0x1d), w(0x1e), w(0x1f), w(0x20), w(0x21), w(0x22), w(0x23), \
+ w(0x24), w(0x25), w(0x26), w(0x27), w(0x28), w(0x29), w(0x2a), \
+ w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f), w(0x30), w(0x31), \
+ w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37), w(0x38), \
+ w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f), \
+ w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), \
+ w(0x47), w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), \
+ w(0x4e), w(0x4f), w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), \
+ w(0x55), w(0x56), w(0x57), w(0x58), w(0x59), w(0x5a), w(0x5b), \
+ w(0x5c), w(0x5d), w(0x5e), w(0x5f), w(0x60), w(0x61), w(0x62), \
+ w(0x63), w(0x64), w(0x65), w(0x66), w(0x67), w(0x68), w(0x69), \
+ w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f), w(0x70), \
+ w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77), \
+ w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), \
+ w(0x7f), w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), \
+ w(0x86), w(0x87), w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), \
+ w(0x8d), w(0x8e), w(0x8f), w(0x90), w(0x91), w(0x92), w(0x93), \
+ w(0x94), w(0x95), w(0x96), w(0x97), w(0x98), w(0x99), w(0x9a), \
+ w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f), w(0xa0), w(0xa1), \
+ w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7), w(0xa8), \
+ w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf), \
+ w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), \
+ w(0xb7), w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), \
+ w(0xbe), w(0xbf), w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), \
+ w(0xc5), w(0xc6), w(0xc7), w(0xc8), w(0xc9), w(0xca), w(0xcb), \
+ w(0xcc), w(0xcd), w(0xce), w(0xcf), w(0xd0), w(0xd1), w(0xd2), \
+ w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7), w(0xd8), w(0xd9), \
+ w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf), w(0xe0), \
+ w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7), \
+ w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), \
+ w(0xef), w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), \
+ w(0xf6), w(0xf7), w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), \
+ w(0xfd), w(0xfe), w(0xff) \
+ }
+
+static const uint_8t sbox[256] = sb_data(f1);
+static const uint_8t isbox[256] = isb_data(f1);
+
+static const uint_8t gfm2_sbox[256] = sb_data(f2);
+static const uint_8t gfm3_sbox[256] = sb_data(f3);
+
+static const uint_8t gfmul_9[256] = mm_data(f9);
+static const uint_8t gfmul_b[256] = mm_data(fb);
+static const uint_8t gfmul_d[256] = mm_data(fd);
+static const uint_8t gfmul_e[256] = mm_data(fe);
+
+#define s_box(x) sbox[(x)]
+#define is_box(x) isbox[(x)]
+#define gfm2_sb(x) gfm2_sbox[(x)]
+#define gfm3_sb(x) gfm3_sbox[(x)]
+#define gfm_9(x) gfmul_9[(x)]
+#define gfm_b(x) gfmul_b[(x)]
+#define gfm_d(x) gfmul_d[(x)]
+#define gfm_e(x) gfmul_e[(x)]
+
+#else
+
+/* this is the high bit of x right shifted by 1 */
+/* position. Since the starting polynomial has */
+/* 9 bits (0x11b), this right shift keeps the */
+/* values of all top bits within a byte */
+
+static uint_8t hibit(const uint_8t x) {
+ uint_8t r = (uint_8t)((x >> 1) | (x >> 2));
+
+ r |= (r >> 2);
+ r |= (r >> 4);
+ return (r + 1) >> 1;
+}
+
+/* return the inverse of the finite field element x */
+
+static uint_8t gf_inv(const uint_8t x) {
+ uint_8t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0;
+
+ if (x < 2) return x;
+
+ for (;;) {
+ if (n1)
+ while (n2 >= n1) /* divide polynomial p2 by p1 */
+ {
+ n2 /= n1; /* shift smaller polynomial left */
+ p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */
+ v2 ^= (v1 * n2); /* shift accumulated value and */
+ n2 = hibit(p2); /* add into result */
+ }
+ else
+ return v1;
+
+ if (n2) /* repeat with values swapped */
+ while (n1 >= n2) {
+ n1 /= n2;
+ p1 ^= p2 * n1;
+ v1 ^= v2 * n1;
+ n1 = hibit(p1);
+ }
+ else
+ return v2;
+ }
+}
+
+/* The forward and inverse affine transformations used in the S-box */
+uint_8t fwd_affine(const uint_8t x) {
+#if defined(HAVE_UINT_32T)
+ uint_32t w = x;
+ w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4);
+ return 0x63 ^ ((w ^ (w >> 8)) & 0xff);
+#else
+ return 0x63 ^ x ^ (x << 1) ^ (x << 2) ^ (x << 3) ^ (x << 4) ^ (x >> 7) ^
+ (x >> 6) ^ (x >> 5) ^ (x >> 4);
+#endif
+}
+
+uint_8t inv_affine(const uint_8t x) {
+#if defined(HAVE_UINT_32T)
+ uint_32t w = x;
+ w = (w << 1) ^ (w << 3) ^ (w << 6);
+ return 0x05 ^ ((w ^ (w >> 8)) & 0xff);
+#else
+ return 0x05 ^ (x << 1) ^ (x << 3) ^ (x << 6) ^ (x >> 7) ^ (x >> 5) ^ (x >> 2);
+#endif
+}
+
+#define s_box(x) fwd_affine(gf_inv(x))
+#define is_box(x) gf_inv(inv_affine(x))
+#define gfm2_sb(x) f2(s_box(x))
+#define gfm3_sb(x) f3(s_box(x))
+#define gfm_9(x) f9(x)
+#define gfm_b(x) fb(x)
+#define gfm_d(x) fd(x)
+#define gfm_e(x) fe(x)
+
+#endif
+
+#if defined(HAVE_MEMCPY)
+#define block_copy_nn(d, s, l) memcpy(d, s, l)
+#define block_copy(d, s) memcpy(d, s, N_BLOCK)
+#else
+#define block_copy_nn(d, s, l) copy_block_nn(d, s, l)
+#define block_copy(d, s) copy_block(d, s)
+#endif
+
+#if !defined(HAVE_MEMCPY)
+static void copy_block(void* d, const void* s) {
+#if defined(HAVE_UINT_32T)
+ ((uint_32t*)d)[0] = ((uint_32t*)s)[0];
+ ((uint_32t*)d)[1] = ((uint_32t*)s)[1];
+ ((uint_32t*)d)[2] = ((uint_32t*)s)[2];
+ ((uint_32t*)d)[3] = ((uint_32t*)s)[3];
+#else
+ ((uint_8t*)d)[0] = ((uint_8t*)s)[0];
+ ((uint_8t*)d)[1] = ((uint_8t*)s)[1];
+ ((uint_8t*)d)[2] = ((uint_8t*)s)[2];
+ ((uint_8t*)d)[3] = ((uint_8t*)s)[3];
+ ((uint_8t*)d)[4] = ((uint_8t*)s)[4];
+ ((uint_8t*)d)[5] = ((uint_8t*)s)[5];
+ ((uint_8t*)d)[6] = ((uint_8t*)s)[6];
+ ((uint_8t*)d)[7] = ((uint_8t*)s)[7];
+ ((uint_8t*)d)[8] = ((uint_8t*)s)[8];
+ ((uint_8t*)d)[9] = ((uint_8t*)s)[9];
+ ((uint_8t*)d)[10] = ((uint_8t*)s)[10];
+ ((uint_8t*)d)[11] = ((uint_8t*)s)[11];
+ ((uint_8t*)d)[12] = ((uint_8t*)s)[12];
+ ((uint_8t*)d)[13] = ((uint_8t*)s)[13];
+ ((uint_8t*)d)[14] = ((uint_8t*)s)[14];
+ ((uint_8t*)d)[15] = ((uint_8t*)s)[15];
+#endif
+}
+
+static void copy_block_nn(void* d, const void* s, uint_8t nn) {
+ while (nn--) *((uint_8t*)d)++ = *((uint_8t*)s)++;
+}
+#endif
+
+static void xor_block(void* d, const void* s) {
+#if defined(HAVE_UINT_32T)
+ ((uint_32t*)d)[0] ^= ((uint_32t*)s)[0];
+ ((uint_32t*)d)[1] ^= ((uint_32t*)s)[1];
+ ((uint_32t*)d)[2] ^= ((uint_32t*)s)[2];
+ ((uint_32t*)d)[3] ^= ((uint_32t*)s)[3];
+#else
+ ((uint_8t*)d)[0] ^= ((uint_8t*)s)[0];
+ ((uint_8t*)d)[1] ^= ((uint_8t*)s)[1];
+ ((uint_8t*)d)[2] ^= ((uint_8t*)s)[2];
+ ((uint_8t*)d)[3] ^= ((uint_8t*)s)[3];
+ ((uint_8t*)d)[4] ^= ((uint_8t*)s)[4];
+ ((uint_8t*)d)[5] ^= ((uint_8t*)s)[5];
+ ((uint_8t*)d)[6] ^= ((uint_8t*)s)[6];
+ ((uint_8t*)d)[7] ^= ((uint_8t*)s)[7];
+ ((uint_8t*)d)[8] ^= ((uint_8t*)s)[8];
+ ((uint_8t*)d)[9] ^= ((uint_8t*)s)[9];
+ ((uint_8t*)d)[10] ^= ((uint_8t*)s)[10];
+ ((uint_8t*)d)[11] ^= ((uint_8t*)s)[11];
+ ((uint_8t*)d)[12] ^= ((uint_8t*)s)[12];
+ ((uint_8t*)d)[13] ^= ((uint_8t*)s)[13];
+ ((uint_8t*)d)[14] ^= ((uint_8t*)s)[14];
+ ((uint_8t*)d)[15] ^= ((uint_8t*)s)[15];
+#endif
+}
+
+static void copy_and_key(void* d, const void* s, const void* k) {
+#if defined(HAVE_UINT_32T)
+ ((uint_32t*)d)[0] = ((uint_32t*)s)[0] ^ ((uint_32t*)k)[0];
+ ((uint_32t*)d)[1] = ((uint_32t*)s)[1] ^ ((uint_32t*)k)[1];
+ ((uint_32t*)d)[2] = ((uint_32t*)s)[2] ^ ((uint_32t*)k)[2];
+ ((uint_32t*)d)[3] = ((uint_32t*)s)[3] ^ ((uint_32t*)k)[3];
+#elif 1
+ ((uint_8t*)d)[0] = ((uint_8t*)s)[0] ^ ((uint_8t*)k)[0];
+ ((uint_8t*)d)[1] = ((uint_8t*)s)[1] ^ ((uint_8t*)k)[1];
+ ((uint_8t*)d)[2] = ((uint_8t*)s)[2] ^ ((uint_8t*)k)[2];
+ ((uint_8t*)d)[3] = ((uint_8t*)s)[3] ^ ((uint_8t*)k)[3];
+ ((uint_8t*)d)[4] = ((uint_8t*)s)[4] ^ ((uint_8t*)k)[4];
+ ((uint_8t*)d)[5] = ((uint_8t*)s)[5] ^ ((uint_8t*)k)[5];
+ ((uint_8t*)d)[6] = ((uint_8t*)s)[6] ^ ((uint_8t*)k)[6];
+ ((uint_8t*)d)[7] = ((uint_8t*)s)[7] ^ ((uint_8t*)k)[7];
+ ((uint_8t*)d)[8] = ((uint_8t*)s)[8] ^ ((uint_8t*)k)[8];
+ ((uint_8t*)d)[9] = ((uint_8t*)s)[9] ^ ((uint_8t*)k)[9];
+ ((uint_8t*)d)[10] = ((uint_8t*)s)[10] ^ ((uint_8t*)k)[10];
+ ((uint_8t*)d)[11] = ((uint_8t*)s)[11] ^ ((uint_8t*)k)[11];
+ ((uint_8t*)d)[12] = ((uint_8t*)s)[12] ^ ((uint_8t*)k)[12];
+ ((uint_8t*)d)[13] = ((uint_8t*)s)[13] ^ ((uint_8t*)k)[13];
+ ((uint_8t*)d)[14] = ((uint_8t*)s)[14] ^ ((uint_8t*)k)[14];
+ ((uint_8t*)d)[15] = ((uint_8t*)s)[15] ^ ((uint_8t*)k)[15];
+#else
+ block_copy(d, s);
+ xor_block(d, k);
+#endif
+}
+
+static void add_round_key(uint_8t d[N_BLOCK], const uint_8t k[N_BLOCK]) {
+ xor_block(d, k);
+}
+
+static void shift_sub_rows(uint_8t st[N_BLOCK]) {
+ uint_8t tt;
+
+ st[0] = s_box(st[0]);
+ st[4] = s_box(st[4]);
+ st[8] = s_box(st[8]);
+ st[12] = s_box(st[12]);
+
+ tt = st[1];
+ st[1] = s_box(st[5]);
+ st[5] = s_box(st[9]);
+ st[9] = s_box(st[13]);
+ st[13] = s_box(tt);
+
+ tt = st[2];
+ st[2] = s_box(st[10]);
+ st[10] = s_box(tt);
+ tt = st[6];
+ st[6] = s_box(st[14]);
+ st[14] = s_box(tt);
+
+ tt = st[15];
+ st[15] = s_box(st[11]);
+ st[11] = s_box(st[7]);
+ st[7] = s_box(st[3]);
+ st[3] = s_box(tt);
+}
+
+static void inv_shift_sub_rows(uint_8t st[N_BLOCK]) {
+ uint_8t tt;
+
+ st[0] = is_box(st[0]);
+ st[4] = is_box(st[4]);
+ st[8] = is_box(st[8]);
+ st[12] = is_box(st[12]);
+
+ tt = st[13];
+ st[13] = is_box(st[9]);
+ st[9] = is_box(st[5]);
+ st[5] = is_box(st[1]);
+ st[1] = is_box(tt);
+
+ tt = st[2];
+ st[2] = is_box(st[10]);
+ st[10] = is_box(tt);
+ tt = st[6];
+ st[6] = is_box(st[14]);
+ st[14] = is_box(tt);
+
+ tt = st[3];
+ st[3] = is_box(st[7]);
+ st[7] = is_box(st[11]);
+ st[11] = is_box(st[15]);
+ st[15] = is_box(tt);
+}
+
+#if defined(VERSION_1)
+static void mix_sub_columns(uint_8t dt[N_BLOCK]) {
+ uint_8t st[N_BLOCK];
+ block_copy(st, dt);
+#else
+static void mix_sub_columns(uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK]) {
+#endif
+ dt[0] = gfm2_sb(st[0]) ^ gfm3_sb(st[5]) ^ s_box(st[10]) ^ s_box(st[15]);
+ dt[1] = s_box(st[0]) ^ gfm2_sb(st[5]) ^ gfm3_sb(st[10]) ^ s_box(st[15]);
+ dt[2] = s_box(st[0]) ^ s_box(st[5]) ^ gfm2_sb(st[10]) ^ gfm3_sb(st[15]);
+ dt[3] = gfm3_sb(st[0]) ^ s_box(st[5]) ^ s_box(st[10]) ^ gfm2_sb(st[15]);
+
+ dt[4] = gfm2_sb(st[4]) ^ gfm3_sb(st[9]) ^ s_box(st[14]) ^ s_box(st[3]);
+ dt[5] = s_box(st[4]) ^ gfm2_sb(st[9]) ^ gfm3_sb(st[14]) ^ s_box(st[3]);
+ dt[6] = s_box(st[4]) ^ s_box(st[9]) ^ gfm2_sb(st[14]) ^ gfm3_sb(st[3]);
+ dt[7] = gfm3_sb(st[4]) ^ s_box(st[9]) ^ s_box(st[14]) ^ gfm2_sb(st[3]);
+
+ dt[8] = gfm2_sb(st[8]) ^ gfm3_sb(st[13]) ^ s_box(st[2]) ^ s_box(st[7]);
+ dt[9] = s_box(st[8]) ^ gfm2_sb(st[13]) ^ gfm3_sb(st[2]) ^ s_box(st[7]);
+ dt[10] = s_box(st[8]) ^ s_box(st[13]) ^ gfm2_sb(st[2]) ^ gfm3_sb(st[7]);
+ dt[11] = gfm3_sb(st[8]) ^ s_box(st[13]) ^ s_box(st[2]) ^ gfm2_sb(st[7]);
+
+ dt[12] = gfm2_sb(st[12]) ^ gfm3_sb(st[1]) ^ s_box(st[6]) ^ s_box(st[11]);
+ dt[13] = s_box(st[12]) ^ gfm2_sb(st[1]) ^ gfm3_sb(st[6]) ^ s_box(st[11]);
+ dt[14] = s_box(st[12]) ^ s_box(st[1]) ^ gfm2_sb(st[6]) ^ gfm3_sb(st[11]);
+ dt[15] = gfm3_sb(st[12]) ^ s_box(st[1]) ^ s_box(st[6]) ^ gfm2_sb(st[11]);
+}
+
+#if defined(VERSION_1)
+static void inv_mix_sub_columns(uint_8t dt[N_BLOCK]) {
+ uint_8t st[N_BLOCK];
+ block_copy(st, dt);
+#else
+static void inv_mix_sub_columns(uint_8t dt[N_BLOCK], uint_8t st[N_BLOCK]) {
+#endif
+ dt[0] = is_box(gfm_e(st[0]) ^ gfm_b(st[1]) ^ gfm_d(st[2]) ^ gfm_9(st[3]));
+ dt[5] = is_box(gfm_9(st[0]) ^ gfm_e(st[1]) ^ gfm_b(st[2]) ^ gfm_d(st[3]));
+ dt[10] = is_box(gfm_d(st[0]) ^ gfm_9(st[1]) ^ gfm_e(st[2]) ^ gfm_b(st[3]));
+ dt[15] = is_box(gfm_b(st[0]) ^ gfm_d(st[1]) ^ gfm_9(st[2]) ^ gfm_e(st[3]));
+
+ dt[4] = is_box(gfm_e(st[4]) ^ gfm_b(st[5]) ^ gfm_d(st[6]) ^ gfm_9(st[7]));
+ dt[9] = is_box(gfm_9(st[4]) ^ gfm_e(st[5]) ^ gfm_b(st[6]) ^ gfm_d(st[7]));
+ dt[14] = is_box(gfm_d(st[4]) ^ gfm_9(st[5]) ^ gfm_e(st[6]) ^ gfm_b(st[7]));
+ dt[3] = is_box(gfm_b(st[4]) ^ gfm_d(st[5]) ^ gfm_9(st[6]) ^ gfm_e(st[7]));
+
+ dt[8] = is_box(gfm_e(st[8]) ^ gfm_b(st[9]) ^ gfm_d(st[10]) ^ gfm_9(st[11]));
+ dt[13] = is_box(gfm_9(st[8]) ^ gfm_e(st[9]) ^ gfm_b(st[10]) ^ gfm_d(st[11]));
+ dt[2] = is_box(gfm_d(st[8]) ^ gfm_9(st[9]) ^ gfm_e(st[10]) ^ gfm_b(st[11]));
+ dt[7] = is_box(gfm_b(st[8]) ^ gfm_d(st[9]) ^ gfm_9(st[10]) ^ gfm_e(st[11]));
+
+ dt[12] =
+ is_box(gfm_e(st[12]) ^ gfm_b(st[13]) ^ gfm_d(st[14]) ^ gfm_9(st[15]));
+ dt[1] = is_box(gfm_9(st[12]) ^ gfm_e(st[13]) ^ gfm_b(st[14]) ^ gfm_d(st[15]));
+ dt[6] = is_box(gfm_d(st[12]) ^ gfm_9(st[13]) ^ gfm_e(st[14]) ^ gfm_b(st[15]));
+ dt[11] =
+ is_box(gfm_b(st[12]) ^ gfm_d(st[13]) ^ gfm_9(st[14]) ^ gfm_e(st[15]));
+}
+
+#if defined(AES_ENC_PREKEYED) || defined(AES_DEC_PREKEYED)
+
+/* Set the cipher key for the pre-keyed version */
+/* NOTE: If the length_type used for the key length is an
+ unsigned 8-bit character, a key length of 256 bits must
+ be entered as a length in bytes (valid inputs are hence
+ 128, 192, 16, 24 and 32).
+*/
+
+return_type aes_set_key(const unsigned char key[], length_type keylen,
+ aes_context ctx[1]) {
+ uint_8t cc, rc, hi;
+
+ switch (keylen) {
+ case 16:
+ case 128: /* length in bits (128 = 8*16) */
+ keylen = 16;
+ break;
+ case 24:
+ case 192: /* length in bits (192 = 8*24) */
+ keylen = 24;
+ break;
+ case 32:
+ /* case 256: length in bits (256 = 8*32) */
+ keylen = 32;
+ break;
+ default:
+ ctx->rnd = 0;
+ return (return_type)-1;
+ }
+ block_copy_nn(ctx->ksch, key, keylen);
+ hi = (keylen + 28) << 2;
+ ctx->rnd = (hi >> 4) - 1;
+ for (cc = keylen, rc = 1; cc < hi; cc += 4) {
+ uint_8t tt, t0, t1, t2, t3;
+
+ t0 = ctx->ksch[cc - 4];
+ t1 = ctx->ksch[cc - 3];
+ t2 = ctx->ksch[cc - 2];
+ t3 = ctx->ksch[cc - 1];
+ if (cc % keylen == 0) {
+ tt = t0;
+ t0 = s_box(t1) ^ rc;
+ t1 = s_box(t2);
+ t2 = s_box(t3);
+ t3 = s_box(tt);
+ rc = f2(rc);
+ } else if (keylen > 24 && cc % keylen == 16) {
+ t0 = s_box(t0);
+ t1 = s_box(t1);
+ t2 = s_box(t2);
+ t3 = s_box(t3);
+ }
+ tt = cc - keylen;
+ ctx->ksch[cc + 0] = ctx->ksch[tt + 0] ^ t0;
+ ctx->ksch[cc + 1] = ctx->ksch[tt + 1] ^ t1;
+ ctx->ksch[cc + 2] = ctx->ksch[tt + 2] ^ t2;
+ ctx->ksch[cc + 3] = ctx->ksch[tt + 3] ^ t3;
+ }
+ return 0;
+}
+
+#endif
+
+#if defined(AES_ENC_PREKEYED)
+
+/* Encrypt a single block of 16 bytes */
+
+return_type aes_encrypt(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK], const aes_context ctx[1]) {
+ if (ctx->rnd) {
+ uint_8t s1[N_BLOCK], r;
+ copy_and_key(s1, in, ctx->ksch);
+
+ for (r = 1; r < ctx->rnd; ++r)
+#if defined(VERSION_1)
+ {
+ mix_sub_columns(s1);
+ add_round_key(s1, ctx->ksch + r * N_BLOCK);
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ mix_sub_columns(s2, s1);
+ copy_and_key(s1, s2, ctx->ksch + r * N_BLOCK);
+ }
+#endif
+ shift_sub_rows(s1);
+ copy_and_key(out, s1, ctx->ksch + r * N_BLOCK);
+ } else
+ return (return_type)-1;
+ return 0;
+}
+
+/* CBC encrypt a number of blocks (input and return an IV) */
+
+return_type aes_cbc_encrypt(const unsigned char* in, unsigned char* out,
+ int n_block, unsigned char iv[N_BLOCK],
+ const aes_context ctx[1]) {
+ while (n_block--) {
+ xor_block(iv, in);
+ if (aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
+ memcpy(out, iv, N_BLOCK);
+ in += N_BLOCK;
+ out += N_BLOCK;
+ }
+ return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined(AES_DEC_PREKEYED)
+
+/* Decrypt a single block of 16 bytes */
+
+return_type aes_decrypt(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK], const aes_context ctx[1]) {
+ if (ctx->rnd) {
+ uint_8t s1[N_BLOCK], r;
+ copy_and_key(s1, in, ctx->ksch + ctx->rnd * N_BLOCK);
+ inv_shift_sub_rows(s1);
+
+ for (r = ctx->rnd; --r;)
+#if defined(VERSION_1)
+ {
+ add_round_key(s1, ctx->ksch + r * N_BLOCK);
+ inv_mix_sub_columns(s1);
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ copy_and_key(s2, s1, ctx->ksch + r * N_BLOCK);
+ inv_mix_sub_columns(s1, s2);
+ }
+#endif
+ copy_and_key(out, s1, ctx->ksch);
+ } else
+ return (return_type)-1;
+ return 0;
+}
+
+/* CBC decrypt a number of blocks (input and return an IV) */
+
+return_type aes_cbc_decrypt(const unsigned char* in, unsigned char* out,
+ int n_block, unsigned char iv[N_BLOCK],
+ const aes_context ctx[1]) {
+ while (n_block--) {
+ uint_8t tmp[N_BLOCK];
+
+ memcpy(tmp, in, N_BLOCK);
+ if (aes_decrypt(in, out, ctx) != EXIT_SUCCESS) return EXIT_FAILURE;
+ xor_block(out, iv);
+ memcpy(iv, tmp, N_BLOCK);
+ in += N_BLOCK;
+ out += N_BLOCK;
+ }
+ return EXIT_SUCCESS;
+}
+
+#endif
+
+#if defined(AES_ENC_128_OTFK)
+
+/* The 'on the fly' encryption key update for for 128 bit keys */
+
+static void update_encrypt_key_128(uint_8t k[N_BLOCK], uint_8t* rc) {
+ uint_8t cc;
+
+ k[0] ^= s_box(k[13]) ^ *rc;
+ k[1] ^= s_box(k[14]);
+ k[2] ^= s_box(k[15]);
+ k[3] ^= s_box(k[12]);
+ *rc = f2(*rc);
+
+ for (cc = 4; cc < 16; cc += 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+}
+
+/* Encrypt a single block of 16 bytes with 'on the fly' 128 bit keying */
+
+void aes_encrypt_128(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[N_BLOCK],
+ unsigned char o_key[N_BLOCK]) {
+ uint_8t s1[N_BLOCK], r, rc = 1;
+
+ if (o_key != key) block_copy(o_key, key);
+ copy_and_key(s1, in, o_key);
+
+ for (r = 1; r < 10; ++r)
+#if defined(VERSION_1)
+ {
+ mix_sub_columns(s1);
+ update_encrypt_key_128(o_key, &rc);
+ add_round_key(s1, o_key);
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ mix_sub_columns(s2, s1);
+ update_encrypt_key_128(o_key, &rc);
+ copy_and_key(s1, s2, o_key);
+ }
+#endif
+
+ shift_sub_rows(s1);
+ update_encrypt_key_128(o_key, &rc);
+ copy_and_key(out, s1, o_key);
+}
+
+#endif
+
+#if defined(AES_DEC_128_OTFK)
+
+/* The 'on the fly' decryption key update for for 128 bit keys */
+
+static void update_decrypt_key_128(uint_8t k[N_BLOCK], uint_8t* rc) {
+ uint_8t cc;
+
+ for (cc = 12; cc > 0; cc -= 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+ *rc = d2(*rc);
+ k[0] ^= s_box(k[13]) ^ *rc;
+ k[1] ^= s_box(k[14]);
+ k[2] ^= s_box(k[15]);
+ k[3] ^= s_box(k[12]);
+}
+
+/* Decrypt a single block of 16 bytes with 'on the fly' 128 bit keying */
+
+void aes_decrypt_128(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[N_BLOCK],
+ unsigned char o_key[N_BLOCK]) {
+ uint_8t s1[N_BLOCK], r, rc = 0x6c;
+ if (o_key != key) block_copy(o_key, key);
+
+ copy_and_key(s1, in, o_key);
+ inv_shift_sub_rows(s1);
+
+ for (r = 10; --r;)
+#if defined(VERSION_1)
+ {
+ update_decrypt_key_128(o_key, &rc);
+ add_round_key(s1, o_key);
+ inv_mix_sub_columns(s1);
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ update_decrypt_key_128(o_key, &rc);
+ copy_and_key(s2, s1, o_key);
+ inv_mix_sub_columns(s1, s2);
+ }
+#endif
+ update_decrypt_key_128(o_key, &rc);
+ copy_and_key(out, s1, o_key);
+}
+
+#endif
+
+#if defined(AES_ENC_256_OTFK)
+
+/* The 'on the fly' encryption key update for for 256 bit keys */
+
+static void update_encrypt_key_256(uint_8t k[2 * N_BLOCK], uint_8t* rc) {
+ uint_8t cc;
+
+ k[0] ^= s_box(k[29]) ^ *rc;
+ k[1] ^= s_box(k[30]);
+ k[2] ^= s_box(k[31]);
+ k[3] ^= s_box(k[28]);
+ *rc = f2(*rc);
+
+ for (cc = 4; cc < 16; cc += 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+
+ k[16] ^= s_box(k[12]);
+ k[17] ^= s_box(k[13]);
+ k[18] ^= s_box(k[14]);
+ k[19] ^= s_box(k[15]);
+
+ for (cc = 20; cc < 32; cc += 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+}
+
+/* Encrypt a single block of 16 bytes with 'on the fly' 256 bit keying */
+
+void aes_encrypt_256(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[2 * N_BLOCK],
+ unsigned char o_key[2 * N_BLOCK]) {
+ uint_8t s1[N_BLOCK], r, rc = 1;
+ if (o_key != key) {
+ block_copy(o_key, key);
+ block_copy(o_key + 16, key + 16);
+ }
+ copy_and_key(s1, in, o_key);
+
+ for (r = 1; r < 14; ++r)
+#if defined(VERSION_1)
+ {
+ mix_sub_columns(s1);
+ if (r & 1)
+ add_round_key(s1, o_key + 16);
+ else {
+ update_encrypt_key_256(o_key, &rc);
+ add_round_key(s1, o_key);
+ }
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ mix_sub_columns(s2, s1);
+ if (r & 1)
+ copy_and_key(s1, s2, o_key + 16);
+ else {
+ update_encrypt_key_256(o_key, &rc);
+ copy_and_key(s1, s2, o_key);
+ }
+ }
+#endif
+
+ shift_sub_rows(s1);
+ update_encrypt_key_256(o_key, &rc);
+ copy_and_key(out, s1, o_key);
+}
+
+#endif
+
+#if defined(AES_DEC_256_OTFK)
+
+/* The 'on the fly' encryption key update for for 256 bit keys */
+
+static void update_decrypt_key_256(uint_8t k[2 * N_BLOCK], uint_8t* rc) {
+ uint_8t cc;
+
+ for (cc = 28; cc > 16; cc -= 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+
+ k[16] ^= s_box(k[12]);
+ k[17] ^= s_box(k[13]);
+ k[18] ^= s_box(k[14]);
+ k[19] ^= s_box(k[15]);
+
+ for (cc = 12; cc > 0; cc -= 4) {
+ k[cc + 0] ^= k[cc - 4];
+ k[cc + 1] ^= k[cc - 3];
+ k[cc + 2] ^= k[cc - 2];
+ k[cc + 3] ^= k[cc - 1];
+ }
+
+ *rc = d2(*rc);
+ k[0] ^= s_box(k[29]) ^ *rc;
+ k[1] ^= s_box(k[30]);
+ k[2] ^= s_box(k[31]);
+ k[3] ^= s_box(k[28]);
+}
+
+/* Decrypt a single block of 16 bytes with 'on the fly'
+ 256 bit keying
+*/
+void aes_decrypt_256(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[2 * N_BLOCK],
+ unsigned char o_key[2 * N_BLOCK]) {
+ uint_8t s1[N_BLOCK], r, rc = 0x80;
+
+ if (o_key != key) {
+ block_copy(o_key, key);
+ block_copy(o_key + 16, key + 16);
+ }
+
+ copy_and_key(s1, in, o_key);
+ inv_shift_sub_rows(s1);
+
+ for (r = 14; --r;)
+#if defined(VERSION_1)
+ {
+ if ((r & 1)) {
+ update_decrypt_key_256(o_key, &rc);
+ add_round_key(s1, o_key + 16);
+ } else
+ add_round_key(s1, o_key);
+ inv_mix_sub_columns(s1);
+ }
+#else
+ {
+ uint_8t s2[N_BLOCK];
+ if ((r & 1)) {
+ update_decrypt_key_256(o_key, &rc);
+ copy_and_key(s2, s1, o_key + 16);
+ } else
+ copy_and_key(s2, s1, o_key);
+ inv_mix_sub_columns(s1, s2);
+ }
+#endif
+ copy_and_key(out, s1, o_key);
+}
+
+#endif
diff --git a/gd/crypto_toolbox/aes.h b/gd/crypto_toolbox/aes.h
new file mode 100644
index 0000000..2ff6fbd
--- /dev/null
+++ b/gd/crypto_toolbox/aes.h
@@ -0,0 +1,154 @@
+/*
+ ---------------------------------------------------------------------------
+ Copyright (c) 1998-2008, Brian Gladman, Worcester, UK. All rights reserved.
+
+ LICENSE TERMS
+
+ The redistribution and use of this software (with or without changes)
+ is allowed without the payment of fees or royalties provided that:
+
+ 1. source code distributions include the above copyright notice, this
+ list of conditions and the following disclaimer;
+
+ 2. binary distributions include the above copyright notice, this list
+ of conditions and the following disclaimer in their documentation;
+
+ 3. the name of the copyright holder is not used to endorse products
+ built using this software without specific written permission.
+
+ DISCLAIMER
+
+ This software is provided 'as is' with no explicit or implied warranties
+ in respect of its properties, including, but not limited to, correctness
+ and/or fitness for purpose.
+ ---------------------------------------------------------------------------
+ Issue 09/09/2006
+
+ This is an AES implementation that uses only 8-bit byte operations on the
+ cipher state.
+ */
+
+#ifndef AES_H
+#define AES_H
+
+#if 1
+#define AES_ENC_PREKEYED /* AES encryption with a precomputed key schedule */
+#endif
+#if 1
+#define AES_DEC_PREKEYED /* AES decryption with a precomputed key schedule */
+#endif
+#if 1
+#define AES_ENC_128_OTFK /* AES encryption with 'on the fly' 128 bit keying */
+#endif
+#if 1
+#define AES_DEC_128_OTFK /* AES decryption with 'on the fly' 128 bit keying */
+#endif
+#if 1
+#define AES_ENC_256_OTFK /* AES encryption with 'on the fly' 256 bit keying */
+#endif
+#if 1
+#define AES_DEC_256_OTFK /* AES decryption with 'on the fly' 256 bit keying */
+#endif
+
+#define N_ROW 4
+#define N_COL 4
+#define N_BLOCK (N_ROW * N_COL)
+#define N_MAX_ROUNDS 14
+
+typedef unsigned char uint_8t;
+
+typedef uint_8t return_type;
+
+/* Warning: The key length for 256 bit keys overflows a byte
+ (see comment below)
+*/
+
+typedef uint_8t length_type;
+
+typedef struct {
+ uint_8t ksch[(N_MAX_ROUNDS + 1) * N_BLOCK];
+ uint_8t rnd;
+} aes_context;
+
+/* The following calls are for a precomputed key schedule
+
+ NOTE: If the length_type used for the key length is an
+ unsigned 8-bit character, a key length of 256 bits must
+ be entered as a length in bytes (valid inputs are hence
+ 128, 192, 16, 24 and 32).
+*/
+
+#if defined(AES_ENC_PREKEYED) || defined(AES_DEC_PREKEYED)
+
+return_type aes_set_key(const unsigned char key[], length_type keylen,
+ aes_context ctx[1]);
+#endif
+
+#if defined(AES_ENC_PREKEYED)
+
+return_type aes_encrypt(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK], const aes_context ctx[1]);
+
+return_type aes_cbc_encrypt(const unsigned char* in, unsigned char* out,
+ int n_block, unsigned char iv[N_BLOCK],
+ const aes_context ctx[1]);
+#endif
+
+#if defined(AES_DEC_PREKEYED)
+
+return_type aes_decrypt(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK], const aes_context ctx[1]);
+
+return_type aes_cbc_decrypt(const unsigned char* in, unsigned char* out,
+ int n_block, unsigned char iv[N_BLOCK],
+ const aes_context ctx[1]);
+#endif
+
+/* The following calls are for 'on the fly' keying. In this case the
+ encryption and decryption keys are different.
+
+ The encryption subroutines take a key in an array of bytes in
+ key[L] where L is 16, 24 or 32 bytes for key lengths of 128,
+ 192, and 256 bits respectively. They then encrypts the input
+ data, in[] with this key and put the reult in the output array
+ out[]. In addition, the second key array, o_key[L], is used
+ to output the key that is needed by the decryption subroutine
+ to reverse the encryption operation. The two key arrays can
+ be the same array but in this case the original key will be
+ overwritten.
+
+ In the same way, the decryption subroutines output keys that
+ can be used to reverse their effect when used for encryption.
+
+ Only 128 and 256 bit keys are supported in these 'on the fly'
+ modes.
+*/
+
+#if defined(AES_ENC_128_OTFK)
+void aes_encrypt_128(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[N_BLOCK], uint_8t o_key[N_BLOCK]);
+#endif
+
+#if defined(AES_DEC_128_OTFK)
+void aes_decrypt_128(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[N_BLOCK],
+ unsigned char o_key[N_BLOCK]);
+#endif
+
+#if defined(AES_ENC_256_OTFK)
+void aes_encrypt_256(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[2 * N_BLOCK],
+ unsigned char o_key[2 * N_BLOCK]);
+#endif
+
+#if defined(AES_DEC_256_OTFK)
+void aes_decrypt_256(const unsigned char in[N_BLOCK],
+ unsigned char out[N_BLOCK],
+ const unsigned char key[2 * N_BLOCK],
+ unsigned char o_key[2 * N_BLOCK]);
+#endif
+
+#endif
diff --git a/gd/crypto_toolbox/aes_cmac.cc b/gd/crypto_toolbox/aes_cmac.cc
new file mode 100644
index 0000000..a58a5af
--- /dev/null
+++ b/gd/crypto_toolbox/aes_cmac.cc
@@ -0,0 +1,202 @@
+/******************************************************************************
+ *
+ * Copyright 2008-2012 Broadcom Corporation
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains the implementation of the AES128 and AES CMAC algorithm.
+ *
+ ******************************************************************************/
+
+#include "crypto_toolbox/aes.h"
+#include "crypto_toolbox/crypto_toolbox.h"
+
+namespace bluetooth {
+namespace crypto_toolbox {
+
+namespace {
+
+typedef struct {
+ uint8_t* text;
+ uint16_t len;
+ uint16_t round;
+} tCMAC_CB;
+
+thread_local tCMAC_CB cmac_cb;
+
+/* Rb for AES-128 as block cipher, LSB as [0] */
+Octet16 const_Rb{0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+/** utility function to do an biteise exclusive-OR of two bit strings of the
+ * length of OCTET16_LEN. Result is stored in first argument.
+ */
+static void xor_128(Octet16* a, const Octet16& b) {
+ // CHECK(a);
+ uint8_t i, *aa = a->data();
+ const uint8_t* bb = b.data();
+
+ for (i = 0; i < OCTET16_LEN; i++) {
+ aa[i] = aa[i] ^ bb[i];
+ }
+}
+} // namespace
+
+/* This function computes AES_128(key, message) */
+Octet16 aes_128(const Octet16& key, const Octet16& message) {
+ Octet16 key_reversed;
+ Octet16 message_reversed;
+ Octet16 output;
+
+ std::reverse_copy(key.begin(), key.end(), key_reversed.begin());
+ std::reverse_copy(message.begin(), message.end(), message_reversed.begin());
+
+ aes_context ctx;
+ aes_set_key(key_reversed.data(), key_reversed.size(), &ctx);
+ aes_encrypt(message_reversed.data(), output.data(), &ctx);
+
+ std::reverse(output.begin(), output.end());
+ return output;
+}
+
+/** utility function to padding the given text to be a 128 bits data. The
+ * parameter dest is input and output parameter, it must point to a
+ * OCTET16_LEN memory space; where include length bytes valid data. */
+static void padding(Octet16* dest, uint8_t length) {
+ uint8_t i, *p = dest->data();
+ /* original last block */
+ for (i = length; i < OCTET16_LEN; i++) p[OCTET16_LEN - i - 1] = (i == length) ? 0x80 : 0;
+}
+
+/** utility function to left shift one bit for a 128 bits value. */
+static void leftshift_onebit(uint8_t* input, uint8_t* output) {
+ uint8_t i, overflow = 0, next_overflow = 0;
+ /* input[0] is LSB */
+ for (i = 0; i < OCTET16_LEN; i++) {
+ next_overflow = (input[i] & 0x80) ? 1 : 0;
+ output[i] = (input[i] << 1) | overflow;
+ overflow = next_overflow;
+ }
+ return;
+}
+
+/** This function is the calculation of block cipher using AES-128. */
+static Octet16 cmac_aes_k_calculate(const Octet16& key) {
+ Octet16 output;
+ Octet16 x{0}; // zero initialized
+
+ uint8_t i = 1;
+ while (i <= cmac_cb.round) {
+ /* Mi' := Mi (+) X */
+ xor_128((Octet16*)&cmac_cb.text[(cmac_cb.round - i) * OCTET16_LEN], x);
+
+ output = aes_128(key, &cmac_cb.text[(cmac_cb.round - i) * OCTET16_LEN], OCTET16_LEN);
+ x = output;
+ i++;
+ }
+
+ return output;
+}
+
+/** This function proceeed to prepare the last block of message Mn depending on
+ * the size of the message.
+ */
+static void cmac_prepare_last_block(const Octet16& k1, const Octet16& k2) {
+ // uint8_t x[16] = {0};
+ bool flag;
+
+ /* last block is a complete block set flag to 1 */
+ flag = ((cmac_cb.len % OCTET16_LEN) == 0 && cmac_cb.len != 0) ? true : false;
+
+ if (flag) { /* last block is complete block */
+ xor_128((Octet16*)&cmac_cb.text[0], k1);
+ } else /* padding then xor with k2 */
+ {
+ padding((Octet16*)&cmac_cb.text[0], (uint8_t)(cmac_cb.len % 16));
+
+ xor_128((Octet16*)&cmac_cb.text[0], k2);
+ }
+}
+
+/** This is the function to generate the two subkeys.
+ * |key| is CMAC key, expect SRK when used by SMP.
+ */
+static void cmac_generate_subkey(const Octet16& key) {
+ Octet16 zero{};
+ Octet16 p = aes_128(key, zero.data(), OCTET16_LEN);
+
+ Octet16 k1, k2;
+ uint8_t* pp = p.data();
+
+ /* If MSB(L) = 0, then K1 = L << 1 */
+ if ((pp[OCTET16_LEN - 1] & 0x80) != 0) {
+ /* Else K1 = ( L << 1 ) (+) Rb */
+ leftshift_onebit(pp, k1.data());
+ xor_128(&k1, const_Rb);
+ } else {
+ leftshift_onebit(pp, k1.data());
+ }
+
+ if ((k1[OCTET16_LEN - 1] & 0x80) != 0) {
+ /* K2 = (K1 << 1) (+) Rb */
+ leftshift_onebit(k1.data(), k2.data());
+ xor_128(&k2, const_Rb);
+ } else {
+ /* If MSB(K1) = 0, then K2 = K1 << 1 */
+ leftshift_onebit(k1.data(), k2.data());
+ }
+
+ cmac_prepare_last_block(k1, k2);
+}
+
+/** key - CMAC key in little endian order
+ * input - text to be signed in little endian byte order.
+ * length - length of the input in byte.
+ */
+Octet16 aes_cmac(const Octet16& key, const uint8_t* input, uint16_t length) {
+ uint16_t len, diff;
+ /* n is number of rounds */
+ uint16_t n = (length + OCTET16_LEN - 1) / OCTET16_LEN;
+
+ if (n == 0) n = 1;
+ len = n * OCTET16_LEN;
+
+ /* allocate a memory space of multiple of 16 bytes to hold text */
+ cmac_cb.text = (uint8_t*)alloca(len);
+ cmac_cb.round = n;
+ diff = len - length;
+
+ if (input != NULL && length > 0) {
+ memcpy(&cmac_cb.text[diff], input, (int)length);
+ cmac_cb.len = length;
+ } else {
+ cmac_cb.len = 0;
+ }
+
+ /* prepare calculation for subkey s and last block of data */
+ cmac_generate_subkey(key);
+ /* start calculation */
+ Octet16 signature = cmac_aes_k_calculate(key);
+
+ /* clean up */
+ memset(&cmac_cb, 0, sizeof(tCMAC_CB));
+ // cmac_cb.text is auto-freed by alloca
+
+ return signature;
+}
+
+} // namespace crypto_toolbox
+} // namespace bluetooth
diff --git a/gd/crypto_toolbox/crypto_toolbox.cc b/gd/crypto_toolbox/crypto_toolbox.cc
new file mode 100644
index 0000000..6582633
--- /dev/null
+++ b/gd/crypto_toolbox/crypto_toolbox.cc
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2018 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 "crypto_toolbox/crypto_toolbox.h"
+#include "crypto_toolbox/aes.h"
+
+#include <endian.h>
+#include <algorithm>
+
+namespace bluetooth {
+namespace crypto_toolbox {
+
+constexpr int OCTET32_LEN = 32;
+
+Octet16 h6(const Octet16& w, std::array<uint8_t, 4> keyid) {
+ return aes_cmac(w, keyid.data(), keyid.size());
+}
+
+Octet16 h7(const Octet16& salt, const Octet16& w) {
+ return aes_cmac(salt, w.data(), w.size());
+}
+
+Octet16 f4(uint8_t* u, uint8_t* v, const Octet16& x, uint8_t z) {
+ constexpr size_t msg_len = OCTET32_LEN /* U size */ + OCTET32_LEN /* V size */ + 1 /* Z size */;
+
+ // DVLOG(2) << "U=" << HexEncode(u, OCTET32_LEN) << ", V=" << HexEncode(v, OCTET32_LEN)
+ // << ", X=" << HexEncode(x.data(), x.size()) << ", Z=" << std::hex << +z;
+
+ std::array<uint8_t, msg_len> msg;
+ auto it = msg.begin();
+ it = std::copy(&z, &z + 1, it);
+ it = std::copy(v, v + OCTET32_LEN, it);
+ it = std::copy(u, u + OCTET32_LEN, it);
+ return aes_cmac(x, msg.data(), msg.size());
+}
+
+/** helper for f5 */
+static Octet16 calculate_mac_key_or_ltk(const Octet16& t, uint8_t counter, uint8_t* key_id, const Octet16& n1,
+ const Octet16& n2, uint8_t* a1, uint8_t* a2, uint8_t* length) {
+ constexpr size_t msg_len = 1 /* Counter size */ + 4 /* keyID size */ + OCTET16_LEN /* N1 size */ +
+ OCTET16_LEN /* N2 size */ + 7 /* A1 size*/ + 7 /* A2 size*/ + 2 /* Length size */;
+
+ std::array<uint8_t, msg_len> msg;
+ auto it = msg.begin();
+ it = std::copy(length, length + 2, it);
+ it = std::copy(a2, a2 + 7, it);
+ it = std::copy(a1, a1 + 7, it);
+ it = std::copy(n2.begin(), n2.end(), it);
+ it = std::copy(n1.begin(), n1.end(), it);
+ it = std::copy(key_id, key_id + 4, it);
+ it = std::copy(&counter, &counter + 1, it);
+
+ return aes_cmac(t, msg.data(), msg.size());
+}
+
+void f5(uint8_t* w, const Octet16& n1, const Octet16& n2, uint8_t* a1, uint8_t* a2, Octet16* mac_key, Octet16* ltk) {
+ // DVLOG(2) << __func__ << "W=" << HexEncode(w, OCTET32_LEN) << ", N1=" << HexEncode(n1.data(), n1.size())
+ // << ", N2=" << HexEncode(n2.data(), n2.size()) << ", A1=" << HexEncode(a1, 7) << ", A2=" << HexEncode(a2,
+ // 7);
+
+ const Octet16 salt{0xBE, 0x83, 0x60, 0x5A, 0xDB, 0x0B, 0x37, 0x60, 0x38, 0xA5, 0xF5, 0xAA, 0x91, 0x83, 0x88, 0x6C};
+ Octet16 t = aes_cmac(salt, w, OCTET32_LEN);
+
+ // DVLOG(2) << "T=" << HexEncode(t.data(), t.size());
+
+ uint8_t key_id[4] = {0x65, 0x6c, 0x74, 0x62}; /* 0x62746c65 */
+ uint8_t length[2] = {0x00, 0x01}; /* 0x0100 */
+
+ *mac_key = calculate_mac_key_or_ltk(t, 0, key_id, n1, n2, a1, a2, length);
+
+ *ltk = calculate_mac_key_or_ltk(t, 1, key_id, n1, n2, a1, a2, length);
+
+ // DVLOG(2) << "mac_key=" << HexEncode(mac_key->data(), mac_key->size());
+ // DVLOG(2) << "ltk=" << HexEncode(ltk->data(), ltk->size());
+}
+
+Octet16 f6(const Octet16& w, const Octet16& n1, const Octet16& n2, const Octet16& r, uint8_t* iocap, uint8_t* a1,
+ uint8_t* a2) {
+ const uint8_t msg_len = OCTET16_LEN /* N1 size */ + OCTET16_LEN /* N2 size */ + OCTET16_LEN /* R size */ +
+ 3 /* IOcap size */ + 7 /* A1 size*/ + 7 /* A2 size*/;
+
+ // DVLOG(2) << __func__ << "W=" << HexEncode(w.data(), w.size()) << ", N1=" << HexEncode(n1.data(), n1.size())
+ // << ", N2=" << HexEncode(n2.data(), n2.size()) << ", R=" << HexEncode(r.data(), r.size())
+ // << ", IOcap=" << HexEncode(iocap, 3) << ", A1=" << HexEncode(a1, 7) << ", A2=" << HexEncode(a2, 7);
+
+ std::array<uint8_t, msg_len> msg;
+ auto it = msg.begin();
+ it = std::copy(a2, a2 + 7, it);
+ it = std::copy(a1, a1 + 7, it);
+ it = std::copy(iocap, iocap + 3, it);
+ it = std::copy(r.begin(), r.end(), it);
+ it = std::copy(n2.begin(), n2.end(), it);
+ it = std::copy(n1.begin(), n1.end(), it);
+
+ return aes_cmac(w, msg.data(), msg.size());
+}
+
+uint32_t g2(uint8_t* u, uint8_t* v, const Octet16& x, const Octet16& y) {
+ constexpr size_t msg_len = OCTET32_LEN /* U size */ + OCTET32_LEN /* V size */
+ + OCTET16_LEN /* Y size */;
+
+ // DVLOG(2) << __func__ << "U=" << HexEncode(u, OCTET32_LEN) << ", V=" << HexEncode(v, OCTET32_LEN)
+ // << ", X=" << HexEncode(x.data(), x.size()) << ", Y=" << HexEncode(y.data(), y.size());
+
+ std::array<uint8_t, msg_len> msg;
+ auto it = msg.begin();
+ it = std::copy(y.begin(), y.end(), it);
+ it = std::copy(v, v + OCTET32_LEN, it);
+ it = std::copy(u, u + OCTET32_LEN, it);
+
+ Octet16 cmac = aes_cmac(x, msg.data(), msg.size());
+
+ /* vres = cmac mod 2**32 mod 10**6 */
+ return le32toh(*(uint32_t*)cmac.data()) % 1000000;
+}
+
+Octet16 ltk_to_link_key(const Octet16& ltk, bool use_h7) {
+ Octet16 ilk; /* intermidiate link key */
+ if (use_h7) {
+ constexpr Octet16 salt{0x31, 0x70, 0x6D, 0x74, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ ilk = h7(salt, ltk);
+ } else {
+ /* "tmp1" mapping to extended ASCII, little endian*/
+ constexpr std::array<uint8_t, 4> keyID_tmp1 = {0x31, 0x70, 0x6D, 0x74};
+ ilk = h6(ltk, keyID_tmp1);
+ }
+
+ /* "lebr" mapping to extended ASCII, little endian */
+ constexpr std::array<uint8_t, 4> keyID_lebr = {0x72, 0x62, 0x65, 0x6c};
+ return h6(ilk, keyID_lebr);
+}
+
+Octet16 link_key_to_ltk(const Octet16& link_key, bool use_h7) {
+ Octet16 iltk; /* intermidiate long term key */
+ if (use_h7) {
+ constexpr Octet16 salt{0x32, 0x70, 0x6D, 0x74, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+ iltk = h7(salt, link_key);
+ } else {
+ /* "tmp2" mapping to extended ASCII, little endian */
+ constexpr std::array<uint8_t, 4> keyID_tmp2 = {0x32, 0x70, 0x6D, 0x74};
+ iltk = h6(link_key, keyID_tmp2);
+ }
+
+ /* "brle" mapping to extended ASCII, little endian */
+ constexpr std::array<uint8_t, 4> keyID_brle = {0x65, 0x6c, 0x72, 0x62};
+ return h6(iltk, keyID_brle);
+}
+
+Octet16 c1(const Octet16& k, const Octet16& r, const uint8_t* pres, const uint8_t* preq, const uint8_t iat,
+ const uint8_t* ia, const uint8_t rat, const uint8_t* ra) {
+ Octet16 p1;
+ auto it = p1.begin();
+ it = std::copy(pres, pres + 7, it);
+ it = std::copy(preq, preq + 7, it);
+ it = std::copy(&rat, &rat + 1, it);
+ it = std::copy(&iat, &iat + 1, it);
+
+ for (uint8_t i = 0; i < OCTET16_LEN; i++) {
+ p1[i] = r[i] ^ p1[i];
+ }
+
+ Octet16 p1bis = aes_128(k, p1);
+
+ std::array<uint8_t, 4> padding{0};
+ Octet16 p2;
+ it = p2.begin();
+ it = std::copy(padding.begin(), padding.end(), it);
+ it = std::copy(ia, ia + 6, it);
+ it = std::copy(ra, ra + 6, it);
+
+ for (uint8_t i = 0; i < OCTET16_LEN; i++) {
+ p2[i] = p1bis[i] ^ p2[i];
+ }
+
+ return aes_128(k, p2);
+}
+
+Octet16 s1(const Octet16& k, const Octet16& r1, const Octet16& r2) {
+ Octet16 text{0};
+ constexpr uint8_t BT_OCTET8_LEN = 8;
+ memcpy(text.data(), r1.data(), BT_OCTET8_LEN);
+ memcpy(text.data() + BT_OCTET8_LEN, r2.data(), BT_OCTET8_LEN);
+
+ return aes_128(k, text);
+}
+
+} // namespace crypto_toolbox
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/crypto_toolbox/crypto_toolbox.h b/gd/crypto_toolbox/crypto_toolbox.h
new file mode 100644
index 0000000..25f7f69
--- /dev/null
+++ b/gd/crypto_toolbox/crypto_toolbox.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#pragma once
+
+#include <array>
+
+namespace bluetooth {
+namespace crypto_toolbox {
+
+constexpr int OCTET16_LEN = 16;
+using Octet16 = std::array<uint8_t, OCTET16_LEN>;
+
+Octet16 c1(const Octet16& k, const Octet16& r, const uint8_t* pres, const uint8_t* preq, const uint8_t iat,
+ const uint8_t* ia, const uint8_t rat, const uint8_t* ra);
+Octet16 s1(const Octet16& k, const Octet16& r1, const Octet16& r2);
+
+extern Octet16 aes_128(const Octet16& key, const Octet16& message);
+extern Octet16 aes_cmac(const Octet16& key, const uint8_t* message, uint16_t length);
+extern Octet16 f4(uint8_t* u, uint8_t* v, const Octet16& x, uint8_t z);
+extern void f5(uint8_t* w, const Octet16& n1, const Octet16& n2, uint8_t* a1, uint8_t* a2, Octet16* mac_key,
+ Octet16* ltk);
+extern Octet16 f6(const Octet16& w, const Octet16& n1, const Octet16& n2, const Octet16& r, uint8_t* iocap, uint8_t* a1,
+ uint8_t* a2);
+extern Octet16 h6(const Octet16& w, std::array<uint8_t, 4> keyid);
+extern Octet16 h7(const Octet16& salt, const Octet16& w);
+extern uint32_t g2(uint8_t* u, uint8_t* v, const Octet16& x, const Octet16& y);
+extern Octet16 ltk_to_link_key(const Octet16& ltk, bool use_h7);
+extern Octet16 link_key_to_ltk(const Octet16& link_key, bool use_h7);
+
+/* This function computes AES_128(key, message). |key| must be 128bit.
+ * |message| can be at most 16 bytes long, it's length in bytes is given in
+ * |length| */
+inline Octet16 aes_128(const Octet16& key, const uint8_t* message, const uint8_t length) {
+ // CHECK(length <= OCTET16_LEN) << "you tried aes_128 more than 16 bytes!";
+ Octet16 msg{0};
+ std::copy(message, message + length, msg.begin());
+ return aes_128(key, msg);
+}
+
+// |tlen| - lenth of mac desired
+// |p_signature| - data pointer to where signed data to be stored, tlen long.
+inline void aes_cmac(const Octet16& key, const uint8_t* message, uint16_t length, uint16_t tlen, uint8_t* p_signature) {
+ Octet16 signature = aes_cmac(key, message, length);
+
+ uint8_t* p_mac = signature.data() + (OCTET16_LEN - tlen);
+ memcpy(p_signature, p_mac, tlen);
+}
+
+inline Octet16 aes_cmac(const Octet16& key, const Octet16& message) {
+ return aes_cmac(key, message.data(), message.size());
+}
+
+} // namespace crypto_toolbox
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/crypto_toolbox/crypto_toolbox_test.cc b/gd/crypto_toolbox/crypto_toolbox_test.cc
new file mode 100644
index 0000000..b5674c1
--- /dev/null
+++ b/gd/crypto_toolbox/crypto_toolbox_test.cc
@@ -0,0 +1,355 @@
+/******************************************************************************
+ *
+ * Copyright 2018 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 <gtest/gtest.h>
+
+#include "crypto_toolbox/aes.h"
+#include "crypto_toolbox/crypto_toolbox.h"
+
+#include <vector>
+
+namespace bluetooth {
+namespace crypto_toolbox {
+
+// BT Spec 5.0 | Vol 3, Part H D.1
+TEST(CryptoToolboxTest, bt_spec_test_d_1_test) {
+ uint8_t k[] = {0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
+
+ uint8_t m[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+ uint8_t aes_cmac_k_m[] = {0x7d, 0xf7, 0x6b, 0x0c, 0x1a, 0xb8, 0x99, 0xb3,
+ 0x3e, 0x42, 0xf0, 0x47, 0xb9, 0x1b, 0x54, 0x6f};
+
+ uint8_t output[16];
+ aes_context ctx;
+ aes_set_key(k, sizeof(k), &ctx);
+ aes_encrypt(m, output, &ctx); /* outputs in byte 48 to byte 63 */
+
+ EXPECT_TRUE(memcmp(output, aes_cmac_k_m, OCTET16_LEN) == 0);
+
+ // useful for debugging
+ // LOG(INFO) << "k " << base::HexEncode(k, OCTET16_LEN);
+ // LOG(INFO) << "m " << base::HexEncode(m, sizeof(m));
+ // LOG(INFO) << "output " << base::HexEncode(output, OCTET16_LEN);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.1.1
+TEST(CryptoToolboxTest, bt_spec_example_d_1_1_test) {
+ Octet16 k{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
+
+ Octet16 aes_cmac_k_m{0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28, 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(k), std::end(k));
+ std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m));
+
+ Octet16 output = aes_cmac(k, nullptr /* empty message */, 0);
+
+ EXPECT_EQ(output, aes_cmac_k_m);
+
+ // useful for debugging
+ // LOG(INFO) << "k " << base::HexEncode(k.data(), k.size());
+ // LOG(INFO) << "aes_cmac(k,nullptr) "
+ // << base::HexEncode(output.data(), output.size());
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.1.2
+TEST(CryptoToolboxTest, bt_spec_example_d_1_2_test) {
+ Octet16 k{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
+
+ Octet16 m = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a};
+
+ Octet16 aes_cmac_k_m{0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44, 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(k), std::end(k));
+ std::reverse(std::begin(m), std::end(m));
+ std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m));
+
+ Octet16 output = aes_cmac(k, m);
+
+ EXPECT_EQ(output, aes_cmac_k_m);
+
+ // useful for debugging
+ // LOG(INFO) << "k " << base::HexEncode(k.data(), k.size());
+ // LOG(INFO) << "m " << base::HexEncode(m, sizeof(m));
+ // LOG(INFO) << "aes_cmac(k,m) "
+ // << base::HexEncode(output.data(), output.size());
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.1.3
+TEST(CryptoToolboxTest, bt_spec_example_d_1_3_test) {
+ Octet16 k{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
+
+ uint8_t m[] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93,
+ 0x17, 0x2a, 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac,
+ 0x45, 0xaf, 0x8e, 0x51, 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11};
+
+ Octet16 aes_cmac_k_m{0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30, 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(k), std::end(k));
+ std::reverse(std::begin(m), std::end(m));
+ std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m));
+
+ Octet16 output = aes_cmac(k, m, sizeof(m));
+ EXPECT_EQ(output, aes_cmac_k_m);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.1.4
+TEST(CryptoToolboxTest, bt_spec_example_d_1_4_test) {
+ Octet16 k{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c};
+
+ uint8_t m[] = {0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10};
+
+ Octet16 aes_cmac_k_m{0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92, 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(k), std::end(k));
+ std::reverse(std::begin(m), std::end(m));
+ std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m));
+
+ Octet16 output = aes_cmac(k, m, sizeof(m));
+
+ EXPECT_EQ(output, aes_cmac_k_m);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.2
+TEST(CryptoToolboxTest, bt_spec_example_d_2_test) {
+ std::vector<uint8_t> u{0x20, 0xb0, 0x03, 0xd2, 0xf2, 0x97, 0xbe, 0x2c, 0x5e, 0x2c, 0x83,
+ 0xa7, 0xe9, 0xf9, 0xa5, 0xb9, 0xef, 0xf4, 0x91, 0x11, 0xac, 0xf4,
+ 0xfd, 0xdb, 0xcc, 0x03, 0x01, 0x48, 0x0e, 0x35, 0x9d, 0xe6};
+ std::vector<uint8_t> v{0x55, 0x18, 0x8b, 0x3d, 0x32, 0xf6, 0xbb, 0x9a, 0x90, 0x0a, 0xfc,
+ 0xfb, 0xee, 0xd4, 0xe7, 0x2a, 0x59, 0xcb, 0x9a, 0xc2, 0xf1, 0x9d,
+ 0x7c, 0xfb, 0x6b, 0x4f, 0xdd, 0x49, 0xf4, 0x7f, 0xc5, 0xfd};
+ Octet16 x{0xd5, 0xcb, 0x84, 0x54, 0xd1, 0x77, 0x73, 0x3e, 0xff, 0xff, 0xb2, 0xec, 0x71, 0x2b, 0xae, 0xab};
+ uint8_t z = 0x00;
+
+ Octet16 aes_cmac_k_m{0xf2, 0xc9, 0x16, 0xf1, 0x07, 0xa9, 0xbd, 0x1c, 0xf1, 0xed, 0xa1, 0xbe, 0xa9, 0x74, 0x87, 0x2d};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(u), std::end(u));
+ std::reverse(std::begin(v), std::end(v));
+ std::reverse(std::begin(x), std::end(x));
+ std::reverse(std::begin(aes_cmac_k_m), std::end(aes_cmac_k_m));
+
+ Octet16 output = f4(u.data(), v.data(), x, z);
+
+ EXPECT_EQ(output, aes_cmac_k_m);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.3
+TEST(CryptoToolboxTest, bt_spec_example_d_3_test) {
+ std::array<uint8_t, 32> dhkey_w{0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10,
+ 0xa6, 0x0a, 0x39, 0x7d, 0x9b, 0x99, 0x79, 0x6b, 0x13, 0xb4, 0xf8,
+ 0x66, 0xf1, 0x86, 0x8d, 0x34, 0xf3, 0x73, 0xbf, 0xa6, 0x98};
+ Octet16 n1{0xd5, 0xcb, 0x84, 0x54, 0xd1, 0x77, 0x73, 0x3e, 0xff, 0xff, 0xb2, 0xec, 0x71, 0x2b, 0xae, 0xab};
+ Octet16 n2{0xa6, 0xe8, 0xe7, 0xcc, 0x25, 0xa7, 0x5f, 0x6e, 0x21, 0x65, 0x83, 0xf7, 0xff, 0x3d, 0xc4, 0xcf};
+ std::array<uint8_t, 7> a1{0x00, 0x56, 0x12, 0x37, 0x37, 0xbf, 0xce};
+ std::array<uint8_t, 7> a2{0x00, 0xa7, 0x13, 0x70, 0x2d, 0xcf, 0xc1};
+
+ Octet16 expected_ltk{0x69, 0x86, 0x79, 0x11, 0x69, 0xd7, 0xcd, 0x23, 0x98, 0x05, 0x22, 0xb5, 0x94, 0x75, 0x0a, 0x38};
+ Octet16 expected_mac_key{0x29, 0x65, 0xf1, 0x76, 0xa1, 0x08, 0x4a, 0x02,
+ 0xfd, 0x3f, 0x6a, 0x20, 0xce, 0x63, 0x6e, 0x20};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(dhkey_w), std::end(dhkey_w));
+ std::reverse(std::begin(n1), std::end(n1));
+ std::reverse(std::begin(n2), std::end(n2));
+ std::reverse(std::begin(a1), std::end(a1));
+ std::reverse(std::begin(a2), std::end(a2));
+ std::reverse(std::begin(expected_ltk), std::end(expected_ltk));
+ std::reverse(std::begin(expected_mac_key), std::end(expected_mac_key));
+
+ Octet16 mac_key, ltk;
+ f5(dhkey_w.data(), n1, n2, a1.data(), a2.data(), &mac_key, <k);
+
+ EXPECT_EQ(mac_key, expected_mac_key);
+ EXPECT_EQ(ltk, expected_ltk);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.4
+TEST(CryptoToolboxTest, bt_spec_example_d_4_test) {
+ Octet16 n1{0xd5, 0xcb, 0x84, 0x54, 0xd1, 0x77, 0x73, 0x3e, 0xff, 0xff, 0xb2, 0xec, 0x71, 0x2b, 0xae, 0xab};
+ Octet16 n2{0xa6, 0xe8, 0xe7, 0xcc, 0x25, 0xa7, 0x5f, 0x6e, 0x21, 0x65, 0x83, 0xf7, 0xff, 0x3d, 0xc4, 0xcf};
+ Octet16 r{0x12, 0xa3, 0x34, 0x3b, 0xb4, 0x53, 0xbb, 0x54, 0x08, 0xda, 0x42, 0xd2, 0x0c, 0x2d, 0x0f, 0xc8};
+ std::vector<uint8_t> IOcap{0x01, 0x01, 0x02};
+ std::vector<uint8_t> a1{0x00, 0x56, 0x12, 0x37, 0x37, 0xbf, 0xce};
+ std::vector<uint8_t> a2{0x00, 0xa7, 0x13, 0x70, 0x2d, 0xcf, 0xc1};
+
+ Octet16 MacKey{0x29, 0x65, 0xf1, 0x76, 0xa1, 0x08, 0x4a, 0x02, 0xfd, 0x3f, 0x6a, 0x20, 0xce, 0x63, 0x6e, 0x20};
+
+ Octet16 expected_aes_cmac{0xe3, 0xc4, 0x73, 0x98, 0x9c, 0xd0, 0xe8, 0xc5,
+ 0xd2, 0x6c, 0x0b, 0x09, 0xda, 0x95, 0x8f, 0x61};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(n1), std::end(n1));
+ std::reverse(std::begin(n2), std::end(n2));
+ std::reverse(std::begin(r), std::end(r));
+ std::reverse(std::begin(IOcap), std::end(IOcap));
+ std::reverse(std::begin(a1), std::end(a1));
+ std::reverse(std::begin(a2), std::end(a2));
+ std::reverse(std::begin(MacKey), std::end(MacKey));
+ std::reverse(std::begin(expected_aes_cmac), std::end(expected_aes_cmac));
+
+ Octet16 aes_cmac = f6(MacKey, n1, n2, r, IOcap.data(), a1.data(), a2.data());
+
+ EXPECT_EQ(aes_cmac, expected_aes_cmac);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.5
+TEST(CryptoToolboxTest, bt_spec_example_d_5_test) {
+ std::array<uint8_t, 32> u{0x20, 0xb0, 0x03, 0xd2, 0xf2, 0x97, 0xbe, 0x2c, 0x5e, 0x2c, 0x83,
+ 0xa7, 0xe9, 0xf9, 0xa5, 0xb9, 0xef, 0xf4, 0x91, 0x11, 0xac, 0xf4,
+ 0xfd, 0xdb, 0xcc, 0x03, 0x01, 0x48, 0x0e, 0x35, 0x9d, 0xe6};
+ std::array<uint8_t, 32> v{0x55, 0x18, 0x8b, 0x3d, 0x32, 0xf6, 0xbb, 0x9a, 0x90, 0x0a, 0xfc,
+ 0xfb, 0xee, 0xd4, 0xe7, 0x2a, 0x59, 0xcb, 0x9a, 0xc2, 0xf1, 0x9d,
+ 0x7c, 0xfb, 0x6b, 0x4f, 0xdd, 0x49, 0xf4, 0x7f, 0xc5, 0xfd};
+
+ Octet16 x{0xd5, 0xcb, 0x84, 0x54, 0xd1, 0x77, 0x73, 0x3e, 0xff, 0xff, 0xb2, 0xec, 0x71, 0x2b, 0xae, 0xab};
+ Octet16 y{0xa6, 0xe8, 0xe7, 0xcc, 0x25, 0xa7, 0x5f, 0x6e, 0x21, 0x65, 0x83, 0xf7, 0xff, 0x3d, 0xc4, 0xcf};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(u), std::end(u));
+ std::reverse(std::begin(v), std::end(v));
+ std::reverse(std::begin(x), std::end(x));
+ std::reverse(std::begin(y), std::end(y));
+
+ uint32_t val = g2(u.data(), v.data(), x, y);
+
+ /* the returned value is already mod 1000000, so do mod on the test result
+ * value too */
+ EXPECT_EQ(val, 0x2f9ed5baU % 1000000);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.6
+TEST(CryptoToolboxTest, bt_spec_example_d_6_test) {
+ Octet16 key{0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
+ std::array<uint8_t, 4> keyID{0x6c, 0x65, 0x62, 0x72};
+ Octet16 expected_aes_cmac{0x2d, 0x9a, 0xe1, 0x02, 0xe7, 0x6d, 0xc9, 0x1c,
+ 0xe8, 0xd3, 0xa9, 0xe2, 0x80, 0xb1, 0x63, 0x99};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(key), std::end(key));
+ std::reverse(std::begin(keyID), std::end(keyID));
+ std::reverse(std::begin(expected_aes_cmac), std::end(expected_aes_cmac));
+
+ Octet16 aes_cmac = h6(key, keyID);
+ EXPECT_EQ(aes_cmac, expected_aes_cmac);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.7
+TEST(CryptoToolboxTest, bt_spec_example_d_7_test) {
+ Octet16 IRK{0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
+ Octet16 prand{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x81, 0x94};
+ Octet16 expected_aes_128{0x15, 0x9d, 0x5f, 0xb7, 0x2e, 0xbe, 0x23, 0x11,
+ 0xa4, 0x8c, 0x1b, 0xdc, 0xc4, 0x0d, 0xfb, 0xaa};
+ std::array<uint8_t, 3> expected_ah{0x0d, 0xfb, 0xaa};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(IRK), std::end(IRK));
+ std::reverse(std::begin(prand), std::end(prand));
+ std::reverse(std::begin(expected_aes_128), std::end(expected_aes_128));
+ std::reverse(std::begin(expected_ah), std::end(expected_ah));
+
+ Octet16 result = aes_128(IRK, prand.data(), 3);
+ EXPECT_EQ(expected_aes_128, result);
+
+ // little/big endian 24 bits
+ EXPECT_EQ(result[0], expected_ah[0]);
+ EXPECT_EQ(result[1], expected_ah[1]);
+ EXPECT_EQ(result[2], expected_ah[2]);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.8
+TEST(CryptoToolboxTest, bt_spec_example_d_8_test) {
+ Octet16 Key{0xec, 0x02, 0x34, 0xa3, 0x57, 0xc8, 0xad, 0x05, 0x34, 0x10, 0x10, 0xa6, 0x0a, 0x39, 0x7d, 0x9b};
+ Octet16 SALT{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x6D, 0x70, 0x31};
+ Octet16 expected_aes_cmac{0xfb, 0x17, 0x35, 0x97, 0xc6, 0xa3, 0xc0, 0xec,
+ 0xd2, 0x99, 0x8c, 0x2a, 0x75, 0xa5, 0x70, 0x11};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(Key), std::end(Key));
+ std::reverse(std::begin(SALT), std::end(SALT));
+ std::reverse(std::begin(expected_aes_cmac), std::end(expected_aes_cmac));
+
+ Octet16 aes_cmac = h7(SALT, Key);
+ EXPECT_EQ(expected_aes_cmac, aes_cmac);
+}
+
+extern Octet16 smp_calculate_ltk_to_link_key(const Octet16& ltk, bool use_h7);
+
+// BT Spec 5.0 | Vol 3, Part H D.9
+TEST(CryptoToolboxTest, bt_spec_example_d_9_test) {
+ Octet16 LTK{0x36, 0x8d, 0xf9, 0xbc, 0xe3, 0x26, 0x4b, 0x58, 0xbd, 0x06, 0x6c, 0x33, 0x33, 0x4f, 0xbf, 0x64};
+ Octet16 expected_link_key{0x28, 0x7a, 0xd3, 0x79, 0xdc, 0xa4, 0x02, 0x53,
+ 0x0a, 0x39, 0xf1, 0xf4, 0x30, 0x47, 0xb8, 0x35};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(LTK), std::end(LTK));
+ std::reverse(std::begin(expected_link_key), std::end(expected_link_key));
+
+ Octet16 link_key = ltk_to_link_key(LTK, true);
+ EXPECT_EQ(expected_link_key, link_key);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.10
+TEST(CryptoToolboxTest, bt_spec_example_d_10_test) {
+ Octet16 LTK{0x36, 0x8d, 0xf9, 0xbc, 0xe3, 0x26, 0x4b, 0x58, 0xbd, 0x06, 0x6c, 0x33, 0x33, 0x4f, 0xbf, 0x64};
+ Octet16 expected_link_key{0xbc, 0x1c, 0xa4, 0xef, 0x63, 0x3f, 0xc1, 0xbd,
+ 0x0d, 0x82, 0x30, 0xaf, 0xee, 0x38, 0x8f, 0xb0};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(LTK), std::end(LTK));
+ std::reverse(std::begin(expected_link_key), std::end(expected_link_key));
+
+ Octet16 link_key = ltk_to_link_key(LTK, false);
+ EXPECT_EQ(expected_link_key, link_key);
+}
+
+// // BT Spec 5.0 | Vol 3, Part H D.11
+TEST(CryptoToolboxTest, bt_spec_example_d_11_test) {
+ Octet16 link_key{0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00};
+ Octet16 expected_ltk{0xe8, 0x5e, 0x09, 0xeb, 0x5e, 0xcc, 0xb3, 0xe2, 0x69, 0x41, 0x8a, 0x13, 0x32, 0x11, 0xbc, 0x79};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(link_key), std::end(link_key));
+ std::reverse(std::begin(expected_ltk), std::end(expected_ltk));
+
+ Octet16 ltk = link_key_to_ltk(link_key, true);
+ EXPECT_EQ(expected_ltk, ltk);
+}
+
+// BT Spec 5.0 | Vol 3, Part H D.12
+TEST(CryptoToolboxTest, bt_spec_example_d_12_test) {
+ Octet16 link_key{0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00};
+ Octet16 expected_ltk{0xa8, 0x13, 0xfb, 0x72, 0xf1, 0xa3, 0xdf, 0xa1, 0x8a, 0x2c, 0x9a, 0x43, 0xf1, 0x0d, 0x0a, 0x30};
+
+ // algorithm expect all input to be in little endian format, so reverse
+ std::reverse(std::begin(link_key), std::end(link_key));
+ std::reverse(std::begin(expected_ltk), std::end(expected_ltk));
+
+ Octet16 ltk = link_key_to_ltk(link_key, false);
+ EXPECT_EQ(expected_ltk, ltk);
+}
+
+} // namespace crypto_toolbox
+} // namespace bluetooth
diff --git a/gd/facade/common.proto b/gd/facade/common.proto
new file mode 100644
index 0000000..bf35409
--- /dev/null
+++ b/gd/facade/common.proto
@@ -0,0 +1,25 @@
+syntax = "proto3";
+
+package bluetooth.facade;
+
+enum EventSubscriptionMode {
+ UNCHANGED = 0;
+ SUBSCRIBE = 1;
+ UNSUBSCRIBE = 2;
+}
+
+enum EventFetchMode {
+ NONE = 0;
+ ALL_CURRENT = 1;
+ AT_LEAST_ONE = 2;
+}
+
+message EventStreamRequest {
+ EventSubscriptionMode subscription_mode = 1;
+ EventFetchMode fetch_mode = 2;
+ uint32 timeout_ms = 3;
+}
+
+message BluetoothAddress {
+ bytes address = 1;
+}
diff --git a/gd/facade/facade_main.cc b/gd/facade/facade_main.cc
new file mode 100644
index 0000000..8ff1e72
--- /dev/null
+++ b/gd/facade/facade_main.cc
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2019 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 "stack_manager.h"
+
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <csignal>
+#include <cstring>
+#include <string>
+#include <thread>
+
+#include "facade/grpc_root_server.h"
+#include "grpc/grpc_module.h"
+#include "hal/hci_hal.h"
+#include "hal/hci_hal_host_rootcanal.h"
+#include "hal/snoop_logger.h"
+
+using ::bluetooth::hal::HciHalHostRootcanalConfig;
+using ::bluetooth::StackManager;
+using ::bluetooth::grpc::GrpcModule;
+using ::bluetooth::ModuleList;
+using ::bluetooth::os::Thread;
+
+namespace {
+::bluetooth::facade::GrpcRootServer grpc_root_server;
+
+void interrupt_handler(int) {
+ grpc_root_server.StopServer();
+}
+} // namespace
+
+// The entry point for the binary with libbluetooth + facades
+int main(int argc, const char** argv) {
+ int root_server_port = 8897;
+ int grpc_port = 8899;
+ int signal_port = 8895;
+
+ const std::string arg_grpc_root_server_port = "--root-server-port=";
+ const std::string arg_grpc_server_port = "--grpc-port=";
+ const std::string arg_rootcanal_port = "--rootcanal-port=";
+ const std::string arg_signal_port = "--signal-port=";
+ const std::string arg_btsnoop_path = "--btsnoop=";
+ std::string btsnoop_path;
+ for (int i = 1; i < argc; i++) {
+ std::string arg = argv[i];
+ if (arg.find(arg_grpc_root_server_port) == 0) {
+ auto port_number = arg.substr(arg_grpc_root_server_port.size());
+ root_server_port = std::stoi(port_number);
+ }
+ if (arg.find(arg_grpc_server_port) == 0) {
+ auto port_number = arg.substr(arg_grpc_server_port.size());
+ grpc_port = std::stoi(port_number);
+ }
+ if (arg.find(arg_rootcanal_port) == 0) {
+ auto port_number = arg.substr(arg_rootcanal_port.size());
+ HciHalHostRootcanalConfig::Get()->SetPort(std::stoi(port_number));
+ }
+ if (arg.find(arg_btsnoop_path) == 0) {
+ btsnoop_path = arg.substr(arg_btsnoop_path.size());
+ ::bluetooth::hal::SnoopLogger::SetFilePath(btsnoop_path);
+ }
+ if (arg.find(arg_signal_port) == 0) {
+ auto port_number = arg.substr(arg_signal_port.size());
+ signal_port = std::stoi(port_number);
+ }
+ }
+
+ signal(SIGINT, interrupt_handler);
+ grpc_root_server.StartServer("0.0.0.0", root_server_port, grpc_port);
+ int tester_signal_socket = socket(AF_INET, SOCK_STREAM, 0);
+ struct sockaddr_in addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(signal_port);
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ connect(tester_signal_socket, (sockaddr*)&addr, sizeof(addr));
+ close(tester_signal_socket);
+ auto wait_thread = std::thread([] { grpc_root_server.RunGrpcLoop(); });
+ wait_thread.join();
+
+ return 0;
+}
diff --git a/gd/facade/grpc_root_server.cc b/gd/facade/grpc_root_server.cc
new file mode 100644
index 0000000..e802dfe
--- /dev/null
+++ b/gd/facade/grpc_root_server.cc
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2019 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 "facade/grpc_root_server.h"
+
+#include <string>
+
+#include "facade/read_only_property_server.h"
+#include "facade/rootservice.grpc.pb.h"
+#include "grpc/grpc_module.h"
+#include "hal/facade.h"
+#include "hci/facade.h"
+#include "l2cap/classic/facade.h"
+#include "os/log.h"
+#include "os/thread.h"
+#include "stack_manager.h"
+
+namespace bluetooth {
+namespace facade {
+
+using ::bluetooth::grpc::GrpcModule;
+using ::bluetooth::os::Thread;
+
+namespace {
+class RootFacadeService : public ::bluetooth::facade::RootFacade::Service {
+ public:
+ RootFacadeService(int grpc_port) : grpc_port_(grpc_port) {}
+
+ ::grpc::Status StartStack(::grpc::ServerContext* context, const ::bluetooth::facade::StartStackRequest* request,
+ ::bluetooth::facade::StartStackResponse* response) override {
+ if (is_running_) {
+ return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "stack is running");
+ }
+
+ ModuleList modules;
+ modules.add<::bluetooth::grpc::GrpcModule>();
+
+ BluetoothModule module_under_test = request->module_under_test();
+ switch (module_under_test) {
+ case BluetoothModule::HAL:
+ modules.add<::bluetooth::hal::HciHalFacadeModule>();
+ break;
+ case BluetoothModule::HCI:
+ modules.add<::bluetooth::facade::ReadOnlyPropertyServerModule>();
+ modules.add<::bluetooth::hci::AclManagerFacadeModule>();
+ modules.add<::bluetooth::hci::ClassicSecurityManagerFacadeModule>();
+ break;
+ case BluetoothModule::L2CAP:
+ modules.add<::bluetooth::facade::ReadOnlyPropertyServerModule>();
+ modules.add<::bluetooth::l2cap::classic::L2capClassicModuleFacadeModule>();
+ break;
+ default:
+ return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "invalid module under test");
+ }
+
+ stack_thread_ = new Thread("stack_thread", Thread::Priority::NORMAL);
+ stack_manager_.StartUp(&modules, stack_thread_);
+
+ GrpcModule* grpc_module = stack_manager_.GetInstance<GrpcModule>();
+ grpc_module->StartServer("0.0.0.0", grpc_port_);
+
+ grpc_loop_thread_ = new std::thread([grpc_module] { grpc_module->RunGrpcLoop(); });
+ is_running_ = true;
+
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status StopStack(::grpc::ServerContext* context, const ::bluetooth::facade::StopStackRequest* request,
+ ::bluetooth::facade::StopStackResponse* response) override {
+ if (!is_running_) {
+ return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "stack is not running");
+ }
+
+ stack_manager_.GetInstance<GrpcModule>()->StopServer();
+ grpc_loop_thread_->join();
+ delete grpc_loop_thread_;
+
+ stack_manager_.ShutDown();
+ delete stack_thread_;
+ is_running_ = false;
+ return ::grpc::Status::OK;
+ }
+
+ private:
+ Thread* stack_thread_ = nullptr;
+ bool is_running_ = false;
+ std::thread* grpc_loop_thread_ = nullptr;
+ StackManager stack_manager_;
+ int grpc_port_ = 8898;
+};
+
+RootFacadeService* root_facade_service;
+} // namespace
+
+void GrpcRootServer::StartServer(const std::string& address, int grpc_root_server_port, int grpc_port) {
+ ASSERT(!started_);
+ started_ = true;
+
+ std::string listening_port = address + ":" + std::to_string(grpc_root_server_port);
+ ::grpc::ServerBuilder builder;
+ root_facade_service = new RootFacadeService(grpc_port);
+ builder.RegisterService(root_facade_service);
+ builder.AddListeningPort(listening_port, ::grpc::InsecureServerCredentials());
+ server_ = builder.BuildAndStart();
+
+ ASSERT(server_ != nullptr);
+}
+
+void GrpcRootServer::StopServer() {
+ ASSERT(started_);
+ server_->Shutdown();
+ started_ = false;
+ server_.reset();
+ delete root_facade_service;
+}
+
+void GrpcRootServer::RunGrpcLoop() {
+ ASSERT(started_);
+ server_->Wait();
+}
+
+} // namespace facade
+} // namespace bluetooth
diff --git a/gd/facade/grpc_root_server.h b/gd/facade/grpc_root_server.h
new file mode 100644
index 0000000..9deba35
--- /dev/null
+++ b/gd/facade/grpc_root_server.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include <grpc++/grpc++.h>
+
+namespace bluetooth {
+namespace facade {
+
+class GrpcRootServer {
+ public:
+ void StartServer(const std::string& address, int grpc_root_server_port, int grpc_port);
+
+ void StopServer();
+
+ void RunGrpcLoop();
+
+ private:
+ bool started_ = false;
+ std::unique_ptr<::grpc::Server> server_ = nullptr;
+};
+
+} // namespace facade
+} // namespace bluetooth
diff --git a/gd/facade/read_only_property_server.cc b/gd/facade/read_only_property_server.cc
new file mode 100644
index 0000000..3c57b87
--- /dev/null
+++ b/gd/facade/read_only_property_server.cc
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019 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 "facade/read_only_property_server.h"
+#include "hci/controller.h"
+
+namespace bluetooth {
+namespace facade {
+
+class ReadOnlyPropertyService : public ReadOnlyProperty::Service {
+ public:
+ ReadOnlyPropertyService(hci::Controller* controller) : controller_(controller) {}
+ ::grpc::Status ReadLocalAddress(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+ ::bluetooth::facade::BluetoothAddress* response) override {
+ auto address = controller_->GetControllerMacAddress().ToString();
+ response->set_address(address);
+ return ::grpc::Status::OK;
+ }
+
+ private:
+ hci::Controller* controller_;
+};
+
+void ReadOnlyPropertyServerModule::ListDependencies(ModuleList* list) {
+ GrpcFacadeModule::ListDependencies(list);
+ list->add<hci::Controller>();
+}
+void ReadOnlyPropertyServerModule::Start() {
+ GrpcFacadeModule::Start();
+ service_ = std::make_unique<ReadOnlyPropertyService>(GetDependency<hci::Controller>());
+}
+void ReadOnlyPropertyServerModule::Stop() {
+ service_.reset();
+ GrpcFacadeModule::Stop();
+}
+::grpc::Service* ReadOnlyPropertyServerModule::GetService() const {
+ return service_.get();
+}
+
+const ModuleFactory ReadOnlyPropertyServerModule::Factory =
+ ::bluetooth::ModuleFactory([]() { return new ReadOnlyPropertyServerModule(); });
+
+} // namespace facade
+} // namespace bluetooth
diff --git a/gd/facade/read_only_property_server.h b/gd/facade/read_only_property_server.h
new file mode 100644
index 0000000..dfac424
--- /dev/null
+++ b/gd/facade/read_only_property_server.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include <grpc++/grpc++.h>
+
+#include "facade/rootservice.grpc.pb.h"
+#include "grpc/grpc_module.h"
+
+namespace bluetooth {
+namespace facade {
+
+class ReadOnlyPropertyService;
+
+class ReadOnlyPropertyServerModule : public ::bluetooth::grpc::GrpcFacadeModule {
+ public:
+ static const ModuleFactory Factory;
+
+ void ListDependencies(ModuleList* list) override;
+ void Start() override;
+ void Stop() override;
+ ::grpc::Service* GetService() const override;
+
+ private:
+ std::unique_ptr<ReadOnlyPropertyService> service_;
+};
+
+} // namespace facade
+} // namespace bluetooth
diff --git a/gd/facade/rootservice.proto b/gd/facade/rootservice.proto
new file mode 100644
index 0000000..eec30ad
--- /dev/null
+++ b/gd/facade/rootservice.proto
@@ -0,0 +1,32 @@
+syntax = "proto3";
+
+package bluetooth.facade;
+
+import "google/protobuf/empty.proto";
+import "facade/common.proto";
+
+service RootFacade {
+ rpc StartStack(StartStackRequest) returns (StartStackResponse) {}
+ rpc StopStack(StopStackRequest) returns (StopStackResponse) {}
+}
+
+enum BluetoothModule {
+ HAL = 0;
+ HCI = 1;
+ L2CAP = 2;
+ SECURITY = 3;
+}
+
+message StartStackRequest {
+ BluetoothModule module_under_test = 1;
+}
+
+message StartStackResponse {}
+
+message StopStackRequest {}
+
+message StopStackResponse {}
+
+service ReadOnlyProperty {
+ rpc ReadLocalAddress(google.protobuf.Empty) returns (facade.BluetoothAddress) {}
+}
diff --git a/gd/fuzz_test.cc b/gd/fuzz_test.cc
new file mode 100644
index 0000000..ef358b5
--- /dev/null
+++ b/gd/fuzz_test.cc
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2019 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 <stddef.h>
+#include <stdint.h>
+
+extern void RunL2capClassicDynamicChannelAllocatorFuzzTest(const uint8_t* data, size_t size);
+extern void RunL2capPacketFuzzTest(const uint8_t* data, size_t size);
+extern void RunHciPacketFuzzTest(const uint8_t* data, size_t size);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ RunL2capClassicDynamicChannelAllocatorFuzzTest(data, size);
+ RunL2capPacketFuzzTest(data, size);
+ RunHciPacketFuzzTest(data, size);
+ return 0;
+}
\ No newline at end of file
diff --git a/gd/grpc/async_grpc.h b/gd/grpc/async_grpc.h
new file mode 100644
index 0000000..7cde95d
--- /dev/null
+++ b/gd/grpc/async_grpc.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <functional>
+#include <future>
+#include <memory>
+#include <mutex>
+
+#include <grpc++/grpc++.h>
+
+#include "os/log.h"
+
+namespace bluetooth {
+namespace grpc {
+
+// To be passed to gRPC async invocations as tag.
+// Function is called when the CompletionQueue.Next() returns this tag.
+// Then, user needs to delete this object.
+using GrpcAsyncEventCallback = std::function<void(bool)>;
+
+template <typename REQ, typename RES>
+class GrpcAsyncServerStreamingHandler {
+ public:
+ virtual ~GrpcAsyncServerStreamingHandler() = default;
+
+ // Implementation for requesting the next specific type RPC, using provided parameters.
+ virtual void OnReadyForNextRequest(::grpc::ServerContext*, REQ* req, ::grpc::ServerAsyncWriter<RES>* res,
+ ::grpc::CompletionQueue* new_call_cq,
+ ::grpc::ServerCompletionQueue* notification_cq, void* tag) = 0;
+
+ virtual void OnRpcRequestReceived(REQ req) = 0;
+
+ virtual void OnRpcRequestFailed() {}
+
+ virtual void OnRpcFinished() {}
+
+ virtual void OnWriteSuccess() {}
+};
+
+// Provides API to upper layer users to control (request, write, finish) a server-streaming asynchronous RPC.
+// When each API is done, callback will be sent to the given GrpcAsyncServerStreamingHandler.
+// Each control box can take one active RPC at one time.
+
+// TODO: problems with this control box:
+// 1. RequestNewRpc is async, but Write and Stop is blocking users. Do we want to do this?
+// 2. Callback to user is done in the gRPC thread. Let's create a pool thread to give it to user?
+// 3. Currently it uses promise to synchronize between events. If we use os/handler it should be easier.
+template <typename REQ, typename RES>
+class GrpcAsyncServerStreamingControlBox {
+ public:
+ GrpcAsyncServerStreamingControlBox(GrpcAsyncServerStreamingHandler<REQ, RES>* async_handler,
+ ::grpc::ServerCompletionQueue* cq)
+ : async_handler_(async_handler), cq_(cq) {}
+
+ void RequestNewRpc() {
+ ASSERT(my_state_ == MyState::IDLE);
+ context_ = std::make_unique<::grpc::ServerContext>();
+ req_ = std::make_unique<REQ>();
+ res_ = std::make_unique<::grpc::ServerAsyncWriter<RES>>(context_.get());
+ request_done_ = std::make_unique<GrpcAsyncEventCallback>([this](bool ok) { this->RequestDone(ok); });
+ async_handler_->OnReadyForNextRequest(context_.get(), req_.get(), res_.get(), cq_, cq_, request_done_.get());
+ my_state_ = MyState::REQUESTING;
+ }
+
+ void Write(const RES& res) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ if (my_state_ == MyState::IDLE || my_state_ == MyState::REQUESTING) {
+ LOG_INFO("stream already stopped");
+ return;
+ }
+ ASSERT(my_state_ == MyState::OPEN);
+ write_done_ = std::make_unique<GrpcAsyncEventCallback>([this](bool ok) { this->WriteDone(ok); });
+ my_state_ = MyState::WRITING;
+ res_->Write(res, write_done_.get());
+ promise_ = new std::promise<void>();
+ auto future = promise_->get_future();
+ future.wait();
+ }
+
+ void StopStreaming() {
+ std::unique_lock<std::mutex> lock(mutex_);
+ ASSERT(my_state_ == MyState::OPEN);
+ rpc_finish_ = std::make_unique<GrpcAsyncEventCallback>([this](bool ok) { this->RpcFinish(ok); });
+ my_state_ = MyState::FINISHING;
+ res_->Finish(::grpc::Status::OK, rpc_finish_.get());
+ promise_ = new std::promise<void>();
+ auto future = promise_->get_future();
+ future.wait();
+ }
+
+ private:
+ void RequestDone(bool ok) {
+ ASSERT(my_state_ == MyState::REQUESTING);
+ if (ok) {
+ async_handler_->OnRpcRequestReceived(*req_);
+ my_state_ = MyState::OPEN;
+ } else {
+ clean_up();
+ async_handler_->OnRpcRequestFailed();
+ my_state_ = MyState::IDLE;
+ }
+ }
+
+ void WriteDone(bool ok) {
+ ASSERT(my_state_ == MyState::WRITING);
+ if (ok) {
+ my_state_ = MyState::OPEN;
+ async_handler_->OnWriteSuccess();
+ } else {
+ clean_up();
+ my_state_ = MyState::IDLE;
+ async_handler_->OnRpcFinished();
+ }
+ promise_->set_value();
+ }
+
+ void RpcFinish(bool ok) {
+ ASSERT(ok);
+ ASSERT(my_state_ == MyState::FINISHING);
+ clean_up();
+ my_state_ = MyState::IDLE;
+ async_handler_->OnRpcFinished();
+ promise_->set_value();
+ }
+
+ void clean_up() {
+ context_ = nullptr;
+ req_ = nullptr;
+ res_ = nullptr;
+ }
+
+ mutable std::mutex mutex_;
+ std::promise<void>* promise_ = nullptr;
+
+ GrpcAsyncServerStreamingHandler<REQ, RES>* async_handler_;
+ ::grpc::ServerCompletionQueue* cq_;
+
+ std::unique_ptr<::grpc::ServerContext> context_ = nullptr;
+ std::unique_ptr<REQ> req_ = nullptr;
+ std::unique_ptr<::grpc::ServerAsyncWriter<RES>> res_ = nullptr;
+
+ std::unique_ptr<GrpcAsyncEventCallback> request_done_ = nullptr;
+ std::unique_ptr<GrpcAsyncEventCallback> write_done_ = nullptr;
+ std::unique_ptr<GrpcAsyncEventCallback> rpc_finish_ = nullptr;
+
+ enum class MyState { IDLE, REQUESTING, OPEN, WRITING, FINISHING } my_state_ = MyState::IDLE;
+};
+
+} // namespace grpc
+} // namespace bluetooth
diff --git a/gd/grpc/grpc_event_stream.h b/gd/grpc/grpc_event_stream.h
new file mode 100644
index 0000000..3ed4bee
--- /dev/null
+++ b/gd/grpc/grpc_event_stream.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <grpc++/grpc++.h>
+
+#include <chrono>
+
+#include "common/blocking_queue.h"
+#include "facade/common.pb.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace grpc {
+
+template <typename RES, typename EVENT>
+class GrpcEventStreamCallback {
+ public:
+ virtual ~GrpcEventStreamCallback() = default;
+ virtual void OnSubscribe() {}
+ virtual void OnUnsubscribe() {}
+ virtual void OnWriteResponse(RES* response, const EVENT& event) = 0;
+};
+
+template <typename RES, typename EVENT>
+class GrpcEventStream {
+ public:
+ explicit GrpcEventStream(GrpcEventStreamCallback<RES, EVENT>* callback) : callback_(callback) {}
+
+ void OnIncomingEvent(const EVENT& event) {
+ if (subscribed_) {
+ event_queue_.push(event);
+ }
+ }
+
+ ::grpc::Status HandleRequest(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
+ ::grpc::ServerWriter<RES>* writer) {
+ ::bluetooth::facade::EventSubscriptionMode subscription_mode = request->subscription_mode();
+ ::bluetooth::facade::EventFetchMode fetch_mode = request->fetch_mode();
+ uint32_t timeout_ms = request->timeout_ms();
+ if (timeout_ms == 0) {
+ timeout_ms = 3000;
+ }
+
+ if (subscription_mode == ::bluetooth::facade::SUBSCRIBE) {
+ event_queue_.clear();
+ callback_->OnSubscribe();
+ subscribed_ = true;
+ }
+
+ if (fetch_mode == ::bluetooth::facade::AT_LEAST_ONE) {
+ RES response;
+ if (!event_queue_.wait_to_take(std::chrono::milliseconds(timeout_ms))) {
+ return ::grpc::Status(::grpc::StatusCode::DEADLINE_EXCEEDED, "timeout exceeded");
+ }
+ EVENT event = event_queue_.take();
+ callback_->OnWriteResponse(&response, event);
+ writer->Write(response);
+ }
+
+ // fetch all current remaining items and append to AT_LEAST_ONE query if present
+ if (fetch_mode == ::bluetooth::facade::ALL_CURRENT || fetch_mode == ::bluetooth::facade::AT_LEAST_ONE) {
+ while (!event_queue_.empty()) {
+ RES response;
+ EVENT event = event_queue_.take();
+ callback_->OnWriteResponse(&response, event);
+ writer->Write(response);
+ }
+ }
+
+ if (subscription_mode == ::bluetooth::facade::UNSUBSCRIBE) {
+ subscribed_ = false;
+ event_queue_.clear();
+ callback_->OnUnsubscribe();
+ }
+
+ return ::grpc::Status::OK;
+ }
+
+ private:
+ common::BlockingQueue<EVENT> event_queue_;
+ GrpcEventStreamCallback<RES, EVENT>* callback_;
+ bool subscribed_ = false;
+};
+
+} // namespace grpc
+} // namespace bluetooth
diff --git a/gd/grpc/grpc_module.cc b/gd/grpc/grpc_module.cc
new file mode 100644
index 0000000..07d7bb0b
--- /dev/null
+++ b/gd/grpc/grpc_module.cc
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2019 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 "grpc/grpc_module.h"
+
+#include "os/log.h"
+#include "grpc/async_grpc.h"
+
+using ::grpc::Server;
+using ::grpc::ServerBuilder;
+
+namespace bluetooth {
+namespace grpc {
+
+void GrpcModule::ListDependencies(ModuleList* list) {
+}
+
+void GrpcModule::Start() {
+ ASSERT(!started_);
+}
+
+void GrpcModule::Stop() {
+ ASSERT(!started_);
+}
+
+void GrpcModule::StartServer(const std::string& address, int port) {
+ ASSERT(!started_);
+ started_ = true;
+
+ std::string listening_port = address + ":" + std::to_string(port);
+ ServerBuilder builder;
+
+ for (const auto& facade : facades_) {
+ builder.RegisterService(facade->GetService());
+ }
+
+ builder.AddListeningPort(listening_port, ::grpc::InsecureServerCredentials());
+ completion_queue_ = builder.AddCompletionQueue();
+ server_ = builder.BuildAndStart();
+ ASSERT(server_ != nullptr);
+
+ for (const auto& facade : facades_) {
+ facade->OnServerStarted(completion_queue_.get());
+ }
+}
+
+void GrpcModule::StopServer() {
+ ASSERT(started_);
+
+ server_->Shutdown();
+ completion_queue_->Shutdown();
+
+ for (const auto& facade : facades_) {
+ facade->OnServerStopped();
+ }
+
+ started_ = false;
+}
+
+void GrpcModule::Register(GrpcFacadeModule* facade) {
+ ASSERT(!started_);
+
+ facades_.push_back(facade);
+}
+
+void GrpcModule::Unregister(GrpcFacadeModule* facade) {
+ ASSERT(!started_);
+
+ for (auto it = facades_.begin(); it != facades_.end(); it++) {
+ if (*it == facade) {
+ facades_.erase(it);
+ return;
+ }
+ }
+
+ ASSERT(false);
+}
+
+void GrpcModule::RunGrpcLoop() {
+ void* tag;
+ bool ok;
+ while (true) {
+ if (!completion_queue_->Next(&tag, &ok)) {
+ LOG_INFO("gRPC is shutdown");
+ break;
+ }
+ auto* data = static_cast<GrpcAsyncEventCallback*>(tag);
+ (*data)(ok);
+ }
+}
+
+std::string GrpcModule::ToString() const {
+ return "Grpc Module";
+}
+
+const ::bluetooth::ModuleFactory GrpcModule::Factory = ::bluetooth::ModuleFactory([]() {
+ return new GrpcModule();
+});
+
+
+void GrpcFacadeModule::ListDependencies(ModuleList* list) {
+ list->add<GrpcModule>();
+}
+
+void GrpcFacadeModule::Start() {
+ GetDependency<GrpcModule>()->Register(this);
+}
+
+void GrpcFacadeModule::Stop() {
+ GetDependency<GrpcModule>()->Unregister(this);
+}
+
+std::string GrpcFacadeModule::ToString() const {
+ return "Grpc Facade Module";
+}
+
+} // namespace grpc
+} // namespace bluetooth
diff --git a/gd/grpc/grpc_module.h b/gd/grpc/grpc_module.h
new file mode 100644
index 0000000..15d3126
--- /dev/null
+++ b/gd/grpc/grpc_module.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <functional>
+#include <vector>
+
+#include <grpc++/grpc++.h>
+#include <module.h>
+
+namespace bluetooth {
+namespace grpc {
+
+class GrpcFacadeModule;
+
+class GrpcModule : public ::bluetooth::Module {
+ public:
+ static const ModuleFactory Factory;
+
+ void StartServer(const std::string& address, int port);
+
+ void StopServer();
+
+ void Register(GrpcFacadeModule* facade);
+
+ void Unregister(GrpcFacadeModule* facade);
+
+ // Blocks for incoming gRPC requests
+ void RunGrpcLoop();
+
+ protected:
+ void ListDependencies(ModuleList* list) override;
+
+ void Start() override;
+
+ void Stop() override;
+
+ std::string ToString() const override;
+
+ private:
+ bool started_;
+ std::unique_ptr<::grpc::Server> server_ = nullptr;
+ std::unique_ptr<::grpc::ServerCompletionQueue> completion_queue_ = nullptr;
+ std::vector<GrpcFacadeModule*> facades_;
+};
+
+class GrpcFacadeModule : public ::bluetooth::Module {
+ friend GrpcModule;
+ protected:
+ void ListDependencies(ModuleList* list) override;
+
+ void Start() override;
+
+ void Stop() override;
+
+ virtual ::grpc::Service* GetService() const = 0;
+
+ virtual void OnServerStarted(::grpc::ServerCompletionQueue* cq) {}
+
+ virtual void OnServerStopped() {}
+
+ std::string ToString() const override;
+};
+
+} // namespace grpc
+} // namespace bluetooth
diff --git a/gd/hal/Android.bp b/gd/hal/Android.bp
new file mode 100644
index 0000000..4c9fa2a
--- /dev/null
+++ b/gd/hal/Android.bp
@@ -0,0 +1,48 @@
+filegroup {
+ name: "BluetoothHalSources",
+ srcs: [
+ "snoop_logger.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothHalSources_hci_rootcanal",
+ srcs: [
+ "hci_hal_host_rootcanal.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothHalSources_hci_android_hidl",
+ srcs: [
+ "hci_hal_android_hidl.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothHalTestSources_hci_rootcanal",
+ srcs: [
+ "hci_hal_host_rootcanal_test.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothHalTestSources_hci_android_hidl",
+ srcs: [
+ "hci_hal_android_hidl_test.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothFacade_hci_hal",
+ srcs: [
+ "facade.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothCertSource_hci_hal",
+ srcs: [
+ "cert/cert.cc",
+ ],
+}
diff --git a/gd/hal/cert/api.proto b/gd/hal/cert/api.proto
new file mode 100644
index 0000000..6071dd1
--- /dev/null
+++ b/gd/hal/cert/api.proto
@@ -0,0 +1,38 @@
+syntax = "proto3";
+
+package bluetooth.hal.cert;
+
+import "google/protobuf/empty.proto";
+import "facade/common.proto";
+
+service HciHalCert {
+ rpc SendHciResetCommand(google.protobuf.Empty) returns (google.protobuf.Empty) {}
+ rpc SetScanMode(ScanModeSettings) returns (google.protobuf.Empty) {}
+ rpc SendHciCommand(HciCommandPacket) returns (google.protobuf.Empty) {}
+ rpc SendHciAcl(HciAclPacket) returns (google.protobuf.Empty) {}
+ rpc SendHciSco(HciScoPacket) returns (google.protobuf.Empty) {}
+
+ rpc FetchHciEvent(bluetooth.facade.EventStreamRequest) returns (stream HciEventPacket) {}
+ rpc FetchHciAcl(bluetooth.facade.EventStreamRequest) returns (stream HciAclPacket) {}
+ rpc FetchHciSco(bluetooth.facade.EventStreamRequest) returns (stream HciScoPacket) {}
+}
+
+message ScanModeSettings {
+ uint32 mode = 1;
+}
+
+message HciEventPacket {
+ bytes payload = 1;
+}
+
+message HciCommandPacket {
+ bytes payload = 1;
+}
+
+message HciAclPacket {
+ bytes payload = 1;
+}
+
+message HciScoPacket {
+ bytes payload = 1;
+}
diff --git a/gd/hal/cert/cert.cc b/gd/hal/cert/cert.cc
new file mode 100644
index 0000000..12240d3
--- /dev/null
+++ b/gd/hal/cert/cert.cc
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2019 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 "hal/cert/cert.h"
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+
+#include "common/blocking_queue.h"
+#include "grpc/grpc_event_stream.h"
+#include "hal/cert/api.grpc.pb.h"
+#include "hal/hci_hal.h"
+#include "hal/serialize_packet.h"
+#include "hci/hci_packets.h"
+
+namespace bluetooth {
+namespace hal {
+namespace cert {
+
+class HciHalCertService : public HciHalCert::Service, public ::bluetooth::hal::HciHalCallbacks {
+ public:
+ HciHalCertService(HciHal* hal)
+ : hal_(hal), hci_event_stream_(&hci_event_stream_callback_), hci_acl_stream_(&hci_acl_stream_callback_),
+ hci_sco_stream_(&hci_sco_stream_callback_) {
+ hal->registerIncomingPacketCallback(this);
+ }
+
+ ~HciHalCertService() {
+ hal_->unregisterIncomingPacketCallback();
+ }
+
+ ::grpc::Status SendHciResetCommand(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ can_send_hci_command_ = false;
+ hal_->sendHciCommand(SerializePacket(hci::ResetBuilder::Create()));
+ std::this_thread::sleep_for(std::chrono::milliseconds(300));
+ while (!can_send_hci_command_) {
+ cv_.wait(lock);
+ }
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SetScanMode(::grpc::ServerContext* context, const ScanModeSettings* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ can_send_hci_command_ = false;
+ unsigned int mode = request->mode();
+ hci::ScanEnable scan_enable;
+ switch (mode) {
+ case 0x00:
+ scan_enable = hci::ScanEnable::NO_SCANS;
+ break;
+ case 0x01:
+ scan_enable = hci::ScanEnable::INQUIRY_SCAN_ONLY;
+ break;
+ case 0x02:
+ scan_enable = hci::ScanEnable::PAGE_SCAN_ONLY;
+ break;
+ case 0x03:
+ scan_enable = hci::ScanEnable::INQUIRY_AND_PAGE_SCAN;
+ break;
+ }
+
+ hal_->sendHciCommand(SerializePacket(hci::WriteScanEnableBuilder::Create(scan_enable)));
+ while (!can_send_hci_command_) {
+ cv_.wait(lock);
+ }
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendHciCommand(::grpc::ServerContext* context, const ::bluetooth::hal::cert::HciCommandPacket* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ can_send_hci_command_ = false;
+ std::string req_string = request->payload();
+ hal_->sendHciCommand(std::vector<uint8_t>(req_string.begin(), req_string.end()));
+ while (!can_send_hci_command_) {
+ cv_.wait(lock);
+ }
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendHciAcl(::grpc::ServerContext* context, const ::bluetooth::hal::cert::HciAclPacket* request,
+ ::google::protobuf::Empty* response) override {
+ std::string req_string = request->payload();
+ hal_->sendAclData(std::vector<uint8_t>(req_string.begin(), req_string.end()));
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendHciSco(::grpc::ServerContext* context, const ::bluetooth::hal::cert::HciScoPacket* request,
+ ::google::protobuf::Empty* response) override {
+ std::string req_string = request->payload();
+ hal_->sendScoData(std::vector<uint8_t>(req_string.begin(), req_string.end()));
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status FetchHciEvent(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
+ ::grpc::ServerWriter<HciEventPacket>* writer) override {
+ return hci_event_stream_.HandleRequest(context, request, writer);
+ };
+
+ ::grpc::Status FetchHciAcl(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
+ ::grpc::ServerWriter<HciAclPacket>* writer) override {
+ return hci_acl_stream_.HandleRequest(context, request, writer);
+ };
+
+ ::grpc::Status FetchHciSco(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
+ ::grpc::ServerWriter<HciScoPacket>* writer) override {
+ return hci_sco_stream_.HandleRequest(context, request, writer);
+ };
+
+ void hciEventReceived(bluetooth::hal::HciPacket event) override {
+ std::string response_str = std::string(event.begin(), event.end());
+ hci_event_stream_.OnIncomingEvent(event);
+ can_send_hci_command_ = true;
+ cv_.notify_one();
+ }
+
+ void aclDataReceived(bluetooth::hal::HciPacket data) override {
+ hci_acl_stream_.OnIncomingEvent(data);
+ }
+
+ void scoDataReceived(bluetooth::hal::HciPacket data) override {
+ hci_sco_stream_.OnIncomingEvent(data);
+ }
+
+ private:
+ HciHal* hal_;
+ bool can_send_hci_command_ = true;
+ mutable std::mutex mutex_;
+ std::condition_variable cv_;
+
+ class HciEventStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciEventPacket, HciPacket> {
+ public:
+ void OnWriteResponse(HciEventPacket* response, const HciPacket& event) override {
+ std::string response_str = std::string(event.begin(), event.end());
+ response->set_payload(std::string(event.begin(), event.end()));
+ }
+ } hci_event_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<HciEventPacket, HciPacket> hci_event_stream_;
+
+ class HciAclStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciAclPacket, HciPacket> {
+ public:
+ void OnWriteResponse(HciAclPacket* response, const HciPacket& event) override {
+ response->set_payload(std::string(event.begin(), event.end()));
+ }
+ } hci_acl_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<HciAclPacket, HciPacket> hci_acl_stream_;
+
+ class HciScoStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciScoPacket, HciPacket> {
+ public:
+ void OnWriteResponse(HciScoPacket* response, const HciPacket& event) override {
+ response->set_payload(std::string(event.begin(), event.end()));
+ }
+ } hci_sco_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<HciScoPacket, HciPacket> hci_sco_stream_;
+};
+
+void HalCertModule::ListDependencies(ModuleList* list) {
+ ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
+ list->add<HciHal>();
+}
+
+void HalCertModule::Start() {
+ ::bluetooth::grpc::GrpcFacadeModule::Start();
+ service_ = new HciHalCertService(GetDependency<HciHal>());
+}
+
+void HalCertModule::Stop() {
+ delete service_;
+ ::bluetooth::grpc::GrpcFacadeModule::Stop();
+}
+
+::grpc::Service* HalCertModule::GetService() const {
+ return service_;
+}
+
+const ModuleFactory HalCertModule::Factory = ::bluetooth::ModuleFactory([]() {
+ return new HalCertModule();
+});
+
+} // namespace cert
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/cert/cert.h b/gd/hal/cert/cert.h
new file mode 100644
index 0000000..7dba43d
--- /dev/null
+++ b/gd/hal/cert/cert.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <grpc++/grpc++.h>
+
+#include "grpc/grpc_module.h"
+
+namespace bluetooth {
+namespace hal {
+namespace cert {
+
+class HciHalCertService;
+
+class HalCertModule : public ::bluetooth::grpc::GrpcFacadeModule {
+ public:
+ static const ModuleFactory Factory;
+
+ void ListDependencies(ModuleList* list) override;
+
+ void Start() override;
+ void Stop() override;
+
+ ::grpc::Service* GetService() const override;
+
+ private:
+ HciHalCertService* service_;
+};
+
+} // namespace cert
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/cert/simple_hal_test.py b/gd/hal/cert/simple_hal_test.py
new file mode 100644
index 0000000..d8e54d0f
--- /dev/null
+++ b/gd/hal/cert/simple_hal_test.py
@@ -0,0 +1,312 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 - 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.
+
+from __future__ import print_function
+
+import os
+import sys
+sys.path.append(os.environ['ANDROID_BUILD_TOP'] + '/system/bt/gd')
+
+from cert.gd_base_test import GdBaseTestClass
+from cert.event_stream import EventStream
+from cert import rootservice_pb2 as cert_rootservice_pb2
+from facade import common_pb2
+from google.protobuf import empty_pb2
+from facade import rootservice_pb2 as facade_rootservice_pb2
+from hal.cert import api_pb2 as hal_cert_pb2
+from hal import facade_pb2 as hal_facade_pb2
+
+class SimpleHalTest(GdBaseTestClass):
+
+ def setup_test(self):
+ self.device_under_test = self.gd_devices[0]
+ self.cert_device = self.gd_cert_devices[0]
+
+ self.device_under_test.rootservice.StartStack(
+ facade_rootservice_pb2.StartStackRequest(
+ module_under_test=facade_rootservice_pb2.BluetoothModule.Value('HAL'),
+ )
+ )
+ self.cert_device.rootservice.StartStack(
+ cert_rootservice_pb2.StartStackRequest(
+ module_to_test=cert_rootservice_pb2.BluetoothModule.Value('HAL'),
+ )
+ )
+
+ self.device_under_test.wait_channel_ready()
+ self.cert_device.wait_channel_ready()
+
+ self.device_under_test.hal.SendHciResetCommand(empty_pb2.Empty())
+ self.cert_device.hal.SendHciResetCommand(empty_pb2.Empty())
+
+ self.hci_event_stream = self.device_under_test.hal.hci_event_stream
+ self.cert_hci_event_stream = self.cert_device.hal.hci_event_stream
+ self.hci_acl_stream = self.device_under_test.hal.hci_acl_stream
+ self.cert_hci_acl_stream = self.cert_device.hal.hci_acl_stream
+
+ def teardown_test(self):
+ self.device_under_test.rootservice.StopStack(
+ facade_rootservice_pb2.StopStackRequest()
+ )
+ self.cert_device.rootservice.StopStack(
+ cert_rootservice_pb2.StopStackRequest()
+ )
+ self.hci_event_stream.clear_event_buffer()
+ self.cert_hci_event_stream.clear_event_buffer()
+
+ def test_none_event(self):
+ self.hci_event_stream.clear_event_buffer()
+
+ self.hci_event_stream.subscribe()
+ self.hci_event_stream.assert_none()
+ self.hci_event_stream.unsubscribe()
+
+ def test_example(self):
+ response = self.device_under_test.hal.SetLoopbackMode(
+ hal_facade_pb2.LoopbackModeSettings(enable=True)
+ )
+
+ def test_fetch_hci_event(self):
+ self.device_under_test.hal.SetLoopbackMode(
+ hal_facade_pb2.LoopbackModeSettings(enable=True)
+ )
+
+ self.hci_event_stream.subscribe()
+
+ self.device_under_test.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x01\x04\x053\x8b\x9e0\x01'
+ )
+ )
+
+ self.hci_event_stream.assert_event_occurs(
+ lambda packet: packet.payload == b'\x19\x08\x01\x04\x053\x8b\x9e0\x01'
+ )
+ self.hci_event_stream.unsubscribe()
+
+ def test_inquiry_from_dut(self):
+ self.hci_event_stream.subscribe()
+
+ self.cert_device.hal.SetScanMode(
+ hal_cert_pb2.ScanModeSettings(mode=3)
+ )
+ self.device_under_test.hal.SetInquiry(
+ hal_facade_pb2.InquirySettings(length=0x30, num_responses=0xff)
+ )
+ self.hci_event_stream.assert_event_occurs(
+ lambda packet: b'\x02\x0f' in packet.payload
+ # Expecting an HCI Event (code 0x02, length 0x0f)
+ )
+ self.hci_event_stream.unsubscribe()
+
+ def test_le_ad_scan_cert_advertises(self):
+ self.hci_event_stream.subscribe()
+
+ # Set the LE Address to 0D:05:04:03:02:01
+ self.device_under_test.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x05\x20\x06\x01\x02\x03\x04\x05\x0D'
+ )
+ )
+ # Set the LE Scan parameters (active, 40ms, 20ms, Random,
+ self.device_under_test.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x0B\x20\x07\x01\x40\x00\x20\x00\x01\x00'
+ )
+ )
+ # Enable Scanning (Disable duplicate filtering)
+ self.device_under_test.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x0C\x20\x02\x01\x00'
+ )
+ )
+
+ # Set the LE Address to 0C:05:04:03:02:01
+ self.cert_device.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x05\x20\x06\x01\x02\x03\x04\x05\x0C'
+ )
+ )
+ # Set LE Advertising parameters
+ self.cert_device.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x06\x20\x0F\x00\x02\x00\x03\x00\x01\x00\xA1\xA2\xA3\xA4\xA5\xA6\x07\x00'
+ )
+ )
+ # Set LE Advertising data
+ self.cert_device.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x08\x20\x20\x0C\x0A\x09Im_A_Cert\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+ )
+ )
+ # Enable Advertising
+ self.cert_device.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x0A\x20\x01\x01'
+ )
+ )
+ self.hci_event_stream.assert_event_occurs(
+ lambda packet: b'Im_A_Cert' in packet.payload
+ # Expecting an HCI Event (code 0x3e, length 0x13, subevent 0x01 )
+ )
+ # Disable Advertising
+ self.cert_device.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x0A\x20\x01\x00'
+ )
+ )
+ # Disable Scanning
+ self.device_under_test.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x0C\x20\x02\x00\x00'
+ )
+ )
+ self.hci_event_stream.unsubscribe()
+
+ def test_le_connection_dut_advertises(self):
+ self.hci_event_stream.subscribe()
+ self.cert_hci_event_stream.subscribe()
+ self.hci_acl_stream.subscribe()
+ self.cert_hci_acl_stream.subscribe()
+
+ # Set the CERT LE Address to 0C:05:04:03:02:01
+ self.cert_device.hal.SendHciCommand(
+ hal_cert_pb2.HciCommandPacket(
+ payload=b'\x05\x20\x06\x01\x02\x03\x04\x05\x0C'
+ )
+ )
+
+ # Direct connect to 0D:05:04:03:02:01
+ self.cert_device.hal.SendHciCommand(
+ hal_cert_pb2.HciCommandPacket(
+ payload=b'\x0D\x20\x19\x11\x01\x22\x02\x00\x01\x01\x02\x03\x04\x05\x0D\x01\x06\x00\x70\x0C\x40\x00\x03\x07\x01\x00\x02\x00'
+ )
+ )
+
+ # Set the LE Address to 0D:05:04:03:02:01
+ self.device_under_test.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x05\x20\x06\x01\x02\x03\x04\x05\x0D'
+ )
+ )
+ # Set LE Advertising parameters
+ self.device_under_test.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x06\x20\x0F\x80\x00\x00\x04\x00\x01\x00\xA1\xA2\xA3\xA4\xA5\xA6\x07\x00'
+ )
+ )
+ # Set LE Advertising data
+ self.device_under_test.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x08\x20\x20\x0C\x0B\x09Im_The_DUT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+ )
+ )
+ # Enable Advertising
+ self.device_under_test.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x0A\x20\x01\x01'
+ )
+ )
+ # LeConnectionComplete TODO: Extract the handle
+ self.cert_hci_event_stream.assert_event_occurs(
+ lambda packet: b'\x3e\x13\x01\x00' in packet.payload
+ )
+ # LeConnectionComplete TODO: Extract the handle
+ self.hci_event_stream.assert_event_occurs(
+ lambda packet: b'\x3e\x13\x01\x00' in packet.payload
+ )
+ # Send ACL Data
+ self.device_under_test.hal.SendHciAcl(
+ hal_facade_pb2.HciAclPacket(
+ payload=b'\xfe\x0e\x0b\x00SomeAclData'
+ )
+ )
+ # Send ACL Data
+ self.cert_device.hal.SendHciAcl(
+ hal_facade_pb2.HciAclPacket(
+ payload=b'\xfe\x0e\x0f\x00SomeMoreAclData'
+ )
+ )
+ self.cert_hci_acl_stream.assert_event_occurs(
+ lambda packet: b'\xfe\x0e\x0b\x00SomeAclData' in packet.payload
+ )
+ self.hci_acl_stream.assert_event_occurs(
+ lambda packet: b'\xfe\x0e\x0f\x00SomeMoreAclData' in packet.payload
+ )
+
+ self.hci_event_stream.unsubscribe()
+ self.cert_hci_event_stream.unsubscribe()
+ self.hci_acl_stream.unsubscribe()
+ self.cert_hci_acl_stream.unsubscribe()
+
+ def test_le_white_list_connection_cert_advertises(self):
+ self.hci_event_stream.subscribe()
+ self.cert_hci_event_stream.subscribe()
+
+ # Set the LE Address to 0D:05:04:03:02:01
+ self.device_under_test.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x05\x20\x06\x01\x02\x03\x04\x05\x0D'
+ )
+ )
+ # Add the cert device to the white list (Random 0C:05:04:03:02:01)
+ self.device_under_test.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x11\x20\x07\x01\x01\x02\x03\x04\x05\x0C'
+ )
+ )
+ # Connect using the white list
+ self.device_under_test.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x0D\x20\x19\x11\x01\x22\x02\x01\x00\xA1\xA2\xA3\xA4\xA5\xA6\x01\x06\x00\x70\x0C\x40\x00\x03\x07\x01\x00\x02\x00'
+ )
+ )
+
+ # Set the LE Address to 0C:05:04:03:02:01
+ self.cert_device.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x05\x20\x06\x01\x02\x03\x04\x05\x0C'
+ )
+ )
+ # Set LE Advertising parameters
+ self.cert_device.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x06\x20\x0F\x00\x02\x00\x03\x00\x01\x00\xA1\xA2\xA3\xA4\xA5\xA6\x07\x00'
+ )
+ )
+ # Set LE Advertising data
+ self.cert_device.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x08\x20\x20\x0C\x0A\x09Im_A_Cert\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
+ )
+ )
+ # Enable Advertising
+ self.cert_device.hal.SendHciCommand(
+ hal_facade_pb2.HciCommandPacket(
+ payload=b'\x0A\x20\x01\x01'
+ )
+ )
+ # LeConnectionComplete
+ self.cert_hci_event_stream.assert_event_occurs(
+ lambda packet: b'\x3e\x13\x01\x00' in packet.payload
+ )
+ # LeConnectionComplete
+ self.hci_event_stream.assert_event_occurs(
+ lambda packet: b'\x3e\x13\x01\x00' in packet.payload
+ )
+
+ self.hci_event_stream.unsubscribe()
+ self.cert_hci_event_stream.unsubscribe()
diff --git a/gd/hal/facade.cc b/gd/hal/facade.cc
new file mode 100644
index 0000000..ce25103
--- /dev/null
+++ b/gd/hal/facade.cc
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2019 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 "hal/facade.h"
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+
+#include "common/blocking_queue.h"
+#include "grpc/grpc_event_stream.h"
+#include "hal/facade.grpc.pb.h"
+#include "hal/hci_hal.h"
+#include "hal/serialize_packet.h"
+#include "hci/hci_packets.h"
+
+using ::grpc::ServerAsyncResponseWriter;
+using ::grpc::ServerAsyncWriter;
+using ::grpc::ServerContext;
+
+using ::bluetooth::facade::EventStreamRequest;
+
+namespace bluetooth {
+namespace hal {
+
+class HciHalFacadeService
+ : public HciHalFacade::Service,
+ public ::bluetooth::hal::HciHalCallbacks {
+ public:
+ HciHalFacadeService(HciHal* hal)
+ : hal_(hal), hci_event_stream_(&hci_event_stream_callback_), hci_acl_stream_(&hci_acl_stream_callback_),
+ hci_sco_stream_(&hci_sco_stream_callback_) {
+ hal->registerIncomingPacketCallback(this);
+ }
+
+ ~HciHalFacadeService() {
+ hal_->unregisterIncomingPacketCallback();
+ }
+
+ ::grpc::Status SendHciResetCommand(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ can_send_hci_command_ = false;
+ hal_->sendHciCommand(SerializePacket(hci::ResetBuilder::Create()));
+ while (!can_send_hci_command_) {
+ cv_.wait(lock);
+ }
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SetLoopbackMode(::grpc::ServerContext* context,
+ const ::bluetooth::hal::LoopbackModeSettings* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ can_send_hci_command_ = false;
+ bool enable = request->enable();
+ hal_->sendHciCommand(SerializePacket(hci::WriteLoopbackModeBuilder::Create(
+ enable ? hci::LoopbackMode::ENABLE_LOCAL : hci::LoopbackMode::NO_LOOPBACK)));
+ while (!can_send_hci_command_) {
+ cv_.wait(lock);
+ }
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SetInquiry(::grpc::ServerContext* context, const ::bluetooth::hal::InquirySettings* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ can_send_hci_command_ = false;
+ hci::Lap lap;
+ lap.lap_ = 0x33;
+
+ hal_->sendHciCommand(SerializePacket(hci::InquiryBuilder::Create(lap, static_cast<uint8_t>(request->length()),
+ static_cast<uint8_t>(request->num_responses()))));
+ while (!can_send_hci_command_) {
+ cv_.wait(lock);
+ }
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendHciCommand(::grpc::ServerContext* context, const ::bluetooth::hal::HciCommandPacket* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ can_send_hci_command_ = false;
+ std::string req_string = request->payload();
+ hal_->sendHciCommand(std::vector<uint8_t>(req_string.begin(), req_string.end()));
+ while (!can_send_hci_command_) {
+ cv_.wait(lock);
+ }
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendHciAcl(::grpc::ServerContext* context, const ::bluetooth::hal::HciAclPacket* request,
+ ::google::protobuf::Empty* response) override {
+ std::string req_string = request->payload();
+ hal_->sendAclData(std::vector<uint8_t>(req_string.begin(), req_string.end()));
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendHciSco(::grpc::ServerContext* context, const ::bluetooth::hal::HciScoPacket* request,
+ ::google::protobuf::Empty* response) override {
+ std::string req_string = request->payload();
+ hal_->sendScoData(std::vector<uint8_t>(req_string.begin(), req_string.end()));
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status FetchHciEvent(::grpc::ServerContext* context, const EventStreamRequest* request,
+ ::grpc::ServerWriter<HciEventPacket>* writer) override {
+ return hci_event_stream_.HandleRequest(context, request, writer);
+ };
+
+ ::grpc::Status FetchHciAcl(::grpc::ServerContext* context, const EventStreamRequest* request,
+ ::grpc::ServerWriter<HciAclPacket>* writer) override {
+ return hci_acl_stream_.HandleRequest(context, request, writer);
+ };
+
+ ::grpc::Status FetchHciSco(::grpc::ServerContext* context, const EventStreamRequest* request,
+ ::grpc::ServerWriter<HciScoPacket>* writer) override {
+ return hci_sco_stream_.HandleRequest(context, request, writer);
+ };
+
+ void hciEventReceived(bluetooth::hal::HciPacket event) override {
+ std::string response_str = std::string(event.begin(), event.end());
+ hci_event_stream_.OnIncomingEvent(event);
+ can_send_hci_command_ = true;
+ cv_.notify_one();
+ }
+
+ void aclDataReceived(bluetooth::hal::HciPacket data) override {
+ hci_acl_stream_.OnIncomingEvent(data);
+ }
+
+ void scoDataReceived(bluetooth::hal::HciPacket data) override {
+ hci_sco_stream_.OnIncomingEvent(data);
+ }
+
+ private:
+ HciHal* hal_;
+ bool can_send_hci_command_ = true;
+ mutable std::mutex mutex_;
+ std::condition_variable cv_;
+
+ class HciEventStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciEventPacket, HciPacket> {
+ public:
+ void OnWriteResponse(HciEventPacket* response, const HciPacket& event) override {
+ std::string response_str = std::string(event.begin(), event.end());
+ response->set_payload(std::string(event.begin(), event.end()));
+ }
+ } hci_event_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<HciEventPacket, HciPacket> hci_event_stream_;
+
+ class HciAclStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciAclPacket, HciPacket> {
+ public:
+ void OnWriteResponse(HciAclPacket* response, const HciPacket& event) override {
+ response->set_payload(std::string(event.begin(), event.end()));
+ }
+ } hci_acl_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<HciAclPacket, HciPacket> hci_acl_stream_;
+
+ class HciScoStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<HciScoPacket, HciPacket> {
+ public:
+ void OnWriteResponse(HciScoPacket* response, const HciPacket& event) override {
+ response->set_payload(std::string(event.begin(), event.end()));
+ }
+ } hci_sco_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<HciScoPacket, HciPacket> hci_sco_stream_;
+};
+
+void HciHalFacadeModule::ListDependencies(ModuleList* list) {
+ ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
+ list->add<HciHal>();
+}
+
+void HciHalFacadeModule::Start() {
+ ::bluetooth::grpc::GrpcFacadeModule::Start();
+ service_ = new HciHalFacadeService(GetDependency<HciHal>());
+}
+
+void HciHalFacadeModule::Stop() {
+ delete service_;
+ ::bluetooth::grpc::GrpcFacadeModule::Stop();
+}
+
+::grpc::Service* HciHalFacadeModule::GetService() const {
+ return service_;
+}
+
+const ModuleFactory HciHalFacadeModule::Factory = ::bluetooth::ModuleFactory([]() {
+ return new HciHalFacadeModule();
+});
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/facade.h b/gd/hal/facade.h
new file mode 100644
index 0000000..fa28d10
--- /dev/null
+++ b/gd/hal/facade.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <list>
+#include <mutex>
+
+#include <grpc++/grpc++.h>
+
+#include "grpc/grpc_module.h"
+#include "hal/hci_hal.h"
+
+namespace bluetooth {
+namespace hal {
+
+class HciHalFacadeService;
+
+class HciHalFacadeModule : public ::bluetooth::grpc::GrpcFacadeModule {
+ public:
+ static const ModuleFactory Factory;
+
+ void ListDependencies(ModuleList* list) override;
+
+ void Start() override;
+ void Stop() override;
+
+ ::grpc::Service* GetService() const override;
+
+ private:
+ HciHalFacadeService* service_;
+};
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/facade.proto b/gd/hal/facade.proto
new file mode 100644
index 0000000..45919fe
--- /dev/null
+++ b/gd/hal/facade.proto
@@ -0,0 +1,48 @@
+syntax = "proto3";
+
+package bluetooth.hal;
+
+import "google/protobuf/empty.proto";
+import "facade/common.proto";
+
+service HciHalFacade {
+ rpc SendHciResetCommand(google.protobuf.Empty) returns (google.protobuf.Empty) {}
+ rpc SetLoopbackMode(LoopbackModeSettings) returns (google.protobuf.Empty) {}
+ rpc SetInquiry(InquirySettings) returns (google.protobuf.Empty) {}
+ rpc SendHciCommand(HciCommandPacket) returns (google.protobuf.Empty) {}
+ rpc SendHciAcl(HciAclPacket) returns (google.protobuf.Empty) {}
+ rpc SendHciSco(HciScoPacket) returns (google.protobuf.Empty) {}
+
+ rpc FetchHciEvent(bluetooth.facade.EventStreamRequest) returns (stream HciEventPacket) {}
+ rpc FetchHciAcl(bluetooth.facade.EventStreamRequest) returns (stream HciAclPacket) {}
+ rpc FetchHciSco(bluetooth.facade.EventStreamRequest) returns (stream HciScoPacket) {}
+}
+
+message LoopbackModeSettings {
+ bool enable = 1;
+}
+
+message ScanModeSettings {
+ uint32 mode = 1;
+}
+
+message InquirySettings {
+ uint32 length = 1;
+ uint32 num_responses = 2;
+}
+
+message HciEventPacket {
+ bytes payload = 1;
+}
+
+message HciCommandPacket {
+ bytes payload = 1;
+}
+
+message HciAclPacket {
+ bytes payload = 1;
+}
+
+message HciScoPacket {
+ bytes payload = 1;
+}
diff --git a/gd/hal/hci_hal.h b/gd/hal/hci_hal.h
new file mode 100644
index 0000000..f95a4f9
--- /dev/null
+++ b/gd/hal/hci_hal.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <vector>
+
+#include "module.h"
+
+namespace bluetooth {
+namespace hal {
+
+using HciPacket = std::vector<uint8_t>;
+
+enum class Status : int32_t { SUCCESS, TRANSPORT_ERROR, INITIALIZATION_ERROR, UNKNOWN };
+
+// Mirrors hardware/interfaces/bluetooth/1.0/IBluetoothHciCallbacks.hal in Android, but moved initializationComplete
+// callback to BluetoothInitializationCompleteCallback
+
+// The interface from the Bluetooth Controller to the stack
+class HciHalCallbacks {
+ public:
+ virtual ~HciHalCallbacks() = default;
+
+ // This function is invoked when an HCI event is received from the
+ // Bluetooth controller to be forwarded to the Bluetooth stack
+ // @param event is the HCI event to be sent to the Bluetooth stack
+ virtual void hciEventReceived(HciPacket event) = 0;
+
+ // Send an ACL data packet form the controller to the host
+ // @param data the ACL HCI packet to be passed to the host stack
+ virtual void aclDataReceived(HciPacket data) = 0;
+
+ // Send a SCO data packet form the controller to the host
+ // @param data the SCO HCI packet to be passed to the host stack
+ virtual void scoDataReceived(HciPacket data) = 0;
+};
+
+// Mirrors hardware/interfaces/bluetooth/1.0/IBluetoothHci.hal in Android
+// The Host Controller Interface (HCI) is the layer defined by the Bluetooth
+// specification between the software that runs on the host and the Bluetooth
+// controller chip. This boundary is the natural choice for a Hardware
+// Abstraction Layer (HAL). Dealing only in HCI packets and events simplifies
+// the stack and abstracts away power management, initialization, and other
+// implementation-specific details related to the hardware.
+class HciHal : public ::bluetooth::Module {
+ public:
+ static const ModuleFactory Factory;
+
+ virtual ~HciHal() = default;
+
+ // Register the callback for incoming packets. All incoming packets are dropped before
+ // this callback is registered. Callback can only be registered once.
+ //
+ // @param callback implements BluetoothHciHalCallbacks which will
+ // receive callbacks when incoming HCI packets are received
+ // from the controller to be sent to the host.
+ virtual void registerIncomingPacketCallback(HciHalCallbacks* callback) = 0;
+
+ // Unregister the callback for incoming packets. Drop all further incoming packets.
+ virtual void unregisterIncomingPacketCallback() = 0;
+
+ // Send an HCI command (as specified in the Bluetooth Specification
+ // V4.2, Vol 2, Part 5, Section 5.4.1) to the Bluetooth controller.
+ // Commands must be executed in order.
+ virtual void sendHciCommand(HciPacket command) = 0;
+
+ // Send an HCI ACL data packet (as specified in the Bluetooth Specification
+ // V4.2, Vol 2, Part 5, Section 5.4.2) to the Bluetooth controller.
+ // Packets must be processed in order.
+ virtual void sendAclData(HciPacket data) = 0;
+
+ // Send an SCO data packet (as specified in the Bluetooth Specification
+ // V4.2, Vol 2, Part 5, Section 5.4.3) to the Bluetooth controller.
+ // Packets must be processed in order.
+ virtual void sendScoData(HciPacket data) = 0;
+};
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/hci_hal_android_hidl.cc b/gd/hal/hci_hal_android_hidl.cc
new file mode 100644
index 0000000..7e45d89
--- /dev/null
+++ b/gd/hal/hci_hal_android_hidl.cc
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2019 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 "hal/hci_hal.h"
+
+#include <stdlib.h>
+#include <vector>
+#include <future>
+
+#include <android/hardware/bluetooth/1.0/IBluetoothHci.h>
+#include <android/hardware/bluetooth/1.0/IBluetoothHciCallbacks.h>
+#include <android/hardware/bluetooth/1.0/types.h>
+
+#include "hal/snoop_logger.h"
+#include "os/log.h"
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::hardware::bluetooth::V1_0::IBluetoothHci;
+using ::android::hardware::bluetooth::V1_0::IBluetoothHciCallbacks;
+using HidlStatus = ::android::hardware::bluetooth::V1_0::Status;
+
+namespace bluetooth {
+namespace hal {
+namespace {
+
+class HciDeathRecipient : public ::android::hardware::hidl_death_recipient {
+ public:
+ virtual void serviceDied(uint64_t /*cookie*/, const android::wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
+ LOG_ERROR("Bluetooth HAL service died!");
+ abort();
+ }
+};
+
+android::sp<HciDeathRecipient> hci_death_recipient_ = new HciDeathRecipient();
+
+class InternalHciCallbacks : public IBluetoothHciCallbacks {
+ public:
+ InternalHciCallbacks(SnoopLogger* btsnoop_logger)
+ : btsnoop_logger_(btsnoop_logger) {
+ init_promise_ = new std::promise<void>();
+ }
+
+ void SetCallback(HciHalCallbacks* callback) {
+ ASSERT(callback_ == nullptr && callback != nullptr);
+ callback_ = callback;
+ }
+
+ void ResetCallback() {
+ callback_ = nullptr;
+ }
+
+ std::promise<void>* GetInitPromise() {
+ return init_promise_;
+ }
+
+ Return<void> initializationComplete(HidlStatus status) {
+ ASSERT(status == HidlStatus::SUCCESS);
+ init_promise_->set_value();
+ return Void();
+ }
+
+ Return<void> hciEventReceived(const hidl_vec<uint8_t>& event) {
+ std::vector<uint8_t> received_hci_packet(event.begin(), event.end());
+ btsnoop_logger_->capture(received_hci_packet, SnoopLogger::Direction::INCOMING,
+ SnoopLogger::PacketType::EVT);
+ if (callback_ != nullptr) {
+ callback_->hciEventReceived(std::move(received_hci_packet));
+ }
+ return Void();
+ }
+
+ Return<void> aclDataReceived(const hidl_vec<uint8_t>& data) {
+ std::vector<uint8_t> received_hci_packet(data.begin(), data.end());
+ btsnoop_logger_->capture(received_hci_packet, SnoopLogger::Direction::INCOMING,
+ SnoopLogger::PacketType::ACL);
+ if (callback_ != nullptr) {
+ callback_->aclDataReceived(std::move(received_hci_packet));
+ }
+ return Void();
+ }
+
+ Return<void> scoDataReceived(const hidl_vec<uint8_t>& data) {
+ std::vector<uint8_t> received_hci_packet(data.begin(), data.end());
+ btsnoop_logger_->capture(received_hci_packet, SnoopLogger::Direction::INCOMING,
+ SnoopLogger::PacketType::SCO);
+ if (callback_ != nullptr) {
+ callback_->scoDataReceived(std::move(received_hci_packet));
+ }
+ return Void();
+ }
+
+ private:
+ std::promise<void>* init_promise_ = nullptr;
+ HciHalCallbacks* callback_ = nullptr;
+ SnoopLogger* btsnoop_logger_ = nullptr;
+};
+
+} // namespace
+
+const std::string SnoopLogger::DefaultFilePath = "/data/misc/bluetooth/logs/btsnoop_hci.log";
+const bool SnoopLogger::AlwaysFlush = false;
+
+class HciHalHidl : public HciHal {
+ public:
+ void registerIncomingPacketCallback(HciHalCallbacks* callback) override {
+ callbacks_->SetCallback(callback);
+ }
+
+ void unregisterIncomingPacketCallback() override {
+ callbacks_->ResetCallback();
+ }
+
+ void sendHciCommand(HciPacket command) override {
+ btsnoop_logger_->capture(command, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::CMD);
+ bt_hci_->sendHciCommand(command);
+ }
+
+ void sendAclData(HciPacket packet) override {
+ btsnoop_logger_->capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::ACL);
+ bt_hci_->sendAclData(packet);
+ }
+
+ void sendScoData(HciPacket packet) override {
+ btsnoop_logger_->capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::SCO);
+ bt_hci_->sendScoData(packet);
+ }
+
+ protected:
+ void ListDependencies(ModuleList* list) override {
+ list->add<SnoopLogger>();
+ }
+
+ void Start() override {
+ btsnoop_logger_ = GetDependency<SnoopLogger>();
+ bt_hci_ = IBluetoothHci::getService();
+ ASSERT(bt_hci_ != nullptr);
+ auto death_link = bt_hci_->linkToDeath(hci_death_recipient_, 0);
+ ASSERT_LOG(death_link.isOk(), "Unable to set the death recipient for the Bluetooth HAL");
+ // Block allows allocation of a variable that might be bypassed by goto.
+ {
+ callbacks_ = new InternalHciCallbacks(btsnoop_logger_);
+ bt_hci_->initialize(callbacks_);
+ // Don't timeout here, time out at a higher layer
+ callbacks_->GetInitPromise()->get_future().wait();
+ }
+ }
+
+ void Stop() override {
+ ASSERT(bt_hci_ != nullptr);
+ auto death_unlink = bt_hci_->unlinkToDeath(hci_death_recipient_);
+ if (!death_unlink.isOk()) {
+ LOG_ERROR("Error unlinking death recipient from the Bluetooth HAL");
+ }
+ bt_hci_->close();
+ callbacks_->ResetCallback();
+ bt_hci_ = nullptr;
+ }
+
+ private:
+ android::sp<InternalHciCallbacks> callbacks_;
+ android::sp<IBluetoothHci> bt_hci_;
+ SnoopLogger* btsnoop_logger_;
+};
+
+const ModuleFactory HciHal::Factory = ModuleFactory([]() {
+ return new HciHalHidl();
+});
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/hci_hal_android_hidl_test.cc b/gd/hal/hci_hal_android_hidl_test.cc
new file mode 100644
index 0000000..5b8b68d
--- /dev/null
+++ b/gd/hal/hci_hal_android_hidl_test.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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 "hal/hci_hal.h"
+
+#include <chrono>
+#include <future>
+
+#include <gtest/gtest.h>
+
+#include "os/thread.h"
+
+using ::bluetooth::os::Thread;
+
+namespace bluetooth {
+namespace hal {
+namespace {
+
+class HciHalHidlTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ thread_ = new Thread("test_thread", Thread::Priority::NORMAL);
+ }
+
+ void TearDown() override {
+ delete thread_;
+ }
+
+ ModuleRegistry fake_registry_;
+ Thread* thread_;
+};
+
+TEST_F(HciHalHidlTest, init_and_close) {
+ fake_registry_.Start<HciHal>(thread_);
+ fake_registry_.StopAll();
+}
+} // namespace
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/hci_hal_host_rootcanal.cc b/gd/hal/hci_hal_host_rootcanal.cc
new file mode 100644
index 0000000..11809ba
--- /dev/null
+++ b/gd/hal/hci_hal_host_rootcanal.cc
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2019 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 "hal/hci_hal_host_rootcanal.h"
+#include "hal/hci_hal.h"
+
+#include <netdb.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <csignal>
+#include <mutex>
+#include <queue>
+
+#include "hal/snoop_logger.h"
+#include "os/log.h"
+#include "os/reactor.h"
+#include "os/thread.h"
+
+namespace {
+constexpr int INVALID_FD = -1;
+
+constexpr uint8_t kH4Command = 0x01;
+constexpr uint8_t kH4Acl = 0x02;
+constexpr uint8_t kH4Sco = 0x03;
+constexpr uint8_t kH4Event = 0x04;
+
+constexpr uint8_t kH4HeaderSize = 1;
+constexpr uint8_t kHciAclHeaderSize = 4;
+constexpr uint8_t kHciScoHeaderSize = 3;
+constexpr uint8_t kHciEvtHeaderSize = 2;
+constexpr int kBufSize = 1024;
+
+int ConnectToRootCanal(const std::string& server, int port) {
+ int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
+ if (socket_fd < 1) {
+ LOG_ERROR("can't create socket: %s", strerror(errno));
+ return INVALID_FD;
+ }
+
+ struct hostent* host;
+ host = gethostbyname(server.c_str());
+ if (host == nullptr) {
+ LOG_ERROR("can't get server name");
+ return INVALID_FD;
+ }
+
+ struct sockaddr_in serv_addr;
+ memset((void*)&serv_addr, 0, sizeof(serv_addr));
+ serv_addr.sin_family = AF_INET;
+ serv_addr.sin_addr.s_addr = INADDR_ANY;
+ serv_addr.sin_port = htons(port);
+
+ int result = connect(socket_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
+ if (result < 0) {
+ LOG_ERROR("can't connect: %s", strerror(errno));
+ return INVALID_FD;
+ }
+
+ timeval socket_timeout{
+ .tv_sec = 3,
+ .tv_usec = 0,
+ };
+ int ret = setsockopt(socket_fd, SOL_SOCKET, SO_RCVTIMEO, &socket_timeout, sizeof(socket_timeout));
+ if (ret == -1) {
+ LOG_ERROR("can't control socket fd: %s", strerror(errno));
+ return INVALID_FD;
+ }
+ return socket_fd;
+}
+} // namespace
+
+namespace bluetooth {
+namespace hal {
+
+const std::string SnoopLogger::DefaultFilePath = "/tmp/btsnoop_hci.log";
+const bool SnoopLogger::AlwaysFlush = true;
+
+class HciHalHostRootcanal : public HciHal {
+ public:
+ void registerIncomingPacketCallback(HciHalCallbacks* callback) override {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT(incoming_packet_callback_ == nullptr && callback != nullptr);
+ incoming_packet_callback_ = callback;
+ }
+
+ void unregisterIncomingPacketCallback() override {
+ std::lock_guard<std::mutex> lock(mutex_);
+ incoming_packet_callback_ = nullptr;
+ }
+
+ void sendHciCommand(HciPacket command) override {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT(sock_fd_ != INVALID_FD);
+ std::vector<uint8_t> packet = std::move(command);
+ btsnoop_logger_->capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::CMD);
+ packet.insert(packet.cbegin(), kH4Command);
+ write_to_rootcanal_fd(packet);
+ }
+
+ void sendAclData(HciPacket data) override {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT(sock_fd_ != INVALID_FD);
+ std::vector<uint8_t> packet = std::move(data);
+ btsnoop_logger_->capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::ACL);
+ packet.insert(packet.cbegin(), kH4Acl);
+ write_to_rootcanal_fd(packet);
+ }
+
+ void sendScoData(HciPacket data) override {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT(sock_fd_ != INVALID_FD);
+ std::vector<uint8_t> packet = std::move(data);
+ btsnoop_logger_->capture(packet, SnoopLogger::Direction::OUTGOING, SnoopLogger::PacketType::SCO);
+ packet.insert(packet.cbegin(), kH4Sco);
+ write_to_rootcanal_fd(packet);
+ }
+
+ protected:
+ void ListDependencies(ModuleList* list) override {
+ list->add<SnoopLogger>();
+ }
+
+ void Start() override {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT(sock_fd_ == INVALID_FD);
+ sock_fd_ = ConnectToRootCanal(config_->GetServerAddress(), config_->GetPort());
+ ASSERT(sock_fd_ != INVALID_FD);
+ reactable_ = hci_incoming_thread_.GetReactor()->Register(
+ sock_fd_, common::Bind(&HciHalHostRootcanal::incoming_packet_received, common::Unretained(this)),
+ common::Closure());
+ btsnoop_logger_ = GetDependency<SnoopLogger>();
+ LOG_INFO("Rootcanal HAL opened successfully");
+ }
+
+ void Stop() override {
+ std::lock_guard<std::mutex> lock(mutex_);
+ if (reactable_ != nullptr) {
+ hci_incoming_thread_.GetReactor()->Unregister(reactable_);
+ ASSERT(sock_fd_ != INVALID_FD);
+ }
+ reactable_ = nullptr;
+ incoming_packet_callback_ = nullptr;
+ ::close(sock_fd_);
+ sock_fd_ = INVALID_FD;
+ LOG_INFO("Rootcanal HAL is closed");
+ }
+
+ private:
+ std::mutex mutex_;
+ HciHalHostRootcanalConfig* config_ = HciHalHostRootcanalConfig::Get();
+ HciHalCallbacks* incoming_packet_callback_ = nullptr;
+ int sock_fd_ = INVALID_FD;
+ bluetooth::os::Thread hci_incoming_thread_ =
+ bluetooth::os::Thread("hci_incoming_thread", bluetooth::os::Thread::Priority::NORMAL);
+ bluetooth::os::Reactor::Reactable* reactable_ = nullptr;
+ std::queue<std::vector<uint8_t>> hci_outgoing_queue_;
+ SnoopLogger* btsnoop_logger_;
+
+ void write_to_rootcanal_fd(HciPacket packet) {
+ // TODO: replace this with new queue when it's ready
+ hci_outgoing_queue_.emplace(packet);
+ if (hci_outgoing_queue_.size() == 1) {
+ hci_incoming_thread_.GetReactor()->ModifyRegistration(
+ reactable_, common::Bind(&HciHalHostRootcanal::incoming_packet_received, common::Unretained(this)),
+ common::Bind(&HciHalHostRootcanal::send_packet_ready, common::Unretained(this)));
+ }
+ }
+
+ void send_packet_ready() {
+ std::lock_guard<std::mutex> lock(this->mutex_);
+ auto packet_to_send = this->hci_outgoing_queue_.front();
+ auto bytes_written = write(this->sock_fd_, (void*)packet_to_send.data(), packet_to_send.size());
+ this->hci_outgoing_queue_.pop();
+ if (bytes_written == -1) {
+ abort();
+ }
+ if (hci_outgoing_queue_.empty()) {
+ this->hci_incoming_thread_.GetReactor()->ModifyRegistration(
+ this->reactable_, common::Bind(&HciHalHostRootcanal::incoming_packet_received, common::Unretained(this)),
+ common::Closure());
+ }
+ }
+
+ void incoming_packet_received() {
+ if (incoming_packet_callback_ == nullptr) {
+ LOG_INFO("Dropping a packet");
+ return;
+ }
+
+ uint8_t buf[kBufSize] = {};
+
+ ssize_t received_size;
+ RUN_NO_INTR(received_size = recv(sock_fd_, buf, kH4HeaderSize, 0));
+ ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
+ if (received_size == 0) {
+ LOG_WARN("Can't read H4 header.");
+ raise(SIGINT);
+ return;
+ }
+
+ if (buf[0] == kH4Event) {
+ RUN_NO_INTR(received_size = recv(sock_fd_, buf + kH4HeaderSize, kHciEvtHeaderSize, 0));
+ ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
+ ASSERT_LOG(received_size == kHciEvtHeaderSize, "malformed HCI event header received");
+
+ uint8_t hci_evt_parameter_total_length = buf[2];
+ ssize_t payload_size;
+ RUN_NO_INTR(payload_size =
+ recv(sock_fd_, buf + kH4HeaderSize + kHciEvtHeaderSize, hci_evt_parameter_total_length, 0));
+ ASSERT_LOG(payload_size != -1, "Can't receive from socket: %s", strerror(errno));
+ ASSERT_LOG(payload_size == hci_evt_parameter_total_length,
+ "malformed HCI event total parameter size received: %zu != %d", payload_size,
+ hci_evt_parameter_total_length);
+
+ HciPacket receivedHciPacket;
+ receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciEvtHeaderSize + payload_size);
+ btsnoop_logger_->capture(receivedHciPacket, SnoopLogger::Direction::INCOMING,
+ SnoopLogger::PacketType::EVT);
+ incoming_packet_callback_->hciEventReceived(receivedHciPacket);
+ }
+
+ if (buf[0] == kH4Acl) {
+ RUN_NO_INTR(received_size = recv(sock_fd_, buf + kH4HeaderSize, kHciAclHeaderSize, 0));
+ ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
+ ASSERT_LOG(received_size == kHciAclHeaderSize, "malformed ACL header received");
+
+ uint16_t hci_acl_data_total_length = buf[4] * 256 + buf[3];
+ int payload_size;
+ RUN_NO_INTR(payload_size = recv(sock_fd_, buf + kH4HeaderSize + kHciAclHeaderSize, hci_acl_data_total_length, 0));
+ ASSERT_LOG(payload_size != -1, "Can't receive from socket: %s", strerror(errno));
+ ASSERT_LOG(payload_size == hci_acl_data_total_length, "malformed ACL length received: %d != %d", payload_size,
+ hci_acl_data_total_length);
+ ASSERT_LOG(hci_acl_data_total_length <= kBufSize - kH4HeaderSize - kHciAclHeaderSize, "packet too long");
+
+ HciPacket receivedHciPacket;
+ receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciAclHeaderSize + payload_size);
+ btsnoop_logger_->capture(receivedHciPacket, SnoopLogger::Direction::INCOMING,
+ SnoopLogger::PacketType::ACL);
+ incoming_packet_callback_->aclDataReceived(receivedHciPacket);
+ }
+
+ if (buf[0] == kH4Sco) {
+ RUN_NO_INTR(received_size = recv(sock_fd_, buf + kH4HeaderSize, kHciScoHeaderSize, 0));
+ ASSERT_LOG(received_size != -1, "Can't receive from socket: %s", strerror(errno));
+ ASSERT_LOG(received_size == kHciScoHeaderSize, "malformed SCO header received");
+
+ uint8_t hci_sco_data_total_length = buf[3];
+ int payload_size;
+ RUN_NO_INTR(payload_size = recv(sock_fd_, buf + kH4HeaderSize + kHciScoHeaderSize, hci_sco_data_total_length, 0));
+ ASSERT_LOG(payload_size != -1, "Can't receive from socket: %s", strerror(errno));
+ ASSERT_LOG(payload_size == hci_sco_data_total_length, "malformed SCO packet received: size mismatch");
+
+ HciPacket receivedHciPacket;
+ receivedHciPacket.assign(buf + kH4HeaderSize, buf + kH4HeaderSize + kHciScoHeaderSize + payload_size);
+ btsnoop_logger_->capture(receivedHciPacket, SnoopLogger::Direction::INCOMING,
+ SnoopLogger::PacketType::SCO);
+ incoming_packet_callback_->scoDataReceived(receivedHciPacket);
+ }
+ memset(buf, 0, kBufSize);
+ }
+};
+
+const ModuleFactory HciHal::Factory = ModuleFactory([]() {
+ return new HciHalHostRootcanal();
+});
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/hci_hal_host_rootcanal.h b/gd/hal/hci_hal_host_rootcanal.h
new file mode 100644
index 0000000..9b73b15
--- /dev/null
+++ b/gd/hal/hci_hal_host_rootcanal.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <string>
+
+namespace bluetooth {
+namespace hal {
+
+// Singleton object to store runtime configuration for rootcanal
+class HciHalHostRootcanalConfig {
+ public:
+ static HciHalHostRootcanalConfig* Get() {
+ static HciHalHostRootcanalConfig instance;
+ return &instance;
+ }
+
+ // Get the listening TCP port for rootcanal HCI socket
+ uint16_t GetPort() {
+ return port_;
+ }
+
+ // Set the listening TCP port for rootcanal HCI socket
+ void SetPort(uint16_t port) {
+ port_ = port;
+ }
+
+ // Get the server address for rootcanal HCI socket
+ std::string GetServerAddress() {
+ return server_address_;
+ }
+
+ // Set the server address for rootcanal HCI socket
+ void SetServerAddress(const std::string& address) {
+ server_address_ = address;
+ }
+
+ private:
+ HciHalHostRootcanalConfig() = default;
+ uint16_t port_ = 6402; // Default server TCP port
+ std::string server_address_ = "127.0.0.1"; // Default server address
+};
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/hci_hal_host_rootcanal_test.cc b/gd/hal/hci_hal_host_rootcanal_test.cc
new file mode 100644
index 0000000..9783e84
--- /dev/null
+++ b/gd/hal/hci_hal_host_rootcanal_test.cc
@@ -0,0 +1,389 @@
+/*
+ * Copyright 2019 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 "hal/hci_hal_host_rootcanal.h"
+#include "hal/hci_hal.h"
+#include "hal/serialize_packet.h"
+
+#include <fcntl.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <cstring>
+#include <queue>
+#include <thread>
+#include <utility>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include "os/log.h"
+#include "os/thread.h"
+#include "os/utils.h"
+#include "packet/raw_builder.h"
+
+using ::bluetooth::os::Thread;
+
+namespace bluetooth {
+namespace hal {
+namespace {
+
+uint16_t kTestPort = 6537;
+
+constexpr uint8_t kH4Command = 0x01;
+constexpr uint8_t kH4Acl = 0x02;
+constexpr uint8_t kH4Sco = 0x03;
+constexpr uint8_t kH4Event = 0x04;
+
+using H4Packet = std::vector<uint8_t>;
+
+std::queue<std::pair<uint8_t, HciPacket>> incoming_packets_queue_;
+
+class TestHciHalCallbacks : public HciHalCallbacks {
+ public:
+ void hciEventReceived(HciPacket packet) override {
+ incoming_packets_queue_.emplace(kH4Event, packet);
+ }
+
+ void aclDataReceived(HciPacket packet) override {
+ incoming_packets_queue_.emplace(kH4Acl, packet);
+ }
+
+ void scoDataReceived(HciPacket packet) override {
+ incoming_packets_queue_.emplace(kH4Sco, packet);
+ }
+};
+
+// An implementation of rootcanal desktop HCI server which listens on localhost:kListeningPort
+class FakeRootcanalDesktopHciServer {
+ public:
+ FakeRootcanalDesktopHciServer() {
+ struct sockaddr_in listen_address;
+ socklen_t sockaddr_in_size = sizeof(struct sockaddr_in);
+ memset(&listen_address, 0, sockaddr_in_size);
+
+ RUN_NO_INTR(listen_fd_ = socket(AF_INET, SOCK_STREAM, 0));
+ if (listen_fd_ < 0) {
+ LOG_WARN("Error creating socket for test channel.");
+ return;
+ }
+
+ listen_address.sin_family = AF_INET;
+ listen_address.sin_port = htons(HciHalHostRootcanalConfig::Get()->GetPort());
+ listen_address.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ if (bind(listen_fd_, reinterpret_cast<sockaddr*>(&listen_address), sockaddr_in_size) < 0) {
+ LOG_WARN("Error binding test channel listener socket to address.");
+ close(listen_fd_);
+ return;
+ }
+
+ if (listen(listen_fd_, 1) < 0) {
+ LOG_WARN("Error listening for test channel.");
+ close(listen_fd_);
+ return;
+ }
+ }
+
+ ~FakeRootcanalDesktopHciServer() {
+ close(listen_fd_);
+ }
+
+ int Accept() {
+ int accept_fd;
+
+ RUN_NO_INTR(accept_fd = accept(listen_fd_, nullptr, nullptr));
+
+ int flags = fcntl(accept_fd, F_GETFL, NULL);
+ int ret = fcntl(accept_fd, F_SETFL, flags | O_NONBLOCK);
+ if (ret == -1) {
+ LOG_ERROR("Can't fcntl");
+ return -1;
+ }
+
+ if (accept_fd < 0) {
+ LOG_WARN("Error accepting test channel connection errno=%d (%s).", errno, strerror(errno));
+
+ if (errno != EAGAIN && errno != EWOULDBLOCK) {
+ LOG_ERROR("Closing listen_fd_ (won't try again).");
+ close(listen_fd_);
+ return -1;
+ }
+ }
+
+ return accept_fd;
+ }
+
+ private:
+ int listen_fd_ = -1;
+};
+
+class HciHalRootcanalTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ thread_ = new Thread("test_thread", Thread::Priority::NORMAL);
+
+ HciHalHostRootcanalConfig::Get()->SetPort(kTestPort);
+ fake_server_ = new FakeRootcanalDesktopHciServer;
+ hal_ = fake_registry_.Start<HciHal>(thread_);
+ hal_->registerIncomingPacketCallback(&callbacks_);
+ fake_server_socket_ = fake_server_->Accept(); // accept() after client is connected to avoid blocking
+ std::queue<std::pair<uint8_t, HciPacket>> empty;
+ std::swap(incoming_packets_queue_, empty);
+ }
+
+ void TearDown() override {
+ hal_->unregisterIncomingPacketCallback();
+ fake_registry_.StopAll();
+ close(fake_server_socket_);
+ delete fake_server_;
+ delete thread_;
+ }
+
+ void SetFakeServerSocketToBlocking() {
+ int flags = fcntl(fake_server_socket_, F_GETFL, NULL);
+ int ret = fcntl(fake_server_socket_, F_SETFL, flags & ~O_NONBLOCK);
+ EXPECT_NE(ret, -1) << "Can't set accept fd to blocking";
+ }
+
+ FakeRootcanalDesktopHciServer* fake_server_ = nullptr;
+ HciHal* hal_ = nullptr;
+ ModuleRegistry fake_registry_;
+ TestHciHalCallbacks callbacks_;
+ int fake_server_socket_ = -1;
+ Thread* thread_;
+};
+
+void check_packet_equal(std::pair<uint8_t, HciPacket> hci_packet1_type_data_pair, H4Packet h4_packet2) {
+ auto packet1_hci_size = hci_packet1_type_data_pair.second.size();
+ EXPECT_EQ(packet1_hci_size + 1, h4_packet2.size());
+ EXPECT_EQ(hci_packet1_type_data_pair.first, h4_packet2[0]);
+ EXPECT_EQ(memcmp(hci_packet1_type_data_pair.second.data(), h4_packet2.data() + 1, packet1_hci_size), 0);
+}
+
+HciPacket make_sample_hci_cmd_pkt(uint8_t parameter_total_length) {
+ HciPacket pkt;
+ pkt.assign(2 + 1 + parameter_total_length, 0x01);
+ pkt[2] = parameter_total_length;
+ return pkt;
+}
+
+HciPacket make_sample_hci_acl_pkt(uint8_t payload_size) {
+ HciPacket pkt;
+ pkt.assign(2 + 2 + payload_size, 0x01);
+ pkt[2] = payload_size;
+ return pkt;
+}
+
+HciPacket make_sample_hci_sco_pkt(uint8_t payload_size) {
+ HciPacket pkt;
+ pkt.assign(3 + payload_size, 0x01);
+ pkt[2] = payload_size;
+ return pkt;
+}
+
+H4Packet make_sample_h4_evt_pkt(uint8_t parameter_total_length) {
+ H4Packet pkt;
+ pkt.assign(1 + 1 + 1 + parameter_total_length, 0x01);
+ pkt[0] = kH4Event;
+ pkt[2] = parameter_total_length;
+ return pkt;
+}
+
+HciPacket make_sample_h4_acl_pkt(uint8_t payload_size) {
+ HciPacket pkt;
+ pkt.assign(1 + 2 + 2 + payload_size, 0x01);
+ pkt[0] = kH4Acl;
+ pkt[3] = payload_size;
+ pkt[4] = 0;
+ return pkt;
+}
+
+HciPacket make_sample_h4_sco_pkt(uint8_t payload_size) {
+ HciPacket pkt;
+ pkt.assign(1 + 3 + payload_size, 0x01);
+ pkt[0] = kH4Sco;
+ pkt[3] = payload_size;
+ return pkt;
+}
+
+TEST_F(HciHalRootcanalTest, init_and_close) {}
+
+TEST_F(HciHalRootcanalTest, receive_hci_evt) {
+ H4Packet incoming_packet = make_sample_h4_evt_pkt(3);
+ write(fake_server_socket_, incoming_packet.data(), incoming_packet.size());
+ while (incoming_packets_queue_.size() != 1) {
+ }
+ auto packet = incoming_packets_queue_.front();
+ incoming_packets_queue_.pop();
+ check_packet_equal(packet, incoming_packet);
+}
+
+TEST_F(HciHalRootcanalTest, receive_hci_acl) {
+ H4Packet incoming_packet = make_sample_h4_acl_pkt(3);
+ write(fake_server_socket_, incoming_packet.data(), incoming_packet.size());
+ while (incoming_packets_queue_.size() != 1) {
+ }
+ auto packet = incoming_packets_queue_.front();
+ incoming_packets_queue_.pop();
+ check_packet_equal(packet, incoming_packet);
+}
+
+TEST_F(HciHalRootcanalTest, receive_hci_sco) {
+ H4Packet incoming_packet = make_sample_h4_sco_pkt(3);
+ write(fake_server_socket_, incoming_packet.data(), incoming_packet.size());
+ while (incoming_packets_queue_.size() != 1) {
+ }
+ auto packet = incoming_packets_queue_.front();
+ incoming_packets_queue_.pop();
+ check_packet_equal(packet, incoming_packet);
+}
+
+TEST_F(HciHalRootcanalTest, receive_two_hci_evts) {
+ H4Packet incoming_packet = make_sample_h4_evt_pkt(3);
+ H4Packet incoming_packet2 = make_sample_h4_evt_pkt(5);
+ write(fake_server_socket_, incoming_packet.data(), incoming_packet.size());
+ write(fake_server_socket_, incoming_packet2.data(), incoming_packet2.size());
+ while (incoming_packets_queue_.size() != 2) {
+ }
+ auto packet = incoming_packets_queue_.front();
+ incoming_packets_queue_.pop();
+ check_packet_equal(packet, incoming_packet);
+ packet = incoming_packets_queue_.front();
+ incoming_packets_queue_.pop();
+ check_packet_equal(packet, incoming_packet2);
+}
+
+TEST_F(HciHalRootcanalTest, receive_evt_and_acl) {
+ H4Packet incoming_packet = make_sample_h4_evt_pkt(3);
+ H4Packet incoming_packet2 = make_sample_h4_acl_pkt(5);
+ write(fake_server_socket_, incoming_packet.data(), incoming_packet.size());
+ write(fake_server_socket_, incoming_packet2.data(), incoming_packet2.size());
+ while (incoming_packets_queue_.size() != 2) {
+ }
+ auto packet = incoming_packets_queue_.front();
+ incoming_packets_queue_.pop();
+ check_packet_equal(packet, incoming_packet);
+ packet = incoming_packets_queue_.front();
+ incoming_packets_queue_.pop();
+ check_packet_equal(packet, incoming_packet2);
+}
+
+TEST_F(HciHalRootcanalTest, receive_multiple_acl_batch) {
+ H4Packet incoming_packet = make_sample_h4_acl_pkt(5);
+ int num_packets = 1000;
+ for (int i = 0; i < num_packets; i++) {
+ write(fake_server_socket_, incoming_packet.data(), incoming_packet.size());
+ }
+ while (incoming_packets_queue_.size() != num_packets) {
+ }
+ for (int i = 0; i < num_packets; i++) {
+ auto packet = incoming_packets_queue_.front();
+ incoming_packets_queue_.pop();
+ check_packet_equal(packet, incoming_packet);
+ }
+}
+
+TEST_F(HciHalRootcanalTest, receive_multiple_acl_sequential) {
+ H4Packet incoming_packet = make_sample_h4_acl_pkt(5);
+ int num_packets = 1000;
+ for (int i = 0; i < num_packets; i++) {
+ write(fake_server_socket_, incoming_packet.data(), incoming_packet.size());
+ while (incoming_packets_queue_.empty()) {
+ }
+ auto packet = incoming_packets_queue_.front();
+ incoming_packets_queue_.pop();
+ check_packet_equal(packet, incoming_packet);
+ }
+}
+
+TEST_F(HciHalRootcanalTest, send_hci_cmd) {
+ uint8_t hci_cmd_param_size = 2;
+ HciPacket hci_data = make_sample_hci_cmd_pkt(hci_cmd_param_size);
+ hal_->sendHciCommand(hci_data);
+ H4Packet read_buf(1 + 2 + 1 + hci_cmd_param_size);
+ SetFakeServerSocketToBlocking();
+ auto size_read = read(fake_server_socket_, read_buf.data(), read_buf.size());
+
+ EXPECT_EQ(size_read, 1 + hci_data.size());
+ check_packet_equal({kH4Command, hci_data}, read_buf);
+}
+
+TEST_F(HciHalRootcanalTest, send_acl) {
+ uint8_t acl_payload_size = 200;
+ HciPacket acl_packet = make_sample_hci_acl_pkt(acl_payload_size);
+ hal_->sendAclData(acl_packet);
+ H4Packet read_buf(1 + 2 + 2 + acl_payload_size);
+ SetFakeServerSocketToBlocking();
+ auto size_read = read(fake_server_socket_, read_buf.data(), read_buf.size());
+
+ EXPECT_EQ(size_read, 1 + acl_packet.size());
+ check_packet_equal({kH4Acl, acl_packet}, read_buf);
+}
+
+TEST_F(HciHalRootcanalTest, send_sco) {
+ uint8_t sco_payload_size = 200;
+ HciPacket sco_packet = make_sample_hci_sco_pkt(sco_payload_size);
+ hal_->sendScoData(sco_packet);
+ H4Packet read_buf(1 + 3 + sco_payload_size);
+ SetFakeServerSocketToBlocking();
+ auto size_read = read(fake_server_socket_, read_buf.data(), read_buf.size());
+
+ EXPECT_EQ(size_read, 1 + sco_packet.size());
+ check_packet_equal({kH4Sco, sco_packet}, read_buf);
+}
+
+TEST_F(HciHalRootcanalTest, send_multiple_acl_batch) {
+ uint8_t acl_payload_size = 200;
+ int num_packets = 1000;
+ HciPacket acl_packet = make_sample_hci_acl_pkt(acl_payload_size);
+ for (int i = 0; i < num_packets; i++) {
+ hal_->sendAclData(acl_packet);
+ }
+ H4Packet read_buf(1 + 2 + 2 + acl_payload_size);
+ SetFakeServerSocketToBlocking();
+ for (int i = 0; i < num_packets; i++) {
+ auto size_read = read(fake_server_socket_, read_buf.data(), read_buf.size());
+ EXPECT_EQ(size_read, 1 + acl_packet.size());
+ check_packet_equal({kH4Acl, acl_packet}, read_buf);
+ }
+}
+
+TEST_F(HciHalRootcanalTest, send_multiple_acl_sequential) {
+ uint8_t acl_payload_size = 200;
+ int num_packets = 1000;
+ HciPacket acl_packet = make_sample_hci_acl_pkt(acl_payload_size);
+ SetFakeServerSocketToBlocking();
+ for (int i = 0; i < num_packets; i++) {
+ hal_->sendAclData(acl_packet);
+ H4Packet read_buf(1 + 2 + 2 + acl_payload_size);
+ auto size_read = read(fake_server_socket_, read_buf.data(), read_buf.size());
+ EXPECT_EQ(size_read, 1 + acl_packet.size());
+ check_packet_equal({kH4Acl, acl_packet}, read_buf);
+ }
+}
+
+TEST(HciHalHidlTest, serialize) {
+ std::vector<uint8_t> bytes = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+ auto packet_bytes = hal::SerializePacket(std::unique_ptr<packet::BasePacketBuilder>(new packet::RawBuilder(bytes)));
+ EXPECT_EQ(bytes, packet_bytes);
+}
+} // namespace
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/serialize_packet.h b/gd/hal/serialize_packet.h
new file mode 100644
index 0000000..621dcec
--- /dev/null
+++ b/gd/hal/serialize_packet.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include "packet/base_packet_builder.h"
+
+namespace bluetooth {
+namespace hal {
+
+inline std::vector<uint8_t> SerializePacket(std::unique_ptr<packet::BasePacketBuilder> packet) {
+ std::vector<uint8_t> packet_bytes;
+ packet_bytes.reserve(packet->size());
+ packet::BitInserter it(packet_bytes);
+ packet->Serialize(it);
+ return packet_bytes;
+}
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/snoop_logger.cc b/gd/hal/snoop_logger.cc
new file mode 100644
index 0000000..3574b17
--- /dev/null
+++ b/gd/hal/snoop_logger.cc
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2019 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 "hal/snoop_logger.h"
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <bitset>
+#include <chrono>
+
+#include "os/log.h"
+
+namespace bluetooth {
+namespace hal {
+
+namespace {
+typedef struct {
+ uint32_t length_original;
+ uint32_t length_captured;
+ uint32_t flags;
+ uint32_t dropped_packets;
+ uint64_t timestamp;
+ uint8_t type;
+} __attribute__((__packed__)) btsnoop_packet_header_t;
+
+typedef struct {
+ uint8_t identification_pattern[8];
+ uint32_t version_number;
+ uint32_t datalink_type;
+} __attribute__((__packed__)) btsnoop_file_header_t;
+
+constexpr uint64_t BTSNOOP_EPOCH_DELTA = 0x00dcddb30f2f8000ULL;
+
+constexpr uint32_t kBytesToTest = 0x12345678;
+constexpr uint8_t kFirstByte = (const uint8_t&)kBytesToTest;
+constexpr bool isLittleEndian = kFirstByte == 0x78;
+constexpr bool isBigEndian = kFirstByte == 0x12;
+static_assert(isLittleEndian || isBigEndian && isLittleEndian != isBigEndian);
+
+constexpr uint32_t BTSNOOP_VERSION_NUMBER = isLittleEndian ? 0x01000000 : 1;
+constexpr uint32_t BTSNOOP_DATALINK_TYPE =
+ isLittleEndian ? 0xea030000 : 0x03ea; // Datalink Type code for HCI UART (H4) is 1002
+uint64_t htonll(uint64_t ll) {
+ if constexpr (isLittleEndian) {
+ return static_cast<uint64_t>(htonl(ll & 0xffffffff)) << 32 | htonl(ll >> 32);
+ } else {
+ return ll;
+ }
+}
+
+constexpr btsnoop_file_header_t BTSNOOP_FILE_HEADER = {
+ .identification_pattern = {'b', 't', 's', 'n', 'o', 'o', 'p', 0x00},
+ .version_number = BTSNOOP_VERSION_NUMBER,
+ .datalink_type = BTSNOOP_DATALINK_TYPE};
+} // namespace
+
+SnoopLogger::SnoopLogger() {
+ bool file_exists;
+ {
+ std::ifstream btsnoop_istream(file_path);
+ file_exists = btsnoop_istream.is_open();
+ }
+ btsnoop_ostream_.open(file_path, std::ios::binary | std::ios::app | std::ios::out);
+ if (!file_exists) {
+ LOG_INFO("Creating new BTSNOOP");
+ btsnoop_ostream_.write(reinterpret_cast<const char*>(&BTSNOOP_FILE_HEADER), sizeof(btsnoop_file_header_t));
+ } else {
+ LOG_INFO("Appending to old BTSNOOP");
+ }
+}
+
+void SnoopLogger::SetFilePath(const std::string& filename) {
+ file_path = filename;
+}
+
+void SnoopLogger::capture(const HciPacket& packet, Direction direction, PacketType type) {
+ uint64_t timestamp_us =
+ std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now().time_since_epoch())
+ .count();
+ std::lock_guard<std::mutex> lock(file_mutex_);
+ std::bitset<32> flags = 0;
+ switch (type) {
+ case PacketType::CMD:
+ flags.set(0, false);
+ flags.set(1, true);
+ break;
+ case PacketType::ACL:
+ flags.set(0, direction == Direction::INCOMING);
+ flags.set(1, false);
+ break;
+ case PacketType::SCO:
+ flags.set(0, direction == Direction::INCOMING);
+ flags.set(1, false);
+ break;
+ case PacketType::EVT:
+ flags.set(0, true);
+ flags.set(1, true);
+ break;
+ }
+ uint32_t length = packet.size() + /* type byte */ 1;
+ btsnoop_packet_header_t header = {.length_original = htonl(length),
+ .length_captured = htonl(length),
+ .flags = htonl(static_cast<uint32_t>(flags.to_ulong())),
+ .dropped_packets = 0,
+ .timestamp = htonll(timestamp_us + BTSNOOP_EPOCH_DELTA),
+ .type = static_cast<uint8_t>(type)};
+ btsnoop_ostream_.write(reinterpret_cast<const char*>(&header), sizeof(btsnoop_packet_header_t));
+ btsnoop_ostream_.write(reinterpret_cast<const char*>(packet.data()), packet.size());
+ if (AlwaysFlush) btsnoop_ostream_.flush();
+}
+
+void SnoopLogger::ListDependencies(ModuleList* list) {
+ // We have no dependencies
+}
+
+void SnoopLogger::Start() {}
+
+void SnoopLogger::Stop() {}
+
+std::string SnoopLogger::file_path = SnoopLogger::DefaultFilePath;
+
+const ModuleFactory SnoopLogger::Factory = ModuleFactory([]() {
+ return new SnoopLogger();
+});
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hal/snoop_logger.h b/gd/hal/snoop_logger.h
new file mode 100644
index 0000000..8021c2b
--- /dev/null
+++ b/gd/hal/snoop_logger.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <fstream>
+#include <iostream>
+#include <mutex>
+#include <string>
+
+#include "hal/hci_hal.h"
+#include "module.h"
+
+namespace bluetooth {
+namespace hal {
+
+class SnoopLogger : public ::bluetooth::Module {
+ public:
+ static const ModuleFactory Factory;
+
+ // Each transport using SnoopLogger should define its own DefaultFilepath
+ static const std::string DefaultFilePath;
+ // Set File Path before module is started to ensure all packets are written to the right file
+ static void SetFilePath(const std::string& filename);
+ // Flag to allow flush into persistent memory on every packet captured. This is enabled on host for debugging.
+ static const bool AlwaysFlush;
+
+ enum class PacketType {
+ CMD = 1,
+ ACL = 2,
+ SCO = 3,
+ EVT = 4,
+ };
+
+ enum class Direction {
+ INCOMING,
+ OUTGOING,
+ };
+
+ void capture(const HciPacket& packet, Direction direction, PacketType type);
+
+ protected:
+ void ListDependencies(ModuleList* list) override;
+ void Start() override;
+ void Stop() override;
+
+ private:
+ SnoopLogger();
+ static std::string file_path;
+ std::ofstream btsnoop_ostream_;
+ std::mutex file_mutex_;
+};
+
+} // namespace hal
+} // namespace bluetooth
diff --git a/gd/hci/Android.bp b/gd/hci/Android.bp
new file mode 100644
index 0000000..8784a49
--- /dev/null
+++ b/gd/hci/Android.bp
@@ -0,0 +1,57 @@
+filegroup {
+ name: "BluetoothHciSources",
+ srcs: [
+ "acl_manager.cc",
+ "acl_fragmenter.cc",
+ "address.cc",
+ "classic_security_manager.cc",
+ "class_of_device.cc",
+ "controller.cc",
+ "device.cc",
+ "device_database.cc",
+ "hci_layer.cc",
+ "le_advertising_manager.cc",
+ "le_scanning_manager.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothHciTestSources",
+ srcs: [
+ "acl_builder_test.cc",
+ "acl_manager_test.cc",
+ "address_unittest.cc",
+ "address_with_type_test.cc",
+ "class_of_device_unittest.cc",
+ "classic_security_manager_test.cc",
+ "controller_test.cc",
+ "device_test.cc",
+ "device_database_test.cc",
+ "dual_device_test.cc",
+ "hci_layer_test.cc",
+ "hci_packets_test.cc",
+ "le_advertising_manager_test.cc",
+ "le_scanning_manager_test.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothFacade_hci_layer",
+ srcs: [
+ "facade.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothCertSource_hci_layer",
+ srcs: [
+ "cert/cert.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothHciFuzzTestSources",
+ srcs: [
+ "hci_packets_fuzz_test.cc",
+ ],
+}
diff --git a/gd/hci/acl_builder_test.cc b/gd/hci/acl_builder_test.cc
new file mode 100644
index 0000000..7fc59c6
--- /dev/null
+++ b/gd/hci/acl_builder_test.cc
@@ -0,0 +1,167 @@
+/*
+ * Copyright 2018 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 "hci/hci_packets.h"
+
+#include <gtest/gtest.h>
+#include <memory>
+
+#include "os/log.h"
+#include "packet/bit_inserter.h"
+#include "packet/raw_builder.h"
+
+using bluetooth::packet::BitInserter;
+using bluetooth::packet::RawBuilder;
+using std::vector;
+
+namespace {
+vector<uint8_t> information_request = {
+ 0xfe, 0x2e, 0x0a, 0x00, 0x06, 0x00, 0x01, 0x00, 0x0a, 0x02, 0x02, 0x00, 0x02, 0x00,
+};
+// 0x00, 0x01, 0x02, 0x03, ...
+vector<uint8_t> counting_bytes;
+// 0xFF, 0xFE, 0xFD, 0xFC, ...
+vector<uint8_t> counting_down_bytes;
+const size_t count_size = 0x8;
+
+} // namespace
+
+namespace bluetooth {
+namespace hci {
+
+class AclBuilderTest : public ::testing::Test {
+ public:
+ AclBuilderTest() {
+ counting_bytes.reserve(count_size);
+ counting_down_bytes.reserve(count_size);
+ for (size_t i = 0; i < count_size; i++) {
+ counting_bytes.push_back(i);
+ counting_down_bytes.push_back(~i);
+ }
+ }
+ ~AclBuilderTest() = default;
+};
+
+TEST(AclBuilderTest, buildAclCount) {
+ uint16_t handle = 0x0314;
+ PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
+ BroadcastFlag broadcast_flag = BroadcastFlag::ACTIVE_SLAVE_BROADCAST;
+
+ std::unique_ptr<RawBuilder> count_payload = std::make_unique<RawBuilder>();
+ count_payload->AddOctets(counting_bytes);
+ ASSERT_EQ(counting_bytes.size(), count_payload->size());
+
+ std::unique_ptr<AclPacketBuilder> count_packet =
+ AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(count_payload));
+
+ ASSERT_EQ(counting_bytes.size() + 4, count_packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> count_packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*count_packet_bytes);
+ count_packet->Serialize(it);
+
+ PacketView<true> count_packet_bytes_view(count_packet_bytes);
+ AclPacketView count_packet_view = AclPacketView::Create(count_packet_bytes_view);
+ ASSERT_TRUE(count_packet_view.IsValid());
+
+ ASSERT_EQ(handle, count_packet_view.GetHandle());
+ ASSERT_EQ(packet_boundary_flag, count_packet_view.GetPacketBoundaryFlag());
+ ASSERT_EQ(broadcast_flag, count_packet_view.GetBroadcastFlag());
+ PacketView<true> count_view = count_packet_view.GetPayload();
+
+ ASSERT_EQ(count_view.size(), counting_bytes.size());
+ for (size_t i = 0; i < count_view.size(); i++) {
+ ASSERT_EQ(count_view[i], counting_bytes[i]);
+ }
+}
+
+TEST(AclBuilderTest, buildAclCountInverted) {
+ uint16_t handle = 0x0304;
+ PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::CONTINUING_FRAGMENT;
+ BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
+
+ std::unique_ptr<RawBuilder> counting_down_bytes_payload = std::make_unique<RawBuilder>();
+ counting_down_bytes_payload->AddOctets(counting_down_bytes);
+ ASSERT_EQ(counting_down_bytes.size(), counting_down_bytes_payload->size());
+
+ std::unique_ptr<AclPacketBuilder> counting_down_bytes_packet =
+ AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(counting_down_bytes_payload));
+
+ ASSERT_EQ(counting_down_bytes.size() + 4, counting_down_bytes_packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> counting_down_bytes_packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*counting_down_bytes_packet_bytes);
+ counting_down_bytes_packet->Serialize(it);
+ PacketView<true> counting_down_bytes_packet_bytes_view(counting_down_bytes_packet_bytes);
+ AclPacketView counting_down_bytes_packet_view = AclPacketView::Create(counting_down_bytes_packet_bytes_view);
+ ASSERT_TRUE(counting_down_bytes_packet_view.IsValid());
+
+ ASSERT_EQ(handle, counting_down_bytes_packet_view.GetHandle());
+ ASSERT_EQ(packet_boundary_flag, counting_down_bytes_packet_view.GetPacketBoundaryFlag());
+ ASSERT_EQ(broadcast_flag, counting_down_bytes_packet_view.GetBroadcastFlag());
+ PacketView<true> counting_down_bytes_view = counting_down_bytes_packet_view.GetPayload();
+
+ ASSERT_EQ(counting_down_bytes_view.size(), counting_down_bytes.size());
+ for (size_t i = 0; i < counting_down_bytes_view.size(); i++) {
+ ASSERT_EQ(counting_down_bytes_view[i], counting_down_bytes[i]);
+ }
+}
+
+TEST(AclBuilderTest, buildInformationRequest) {
+ uint16_t handle = 0x0efe;
+ PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
+ BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
+
+ std::vector<uint8_t> payload_bytes(information_request.begin() + 4, information_request.end());
+ std::unique_ptr<RawBuilder> payload = std::make_unique<RawBuilder>();
+ payload->AddOctets(payload_bytes);
+ ASSERT_EQ(payload_bytes.size(), payload->size());
+
+ std::unique_ptr<AclPacketBuilder> packet =
+ AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(payload));
+
+ ASSERT_EQ(information_request.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+ PacketView<true> packet_bytes_view(packet_bytes);
+ AclPacketView packet_view = AclPacketView::Create(packet_bytes_view);
+ ASSERT_TRUE(packet_view.IsValid());
+
+ ASSERT_EQ(packet_bytes->size(), information_request.size());
+ for (size_t i = 0; i < packet_bytes->size(); i++) {
+ ASSERT_EQ((*packet_bytes)[i], information_request[i]);
+ }
+
+ ASSERT_EQ(handle, packet_view.GetHandle());
+ ASSERT_EQ(packet_boundary_flag, packet_view.GetPacketBoundaryFlag());
+ ASSERT_EQ(broadcast_flag, packet_view.GetBroadcastFlag());
+ PacketView<true> payload_view = packet_view.GetPayload();
+
+ ASSERT_EQ(payload_view.size(), payload_bytes.size());
+ for (size_t i = 0; i < payload_view.size(); i++) {
+ ASSERT_EQ(payload_view[i], payload_bytes[i]);
+ }
+
+ ASSERT_EQ(packet_view.size(), information_request.size());
+ for (size_t i = 0; i < packet_view.size(); i++) {
+ ASSERT_EQ(packet_view[i], information_request[i]);
+ }
+}
+
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/acl_fragmenter.cc b/gd/hci/acl_fragmenter.cc
new file mode 100644
index 0000000..fa3b31d
--- /dev/null
+++ b/gd/hci/acl_fragmenter.cc
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 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 "hci/acl_fragmenter.h"
+
+#include "os/log.h"
+#include "packet/fragmenting_inserter.h"
+
+namespace bluetooth {
+namespace hci {
+
+AclFragmenter::AclFragmenter(size_t mtu, std::unique_ptr<packet::BasePacketBuilder> packet)
+ : mtu_(mtu), packet_(std::move(packet)) {}
+
+std::vector<std::unique_ptr<packet::RawBuilder>> AclFragmenter::GetFragments() {
+ std::vector<std::unique_ptr<packet::RawBuilder>> to_return;
+ packet::FragmentingInserter fragmenting_inserter(mtu_, std::back_insert_iterator(to_return));
+ packet_->Serialize(fragmenting_inserter);
+ fragmenting_inserter.finalize();
+ return to_return;
+}
+
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/acl_fragmenter.h b/gd/hci/acl_fragmenter.h
new file mode 100644
index 0000000..4bc3d06
--- /dev/null
+++ b/gd/hci/acl_fragmenter.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <forward_list>
+#include <iterator>
+#include <memory>
+#include <vector>
+
+#include "packet/base_packet_builder.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace hci {
+
+class AclFragmenter {
+ public:
+ AclFragmenter(size_t mtu, std::unique_ptr<packet::BasePacketBuilder> input);
+ virtual ~AclFragmenter() = default;
+
+ std::vector<std::unique_ptr<packet::RawBuilder>> GetFragments();
+
+ private:
+ size_t mtu_;
+ std::unique_ptr<packet::BasePacketBuilder> packet_;
+};
+
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/acl_manager.cc b/gd/hci/acl_manager.cc
new file mode 100644
index 0000000..2852b6c
--- /dev/null
+++ b/gd/hci/acl_manager.cc
@@ -0,0 +1,1811 @@
+/*
+ * Copyright 2019 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 "hci/acl_manager.h"
+
+#include <future>
+#include <queue>
+#include <set>
+#include <utility>
+
+#include "acl_fragmenter.h"
+#include "acl_manager.h"
+#include "common/bidi_queue.h"
+#include "hci/controller.h"
+#include "hci/hci_layer.h"
+
+namespace bluetooth {
+namespace hci {
+
+constexpr uint16_t kQualcommDebugHandle = 0xedc;
+
+using common::Bind;
+using common::BindOnce;
+
+struct AclManager::acl_connection {
+ acl_connection(AddressWithType address_with_type) : address_with_type_(address_with_type) {}
+ friend AclConnection;
+ AddressWithType address_with_type_;
+ std::unique_ptr<AclConnection::Queue> queue_ = std::make_unique<AclConnection::Queue>(10);
+ bool is_disconnected_ = false;
+ ErrorCode disconnect_reason_;
+ os::Handler* command_complete_handler_ = nullptr;
+ os::Handler* disconnect_handler_ = nullptr;
+ ConnectionManagementCallbacks* command_complete_callbacks_;
+ common::OnceCallback<void(ErrorCode)> on_disconnect_callback_;
+ // Round-robin: Track if dequeue is registered for this connection
+ bool is_registered_ = false;
+ // Credits: Track the number of packets which have been sent to the controller
+ uint16_t number_of_sent_packets_ = 0;
+ void call_disconnect_callback() {
+ disconnect_handler_->Post(BindOnce(std::move(on_disconnect_callback_), disconnect_reason_));
+ }
+};
+
+struct AclManager::impl {
+ impl(const AclManager& acl_manager) : acl_manager_(acl_manager) {}
+
+ void Start() {
+ hci_layer_ = acl_manager_.GetDependency<HciLayer>();
+ handler_ = acl_manager_.GetHandler();
+ controller_ = acl_manager_.GetDependency<Controller>();
+ max_acl_packet_credits_ = controller_->GetControllerNumAclPacketBuffers();
+ acl_packet_credits_ = max_acl_packet_credits_;
+ acl_buffer_length_ = controller_->GetControllerAclPacketLength();
+ controller_->RegisterCompletedAclPacketsCallback(
+ common::Bind(&impl::incoming_acl_credits, common::Unretained(this)), handler_);
+
+ // TODO: determine when we should reject connection
+ should_accept_connection_ = common::Bind([](Address, ClassOfDevice) { return true; });
+ hci_queue_end_ = hci_layer_->GetAclQueueEnd();
+ hci_queue_end_->RegisterDequeue(
+ handler_, common::Bind(&impl::dequeue_and_route_acl_packet_to_connection, common::Unretained(this)));
+ hci_layer_->RegisterEventHandler(EventCode::CONNECTION_COMPLETE,
+ Bind(&impl::on_connection_complete, common::Unretained(this)), handler_);
+ hci_layer_->RegisterEventHandler(EventCode::DISCONNECTION_COMPLETE,
+ Bind(&impl::on_disconnection_complete, common::Unretained(this)), handler_);
+ hci_layer_->RegisterEventHandler(EventCode::CONNECTION_REQUEST,
+ Bind(&impl::on_incoming_connection, common::Unretained(this)), handler_);
+ hci_layer_->RegisterLeEventHandler(SubeventCode::CONNECTION_COMPLETE,
+ Bind(&impl::on_le_connection_complete, common::Unretained(this)), handler_);
+ hci_layer_->RegisterLeEventHandler(SubeventCode::ENHANCED_CONNECTION_COMPLETE,
+ Bind(&impl::on_le_enhanced_connection_complete, common::Unretained(this)),
+ handler_);
+ hci_layer_->RegisterEventHandler(EventCode::CONNECTION_PACKET_TYPE_CHANGED,
+ Bind(&impl::on_connection_packet_type_changed, common::Unretained(this)),
+ handler_);
+ hci_layer_->RegisterEventHandler(EventCode::AUTHENTICATION_COMPLETE,
+ Bind(&impl::on_authentication_complete, common::Unretained(this)), handler_);
+ hci_layer_->RegisterEventHandler(EventCode::READ_CLOCK_OFFSET_COMPLETE,
+ Bind(&impl::on_read_clock_offset_complete, common::Unretained(this)), handler_);
+ hci_layer_->RegisterEventHandler(EventCode::MODE_CHANGE, Bind(&impl::on_mode_change, common::Unretained(this)),
+ handler_);
+ hci_layer_->RegisterEventHandler(EventCode::QOS_SETUP_COMPLETE,
+ Bind(&impl::on_qos_setup_complete, common::Unretained(this)), handler_);
+ hci_layer_->RegisterEventHandler(EventCode::ROLE_CHANGE, Bind(&impl::on_role_change, common::Unretained(this)),
+ handler_);
+ hci_layer_->RegisterEventHandler(EventCode::FLOW_SPECIFICATION_COMPLETE,
+ Bind(&impl::on_flow_specification_complete, common::Unretained(this)), handler_);
+ hci_layer_->RegisterEventHandler(EventCode::FLUSH_OCCURRED,
+ Bind(&impl::on_flush_occurred, common::Unretained(this)), handler_);
+ hci_mtu_ = controller_->GetControllerAclPacketLength();
+ }
+
+ void Stop() {
+ hci_layer_->UnregisterEventHandler(EventCode::DISCONNECTION_COMPLETE);
+ hci_layer_->UnregisterEventHandler(EventCode::CONNECTION_COMPLETE);
+ hci_layer_->UnregisterEventHandler(EventCode::CONNECTION_REQUEST);
+ hci_layer_->UnregisterEventHandler(EventCode::AUTHENTICATION_COMPLETE);
+ hci_queue_end_->UnregisterDequeue();
+ unregister_all_connections();
+ acl_connections_.clear();
+ hci_queue_end_ = nullptr;
+ handler_ = nullptr;
+ hci_layer_ = nullptr;
+ }
+
+ void incoming_acl_credits(uint16_t handle, uint16_t credits) {
+ auto connection_pair = acl_connections_.find(handle);
+ if (connection_pair == acl_connections_.end()) {
+ LOG_INFO("Dropping %hx received credits to unknown connection 0x%0hx", credits, handle);
+ return;
+ }
+ if (connection_pair->second.is_disconnected_) {
+ LOG_INFO("Dropping %hx received credits to disconnected connection 0x%0hx", credits, handle);
+ return;
+ }
+ connection_pair->second.number_of_sent_packets_ -= credits;
+ acl_packet_credits_ += credits;
+ ASSERT(acl_packet_credits_ <= max_acl_packet_credits_);
+ start_round_robin();
+ }
+
+ // Round-robin scheduler
+ void start_round_robin() {
+ if (acl_packet_credits_ == 0) {
+ return;
+ }
+ if (!fragments_to_send_.empty()) {
+ send_next_fragment();
+ return;
+ }
+ for (auto connection_pair = acl_connections_.begin(); connection_pair != acl_connections_.end();
+ connection_pair = std::next(connection_pair)) {
+ if (connection_pair->second.is_registered_) {
+ continue;
+ }
+ connection_pair->second.is_registered_ = true;
+ connection_pair->second.queue_->GetDownEnd()->RegisterDequeue(
+ handler_, common::Bind(&impl::handle_dequeue_from_upper, common::Unretained(this), connection_pair));
+ }
+ }
+
+ void handle_dequeue_from_upper(std::map<uint16_t, acl_connection>::iterator connection_pair) {
+ current_connection_pair_ = connection_pair;
+ buffer_packet();
+ }
+
+ void unregister_all_connections() {
+ for (auto connection_pair = acl_connections_.begin(); connection_pair != acl_connections_.end();
+ connection_pair = std::next(connection_pair)) {
+ if (connection_pair->second.is_registered_) {
+ connection_pair->second.is_registered_ = false;
+ connection_pair->second.queue_->GetDownEnd()->UnregisterDequeue();
+ }
+ }
+ }
+
+ void buffer_packet() {
+ unregister_all_connections();
+ BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
+ // Wrap packet and enqueue it
+ uint16_t handle = current_connection_pair_->first;
+
+ auto packet = current_connection_pair_->second.queue_->GetDownEnd()->TryDequeue();
+ ASSERT(packet != nullptr);
+
+ if (packet->size() <= hci_mtu_) {
+ fragments_to_send_.push_front(AclPacketBuilder::Create(handle, PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE,
+ broadcast_flag, std::move(packet)));
+ } else {
+ auto fragments = AclFragmenter(hci_mtu_, std::move(packet)).GetFragments();
+ PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
+ for (size_t i = 0; i < fragments.size(); i++) {
+ fragments_to_send_.push_back(
+ AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(fragments[i])));
+ packet_boundary_flag = PacketBoundaryFlag::CONTINUING_FRAGMENT;
+ }
+ }
+ ASSERT(fragments_to_send_.size() > 0);
+
+ current_connection_pair_->second.number_of_sent_packets_ += fragments_to_send_.size();
+ send_next_fragment();
+ }
+
+ void send_next_fragment() {
+ hci_queue_end_->RegisterEnqueue(handler_,
+ common::Bind(&impl::handle_enqueue_next_fragment, common::Unretained(this)));
+ }
+
+ std::unique_ptr<AclPacketBuilder> handle_enqueue_next_fragment() {
+ ASSERT(acl_packet_credits_ > 0);
+ if (acl_packet_credits_ == 1 || fragments_to_send_.size() == 1) {
+ hci_queue_end_->UnregisterEnqueue();
+ if (fragments_to_send_.size() == 1) {
+ handler_->Post(common::BindOnce(&impl::start_round_robin, common::Unretained(this)));
+ }
+ }
+ ASSERT(fragments_to_send_.size() > 0);
+ auto raw_pointer = fragments_to_send_.front().release();
+ acl_packet_credits_ -= 1;
+ fragments_to_send_.pop_front();
+ return std::unique_ptr<AclPacketBuilder>(raw_pointer);
+ }
+
+ void dequeue_and_route_acl_packet_to_connection() {
+ auto packet = hci_queue_end_->TryDequeue();
+ ASSERT(packet != nullptr);
+ if (!packet->IsValid()) {
+ LOG_INFO("Dropping invalid packet of size %zu", packet->size());
+ return;
+ }
+ uint16_t handle = packet->GetHandle();
+ if (handle == kQualcommDebugHandle) {
+ return;
+ }
+ auto connection_pair = acl_connections_.find(handle);
+ if (connection_pair == acl_connections_.end()) {
+ LOG_INFO("Dropping packet of size %zu to unknown connection 0x%0hx", packet->size(), handle);
+ return;
+ }
+ // TODO: What happens if the connection is stalled and fills up?
+ // TODO hsz: define enqueue callback
+ auto queue_end = connection_pair->second.queue_->GetDownEnd();
+ PacketView<kLittleEndian> payload = packet->GetPayload();
+ queue_end->RegisterEnqueue(handler_, common::Bind(
+ [](decltype(queue_end) queue_end, PacketView<kLittleEndian> payload) {
+ queue_end->UnregisterEnqueue();
+ return std::make_unique<PacketView<kLittleEndian>>(payload);
+ },
+ queue_end, std::move(payload)));
+ }
+
+ void on_incoming_connection(EventPacketView packet) {
+ ConnectionRequestView request = ConnectionRequestView::Create(packet);
+ ASSERT(request.IsValid());
+ Address address = request.GetBdAddr();
+ if (client_callbacks_ == nullptr) {
+ LOG_ERROR("No callbacks to call");
+ auto reason = RejectConnectionReason::LIMITED_RESOURCES;
+ this->reject_connection(RejectConnectionRequestBuilder::Create(address, reason));
+ return;
+ }
+ connecting_.insert(address);
+ if (is_classic_link_already_connected(address)) {
+ auto reason = RejectConnectionReason::UNACCEPTABLE_BD_ADDR;
+ this->reject_connection(RejectConnectionRequestBuilder::Create(address, reason));
+ } else if (should_accept_connection_.Run(address, request.GetClassOfDevice())) {
+ this->accept_connection(address);
+ } else {
+ auto reason = RejectConnectionReason::LIMITED_RESOURCES; // TODO: determine reason
+ this->reject_connection(RejectConnectionRequestBuilder::Create(address, reason));
+ }
+ }
+
+ void on_classic_connection_complete(Address address) {
+ auto connecting_addr = connecting_.find(address);
+ if (connecting_addr == connecting_.end()) {
+ LOG_WARN("No prior connection request for %s", address.ToString().c_str());
+ } else {
+ connecting_.erase(connecting_addr);
+ }
+ }
+
+ void on_common_le_connection_complete(AddressWithType address_with_type) {
+ auto connecting_addr_with_type = connecting_le_.find(address_with_type);
+ if (connecting_addr_with_type == connecting_le_.end()) {
+ LOG_WARN("No prior connection request for %s", address_with_type.ToString().c_str());
+ } else {
+ connecting_le_.erase(connecting_addr_with_type);
+ }
+ }
+
+ void on_le_connection_complete(LeMetaEventView packet) {
+ LeConnectionCompleteView connection_complete = LeConnectionCompleteView::Create(packet);
+ ASSERT(connection_complete.IsValid());
+ auto status = connection_complete.GetStatus();
+ auto address = connection_complete.GetPeerAddress();
+ auto peer_address_type = connection_complete.GetPeerAddressType();
+ // TODO: find out which address and type was used to initiate the connection
+ AddressWithType address_with_type(address, peer_address_type);
+ on_common_le_connection_complete(address_with_type);
+ if (status != ErrorCode::SUCCESS) {
+ le_client_handler_->Post(common::BindOnce(&LeConnectionCallbacks::OnLeConnectFail,
+ common::Unretained(le_client_callbacks_), address_with_type, status));
+ return;
+ }
+ // TODO: Check and save other connection parameters
+ uint16_t handle = connection_complete.GetConnectionHandle();
+ ASSERT(acl_connections_.count(handle) == 0);
+ acl_connections_.emplace(handle, address_with_type);
+ if (acl_connections_.size() == 1 && fragments_to_send_.size() == 0) {
+ start_round_robin();
+ }
+ auto role = connection_complete.GetRole();
+ std::unique_ptr<AclConnection> connection_proxy(
+ new AclConnection(&acl_manager_, handle, address, peer_address_type, role));
+ le_client_handler_->Post(common::BindOnce(&LeConnectionCallbacks::OnLeConnectSuccess,
+ common::Unretained(le_client_callbacks_), address_with_type,
+ std::move(connection_proxy)));
+ }
+
+ void on_le_enhanced_connection_complete(LeMetaEventView packet) {
+ LeEnhancedConnectionCompleteView connection_complete = LeEnhancedConnectionCompleteView::Create(packet);
+ ASSERT(connection_complete.IsValid());
+ auto status = connection_complete.GetStatus();
+ auto address = connection_complete.GetPeerAddress();
+ auto peer_address_type = connection_complete.GetPeerAddressType();
+ auto peer_resolvable_address = connection_complete.GetPeerResolvablePrivateAddress();
+ AddressWithType reporting_address_with_type(address, peer_address_type);
+ if (!peer_resolvable_address.IsEmpty()) {
+ reporting_address_with_type = AddressWithType(peer_resolvable_address, AddressType::RANDOM_DEVICE_ADDRESS);
+ }
+ on_common_le_connection_complete(reporting_address_with_type);
+ if (status != ErrorCode::SUCCESS) {
+ le_client_handler_->Post(common::BindOnce(&LeConnectionCallbacks::OnLeConnectFail,
+ common::Unretained(le_client_callbacks_), reporting_address_with_type,
+ status));
+ return;
+ }
+ // TODO: Check and save other connection parameters
+ uint16_t handle = connection_complete.GetConnectionHandle();
+ ASSERT(acl_connections_.count(handle) == 0);
+ acl_connections_.emplace(handle, reporting_address_with_type);
+ if (acl_connections_.size() == 1 && fragments_to_send_.size() == 0) {
+ start_round_robin();
+ }
+ auto role = connection_complete.GetRole();
+ std::unique_ptr<AclConnection> connection_proxy(
+ new AclConnection(&acl_manager_, handle, address, peer_address_type, role));
+ le_client_handler_->Post(common::BindOnce(&LeConnectionCallbacks::OnLeConnectSuccess,
+ common::Unretained(le_client_callbacks_), reporting_address_with_type,
+ std::move(connection_proxy)));
+ }
+
+ void on_connection_complete(EventPacketView packet) {
+ ConnectionCompleteView connection_complete = ConnectionCompleteView::Create(packet);
+ ASSERT(connection_complete.IsValid());
+ auto status = connection_complete.GetStatus();
+ auto address = connection_complete.GetBdAddr();
+ on_classic_connection_complete(address);
+ if (status != ErrorCode::SUCCESS) {
+ client_handler_->Post(common::BindOnce(&ConnectionCallbacks::OnConnectFail, common::Unretained(client_callbacks_),
+ address, status));
+ return;
+ }
+ uint16_t handle = connection_complete.GetConnectionHandle();
+ ASSERT(acl_connections_.count(handle) == 0);
+ acl_connections_.emplace(handle, AddressWithType{address, AddressType::PUBLIC_DEVICE_ADDRESS});
+ if (acl_connections_.size() == 1 && fragments_to_send_.size() == 0) {
+ start_round_robin();
+ }
+ std::unique_ptr<AclConnection> connection_proxy(new AclConnection(&acl_manager_, handle, address));
+ client_handler_->Post(common::BindOnce(&ConnectionCallbacks::OnConnectSuccess,
+ common::Unretained(client_callbacks_), std::move(connection_proxy)));
+ while (!pending_outgoing_connections_.empty()) {
+ auto create_connection_packet_and_address = std::move(pending_outgoing_connections_.front());
+ pending_outgoing_connections_.pop();
+ if (!is_classic_link_already_connected(create_connection_packet_and_address.first)) {
+ connecting_.insert(create_connection_packet_and_address.first);
+ hci_layer_->EnqueueCommand(std::move(create_connection_packet_and_address.second),
+ common::BindOnce([](CommandStatusView status) {
+ ASSERT(status.IsValid());
+ ASSERT(status.GetCommandOpCode() == OpCode::CREATE_CONNECTION);
+ }),
+ handler_);
+ break;
+ }
+ }
+ }
+
+ void on_disconnection_complete(EventPacketView packet) {
+ DisconnectionCompleteView disconnection_complete = DisconnectionCompleteView::Create(packet);
+ ASSERT(disconnection_complete.IsValid());
+ uint16_t handle = disconnection_complete.GetConnectionHandle();
+ auto status = disconnection_complete.GetStatus();
+ if (status == ErrorCode::SUCCESS) {
+ ASSERT(acl_connections_.count(handle) == 1);
+ auto& acl_connection = acl_connections_.find(handle)->second;
+ acl_connection.is_disconnected_ = true;
+ acl_connection.disconnect_reason_ = disconnection_complete.GetReason();
+ acl_connection.call_disconnect_callback();
+ // Reclaim outstanding packets
+ acl_packet_credits_ += acl_connection.number_of_sent_packets_;
+ acl_connection.number_of_sent_packets_ = 0;
+ } else {
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received disconnection complete with error code %s, handle 0x%02hx", error_code.c_str(), handle);
+ }
+ }
+
+ void on_connection_packet_type_changed(EventPacketView packet) {
+ ConnectionPacketTypeChangedView packet_type_changed = ConnectionPacketTypeChangedView::Create(packet);
+ if (!packet_type_changed.IsValid()) {
+ LOG_ERROR("Received on_connection_packet_type_changed with invalid packet");
+ return;
+ } else if (packet_type_changed.GetStatus() != ErrorCode::SUCCESS) {
+ auto status = packet_type_changed.GetStatus();
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received on_connection_packet_type_changed with error code %s", error_code.c_str());
+ return;
+ }
+ uint16_t handle = packet_type_changed.GetConnectionHandle();
+ auto& acl_connection = acl_connections_.find(handle)->second;
+ if (acl_connection.command_complete_handler_ != nullptr) {
+ uint16_t packet_type = packet_type_changed.GetPacketType();
+ acl_connection.command_complete_handler_->Post(
+ common::BindOnce(&ConnectionManagementCallbacks::OnConnectionPacketTypeChanged,
+ common::Unretained(acl_connection.command_complete_callbacks_), packet_type));
+ }
+ }
+
+ void on_master_link_key_complete(EventPacketView packet) {
+ MasterLinkKeyCompleteView complete_view = MasterLinkKeyCompleteView::Create(packet);
+ if (!complete_view.IsValid()) {
+ LOG_ERROR("Received on_master_link_key_complete with invalid packet");
+ return;
+ } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+ auto status = complete_view.GetStatus();
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received on_master_link_key_complete with error code %s", error_code.c_str());
+ return;
+ }
+ if (acl_manager_client_callbacks_ != nullptr) {
+ uint16_t connection_handle = complete_view.GetConnectionHandle();
+ KeyFlag key_flag = complete_view.GetKeyFlag();
+ acl_manager_client_handler_->Post(common::BindOnce(&AclManagerCallbacks::OnMasterLinkKeyComplete,
+ common::Unretained(acl_manager_client_callbacks_),
+ connection_handle, key_flag));
+ }
+ }
+
+ void on_authentication_complete(EventPacketView packet) {
+ AuthenticationCompleteView authentication_complete = AuthenticationCompleteView::Create(packet);
+ if (!authentication_complete.IsValid()) {
+ LOG_ERROR("Received on_authentication_complete with invalid packet");
+ return;
+ } else if (authentication_complete.GetStatus() != ErrorCode::SUCCESS) {
+ auto status = authentication_complete.GetStatus();
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received on_authentication_complete with error code %s", error_code.c_str());
+ return;
+ }
+ uint16_t handle = authentication_complete.GetConnectionHandle();
+ auto& acl_connection = acl_connections_.find(handle)->second;
+ if (acl_connection.command_complete_handler_ != nullptr) {
+ acl_connection.command_complete_handler_->Post(
+ common::BindOnce(&ConnectionManagementCallbacks::OnAuthenticationComplete,
+ common::Unretained(acl_connection.command_complete_callbacks_)));
+ }
+ }
+
+ void on_encryption_change(EventPacketView packet) {
+ EncryptionChangeView encryption_change_view = EncryptionChangeView::Create(packet);
+ if (!encryption_change_view.IsValid()) {
+ LOG_ERROR("Received on_encryption_change with invalid packet");
+ return;
+ } else if (encryption_change_view.GetStatus() != ErrorCode::SUCCESS) {
+ auto status = encryption_change_view.GetStatus();
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received on_change_connection_link_key_complete with error code %s", error_code.c_str());
+ return;
+ }
+ uint16_t handle = encryption_change_view.GetConnectionHandle();
+ auto& acl_connection = acl_connections_.find(handle)->second;
+ if (acl_connection.command_complete_handler_ != nullptr) {
+ EncryptionEnabled enabled = encryption_change_view.GetEncryptionEnabled();
+ acl_connection.command_complete_handler_->Post(
+ common::BindOnce(&ConnectionManagementCallbacks::OnEncryptionChange,
+ common::Unretained(acl_connection.command_complete_callbacks_), enabled));
+ }
+ }
+
+ void on_change_connection_link_key_complete(EventPacketView packet) {
+ ChangeConnectionLinkKeyCompleteView complete_view = ChangeConnectionLinkKeyCompleteView::Create(packet);
+ if (!complete_view.IsValid()) {
+ LOG_ERROR("Received on_change_connection_link_key_complete with invalid packet");
+ return;
+ } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+ auto status = complete_view.GetStatus();
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received on_change_connection_link_key_complete with error code %s", error_code.c_str());
+ return;
+ }
+ uint16_t handle = complete_view.GetConnectionHandle();
+ auto& acl_connection = acl_connections_.find(handle)->second;
+ if (acl_connection.command_complete_handler_ != nullptr) {
+ acl_connection.command_complete_handler_->Post(
+ common::BindOnce(&ConnectionManagementCallbacks::OnChangeConnectionLinkKeyComplete,
+ common::Unretained(acl_connection.command_complete_callbacks_)));
+ }
+ }
+
+ void on_read_clock_offset_complete(EventPacketView packet) {
+ ReadClockOffsetCompleteView complete_view = ReadClockOffsetCompleteView::Create(packet);
+ if (!complete_view.IsValid()) {
+ LOG_ERROR("Received on_read_clock_offset_complete with invalid packet");
+ return;
+ } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+ auto status = complete_view.GetStatus();
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received on_read_clock_offset_complete with error code %s", error_code.c_str());
+ return;
+ }
+ uint16_t handle = complete_view.GetConnectionHandle();
+ auto& acl_connection = acl_connections_.find(handle)->second;
+ if (acl_connection.command_complete_handler_ != nullptr) {
+ uint16_t clock_offset = complete_view.GetClockOffset();
+ acl_connection.command_complete_handler_->Post(
+ common::BindOnce(&ConnectionManagementCallbacks::OnReadClockOffsetComplete,
+ common::Unretained(acl_connection.command_complete_callbacks_), clock_offset));
+ }
+ }
+
+ void on_mode_change(EventPacketView packet) {
+ ModeChangeView mode_change_view = ModeChangeView::Create(packet);
+ if (!mode_change_view.IsValid()) {
+ LOG_ERROR("Received on_mode_change with invalid packet");
+ return;
+ } else if (mode_change_view.GetStatus() != ErrorCode::SUCCESS) {
+ auto status = mode_change_view.GetStatus();
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received on_mode_change with error code %s", error_code.c_str());
+ return;
+ }
+ uint16_t handle = mode_change_view.GetConnectionHandle();
+ auto& acl_connection = acl_connections_.find(handle)->second;
+ if (acl_connection.command_complete_handler_ != nullptr) {
+ Mode current_mode = mode_change_view.GetCurrentMode();
+ uint16_t interval = mode_change_view.GetInterval();
+ acl_connection.command_complete_handler_->Post(
+ common::BindOnce(&ConnectionManagementCallbacks::OnModeChange,
+ common::Unretained(acl_connection.command_complete_callbacks_), current_mode, interval));
+ }
+ }
+
+ void on_qos_setup_complete(EventPacketView packet) {
+ QosSetupCompleteView complete_view = QosSetupCompleteView::Create(packet);
+ if (!complete_view.IsValid()) {
+ LOG_ERROR("Received on_qos_setup_complete with invalid packet");
+ return;
+ } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+ auto status = complete_view.GetStatus();
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received on_qos_setup_complete with error code %s", error_code.c_str());
+ return;
+ }
+ uint16_t handle = complete_view.GetConnectionHandle();
+ auto& acl_connection = acl_connections_.find(handle)->second;
+ if (acl_connection.command_complete_handler_ != nullptr) {
+ ServiceType service_type = complete_view.GetServiceType();
+ uint32_t token_rate = complete_view.GetTokenRate();
+ uint32_t peak_bandwidth = complete_view.GetPeakBandwidth();
+ uint32_t latency = complete_view.GetLatency();
+ uint32_t delay_variation = complete_view.GetDelayVariation();
+ acl_connection.command_complete_handler_->Post(
+ common::BindOnce(&ConnectionManagementCallbacks::OnQosSetupComplete,
+ common::Unretained(acl_connection.command_complete_callbacks_), service_type, token_rate,
+ peak_bandwidth, latency, delay_variation));
+ }
+ }
+
+ void on_role_change(EventPacketView packet) {
+ RoleChangeView role_change_view = RoleChangeView::Create(packet);
+ if (!role_change_view.IsValid()) {
+ LOG_ERROR("Received on_role_change with invalid packet");
+ return;
+ } else if (role_change_view.GetStatus() != ErrorCode::SUCCESS) {
+ auto status = role_change_view.GetStatus();
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received on_role_change with error code %s", error_code.c_str());
+ return;
+ }
+ if (acl_manager_client_callbacks_ != nullptr) {
+ Address bd_addr = role_change_view.GetBdAddr();
+ Role new_role = role_change_view.GetNewRole();
+ acl_manager_client_handler_->Post(common::BindOnce(
+ &AclManagerCallbacks::OnRoleChange, common::Unretained(acl_manager_client_callbacks_), bd_addr, new_role));
+ }
+ }
+
+ void on_flow_specification_complete(EventPacketView packet) {
+ FlowSpecificationCompleteView complete_view = FlowSpecificationCompleteView::Create(packet);
+ if (!complete_view.IsValid()) {
+ LOG_ERROR("Received on_flow_specification_complete with invalid packet");
+ return;
+ } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+ auto status = complete_view.GetStatus();
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received on_flow_specification_complete with error code %s", error_code.c_str());
+ return;
+ }
+ uint16_t handle = complete_view.GetConnectionHandle();
+ auto& acl_connection = acl_connections_.find(handle)->second;
+ if (acl_connection.command_complete_handler_ != nullptr) {
+ FlowDirection flow_direction = complete_view.GetFlowDirection();
+ ServiceType service_type = complete_view.GetServiceType();
+ uint32_t token_rate = complete_view.GetTokenRate();
+ uint32_t token_bucket_size = complete_view.GetTokenBucketSize();
+ uint32_t peak_bandwidth = complete_view.GetPeakBandwidth();
+ uint32_t access_latency = complete_view.GetAccessLatency();
+ acl_connection.command_complete_handler_->Post(
+ common::BindOnce(&ConnectionManagementCallbacks::OnFlowSpecificationComplete,
+ common::Unretained(acl_connection.command_complete_callbacks_), flow_direction, service_type,
+ token_rate, token_bucket_size, peak_bandwidth, access_latency));
+ }
+ }
+
+ void on_flush_occurred(EventPacketView packet) {
+ FlushOccurredView flush_occurred_view = FlushOccurredView::Create(packet);
+ if (!flush_occurred_view.IsValid()) {
+ LOG_ERROR("Received on_flush_occurred with invalid packet");
+ return;
+ }
+ uint16_t handle = flush_occurred_view.GetConnectionHandle();
+ auto& acl_connection = acl_connections_.find(handle)->second;
+ if (acl_connection.command_complete_handler_ != nullptr) {
+ acl_connection.command_complete_handler_->Post(
+ common::BindOnce(&ConnectionManagementCallbacks::OnFlushOccurred,
+ common::Unretained(acl_connection.command_complete_callbacks_)));
+ }
+ }
+
+ void on_role_discovery_complete(CommandCompleteView view) {
+ auto complete_view = RoleDiscoveryCompleteView::Create(view);
+ if (!complete_view.IsValid()) {
+ LOG_ERROR("Received on_role_discovery_complete with invalid packet");
+ return;
+ } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+ auto status = complete_view.GetStatus();
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received on_role_discovery_complete with error code %s", error_code.c_str());
+ return;
+ }
+ uint16_t handle = complete_view.GetConnectionHandle();
+ auto& acl_connection = acl_connections_.find(handle)->second;
+ if (acl_connection.command_complete_handler_ != nullptr) {
+ Role role = complete_view.GetCurrentRole();
+ acl_connection.command_complete_handler_->Post(
+ common::BindOnce(&ConnectionManagementCallbacks::OnRoleDiscoveryComplete,
+ common::Unretained(acl_connection.command_complete_callbacks_), role));
+ }
+ }
+
+ void on_read_link_policy_settings_complete(CommandCompleteView view) {
+ auto complete_view = ReadLinkPolicySettingsCompleteView::Create(view);
+ if (!complete_view.IsValid()) {
+ LOG_ERROR("Received on_read_link_policy_settings_complete with invalid packet");
+ return;
+ } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+ auto status = complete_view.GetStatus();
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received on_read_link_policy_settings_complete with error code %s", error_code.c_str());
+ return;
+ }
+ uint16_t handle = complete_view.GetConnectionHandle();
+ auto& acl_connection = acl_connections_.find(handle)->second;
+ if (acl_connection.command_complete_handler_ != nullptr) {
+ uint16_t link_policy_settings = complete_view.GetLinkPolicySettings();
+ acl_connection.command_complete_handler_->Post(
+ common::BindOnce(&ConnectionManagementCallbacks::OnReadLinkPolicySettingsComplete,
+ common::Unretained(acl_connection.command_complete_callbacks_), link_policy_settings));
+ }
+ }
+
+ void on_read_default_link_policy_settings_complete(CommandCompleteView view) {
+ auto complete_view = ReadDefaultLinkPolicySettingsCompleteView::Create(view);
+ if (!complete_view.IsValid()) {
+ LOG_ERROR("Received on_read_link_policy_settings_complete with invalid packet");
+ return;
+ } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+ auto status = complete_view.GetStatus();
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received on_read_link_policy_settings_complete with error code %s", error_code.c_str());
+ return;
+ }
+ if (acl_manager_client_callbacks_ != nullptr) {
+ uint16_t default_link_policy_settings = complete_view.GetDefaultLinkPolicySettings();
+ acl_manager_client_handler_->Post(common::BindOnce(&AclManagerCallbacks::OnReadDefaultLinkPolicySettingsComplete,
+ common::Unretained(acl_manager_client_callbacks_),
+ default_link_policy_settings));
+ }
+ }
+
+ void on_read_automatic_flush_timeout_complete(CommandCompleteView view) {
+ auto complete_view = ReadAutomaticFlushTimeoutCompleteView::Create(view);
+ if (!complete_view.IsValid()) {
+ LOG_ERROR("Received on_read_automatic_flush_timeout_complete with invalid packet");
+ return;
+ } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+ auto status = complete_view.GetStatus();
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received on_read_automatic_flush_timeout_complete with error code %s", error_code.c_str());
+ return;
+ }
+ uint16_t handle = complete_view.GetConnectionHandle();
+ auto& acl_connection = acl_connections_.find(handle)->second;
+ if (acl_connection.command_complete_handler_ != nullptr) {
+ uint16_t flush_timeout = complete_view.GetFlushTimeout();
+ acl_connection.command_complete_handler_->Post(
+ common::BindOnce(&ConnectionManagementCallbacks::OnReadAutomaticFlushTimeoutComplete,
+ common::Unretained(acl_connection.command_complete_callbacks_), flush_timeout));
+ }
+ }
+
+ void on_read_transmit_power_level_complete(CommandCompleteView view) {
+ auto complete_view = ReadTransmitPowerLevelCompleteView::Create(view);
+ if (!complete_view.IsValid()) {
+ LOG_ERROR("Received on_read_transmit_power_level_complete with invalid packet");
+ return;
+ } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+ auto status = complete_view.GetStatus();
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received on_read_transmit_power_level_complete with error code %s", error_code.c_str());
+ return;
+ }
+ uint16_t handle = complete_view.GetConnectionHandle();
+ auto& acl_connection = acl_connections_.find(handle)->second;
+ if (acl_connection.command_complete_handler_ != nullptr) {
+ uint8_t transmit_power_level = complete_view.GetTransmitPowerLevel();
+ acl_connection.command_complete_handler_->Post(
+ common::BindOnce(&ConnectionManagementCallbacks::OnReadTransmitPowerLevelComplete,
+ common::Unretained(acl_connection.command_complete_callbacks_), transmit_power_level));
+ }
+ }
+
+ void on_read_link_supervision_timeout_complete(CommandCompleteView view) {
+ auto complete_view = ReadLinkSupervisionTimeoutCompleteView::Create(view);
+ if (!complete_view.IsValid()) {
+ LOG_ERROR("Received on_read_link_supervision_timeout_complete with invalid packet");
+ return;
+ } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+ auto status = complete_view.GetStatus();
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received on_read_link_supervision_timeout_complete with error code %s", error_code.c_str());
+ return;
+ }
+ uint16_t handle = complete_view.GetConnectionHandle();
+ auto& acl_connection = acl_connections_.find(handle)->second;
+ if (acl_connection.command_complete_handler_ != nullptr) {
+ uint16_t link_supervision_timeout = complete_view.GetLinkSupervisionTimeout();
+ acl_connection.command_complete_handler_->Post(
+ common::BindOnce(&ConnectionManagementCallbacks::OnReadLinkSupervisionTimeoutComplete,
+ common::Unretained(acl_connection.command_complete_callbacks_), link_supervision_timeout));
+ }
+ }
+
+ void on_read_failed_contact_counter_complete(CommandCompleteView view) {
+ auto complete_view = ReadFailedContactCounterCompleteView::Create(view);
+ if (!complete_view.IsValid()) {
+ LOG_ERROR("Received on_read_failed_contact_counter_complete with invalid packet");
+ return;
+ } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+ auto status = complete_view.GetStatus();
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received on_read_failed_contact_counter_complete with error code %s", error_code.c_str());
+ return;
+ }
+ uint16_t handle = complete_view.GetConnectionHandle();
+ auto& acl_connection = acl_connections_.find(handle)->second;
+ if (acl_connection.command_complete_handler_ != nullptr) {
+ uint16_t failed_contact_counter = complete_view.GetFailedContactCounter();
+ acl_connection.command_complete_handler_->Post(
+ common::BindOnce(&ConnectionManagementCallbacks::OnReadFailedContactCounterComplete,
+ common::Unretained(acl_connection.command_complete_callbacks_), failed_contact_counter));
+ }
+ }
+
+ void on_read_link_quality_complete(CommandCompleteView view) {
+ auto complete_view = ReadLinkQualityCompleteView::Create(view);
+ if (!complete_view.IsValid()) {
+ LOG_ERROR("Received on_read_link_quality_complete with invalid packet");
+ return;
+ } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+ auto status = complete_view.GetStatus();
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received on_read_link_quality_complete with error code %s", error_code.c_str());
+ return;
+ }
+ uint16_t handle = complete_view.GetConnectionHandle();
+ auto& acl_connection = acl_connections_.find(handle)->second;
+ if (acl_connection.command_complete_handler_ != nullptr) {
+ uint8_t link_quality = complete_view.GetLinkQuality();
+ acl_connection.command_complete_handler_->Post(
+ common::BindOnce(&ConnectionManagementCallbacks::OnReadLinkQualityComplete,
+ common::Unretained(acl_connection.command_complete_callbacks_), link_quality));
+ }
+ }
+
+ void on_read_afh_channel_map_complete(CommandCompleteView view) {
+ auto complete_view = ReadAfhChannelMapCompleteView::Create(view);
+ if (!complete_view.IsValid()) {
+ LOG_ERROR("Received on_read_afh_channel_map_complete with invalid packet");
+ return;
+ } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+ auto status = complete_view.GetStatus();
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received on_read_afh_channel_map_complete with error code %s", error_code.c_str());
+ return;
+ }
+ uint16_t handle = complete_view.GetConnectionHandle();
+ auto& acl_connection = acl_connections_.find(handle)->second;
+ if (acl_connection.command_complete_handler_ != nullptr) {
+ AfhMode afh_mode = complete_view.GetAfhMode();
+ std::array<uint8_t, 10> afh_channel_map = complete_view.GetAfhChannelMap();
+ acl_connection.command_complete_handler_->Post(
+ common::BindOnce(&ConnectionManagementCallbacks::OnReadAfhChannelMapComplete,
+ common::Unretained(acl_connection.command_complete_callbacks_), afh_mode, afh_channel_map));
+ }
+ }
+
+ void on_read_rssi_complete(CommandCompleteView view) {
+ auto complete_view = ReadRssiCompleteView::Create(view);
+ if (!complete_view.IsValid()) {
+ LOG_ERROR("Received on_read_rssi_complete with invalid packet");
+ return;
+ } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+ auto status = complete_view.GetStatus();
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received on_read_rssi_complete with error code %s", error_code.c_str());
+ return;
+ }
+ uint16_t handle = complete_view.GetConnectionHandle();
+ auto& acl_connection = acl_connections_.find(handle)->second;
+ if (acl_connection.command_complete_handler_ != nullptr) {
+ uint8_t rssi = complete_view.GetRssi();
+ acl_connection.command_complete_handler_->Post(
+ common::BindOnce(&ConnectionManagementCallbacks::OnReadRssiComplete,
+ common::Unretained(acl_connection.command_complete_callbacks_), rssi));
+ }
+ }
+
+ void on_read_clock_complete(CommandCompleteView view) {
+ auto complete_view = ReadClockCompleteView::Create(view);
+ if (!complete_view.IsValid()) {
+ LOG_ERROR("Received on_read_clock_complete with invalid packet");
+ return;
+ } else if (complete_view.GetStatus() != ErrorCode::SUCCESS) {
+ auto status = complete_view.GetStatus();
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received on_read_clock_complete with error code %s", error_code.c_str());
+ return;
+ }
+ uint16_t handle = complete_view.GetConnectionHandle();
+ auto& acl_connection = acl_connections_.find(handle)->second;
+ if (acl_connection.command_complete_handler_ != nullptr) {
+ uint32_t clock = complete_view.GetClock();
+ uint16_t accuracy = complete_view.GetAccuracy();
+ acl_connection.command_complete_handler_->Post(
+ common::BindOnce(&ConnectionManagementCallbacks::OnReadClockComplete,
+ common::Unretained(acl_connection.command_complete_callbacks_), clock, accuracy));
+ }
+ }
+
+ bool is_classic_link_already_connected(Address address) {
+ for (const auto& connection : acl_connections_) {
+ if (connection.second.address_with_type_.GetAddress() == address) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void create_connection(Address address) {
+ // TODO: Configure default connection parameters?
+ uint16_t packet_type = 0x4408 /* DM 1,3,5 */ | 0x8810 /*DH 1,3,5 */;
+ PageScanRepetitionMode page_scan_repetition_mode = PageScanRepetitionMode::R1;
+ uint16_t clock_offset = 0;
+ ClockOffsetValid clock_offset_valid = ClockOffsetValid::INVALID;
+ CreateConnectionRoleSwitch allow_role_switch = CreateConnectionRoleSwitch::ALLOW_ROLE_SWITCH;
+ ASSERT(client_callbacks_ != nullptr);
+ std::unique_ptr<CreateConnectionBuilder> packet = CreateConnectionBuilder::Create(
+ address, packet_type, page_scan_repetition_mode, clock_offset, clock_offset_valid, allow_role_switch);
+
+ if (connecting_.empty()) {
+ if (is_classic_link_already_connected(address)) {
+ LOG_WARN("already connected: %s", address.ToString().c_str());
+ return;
+ }
+ connecting_.insert(address);
+ hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce([](CommandStatusView status) {
+ ASSERT(status.IsValid());
+ ASSERT(status.GetCommandOpCode() == OpCode::CREATE_CONNECTION);
+ }),
+ handler_);
+ } else {
+ pending_outgoing_connections_.emplace(address, std::move(packet));
+ }
+ }
+
+ void create_le_connection(AddressWithType address_with_type) {
+ // TODO: Add white list handling.
+ // TODO: Configure default LE connection parameters?
+ uint16_t le_scan_interval = 0x0020;
+ uint16_t le_scan_window = 0x0010;
+ InitiatorFilterPolicy initiator_filter_policy = InitiatorFilterPolicy::USE_PEER_ADDRESS;
+ OwnAddressType own_address_type = OwnAddressType::RANDOM_DEVICE_ADDRESS;
+ uint16_t conn_interval_min = 0x0006;
+ uint16_t conn_interval_max = 0x0C00;
+ uint16_t conn_latency = 0x0C0;
+ uint16_t supervision_timeout = 0x0C00;
+ uint16_t minimum_ce_length = 0x0002;
+ uint16_t maximum_ce_length = 0x0C00;
+ ASSERT(le_client_callbacks_ != nullptr);
+
+ connecting_le_.insert(address_with_type);
+
+ hci_layer_->EnqueueCommand(
+ LeCreateConnectionBuilder::Create(le_scan_interval, le_scan_window, initiator_filter_policy,
+ address_with_type.GetAddressType(), address_with_type.GetAddress(),
+ own_address_type, conn_interval_min, conn_interval_max, conn_latency,
+ supervision_timeout, minimum_ce_length, maximum_ce_length),
+ common::BindOnce([](CommandStatusView status) {
+ ASSERT(status.IsValid());
+ ASSERT(status.GetCommandOpCode() == OpCode::CREATE_CONNECTION);
+ }),
+ handler_);
+ }
+
+ void cancel_connect(Address address) {
+ auto connecting_addr = connecting_.find(address);
+ if (connecting_addr == connecting_.end()) {
+ LOG_INFO("Cannot cancel non-existent connection to %s", address.ToString().c_str());
+ return;
+ }
+ std::unique_ptr<CreateConnectionCancelBuilder> packet = CreateConnectionCancelBuilder::Create(address);
+ hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce([](CommandCompleteView complete) { /* TODO */ }),
+ handler_);
+ }
+
+ void master_link_key(KeyFlag key_flag) {
+ std::unique_ptr<MasterLinkKeyBuilder> packet = MasterLinkKeyBuilder::Create(key_flag);
+ hci_layer_->EnqueueCommand(
+ std::move(packet),
+ common::BindOnce(&impl::check_command_status<MasterLinkKeyStatusView>, common::Unretained(this)), handler_);
+ }
+
+ void switch_role(Address address, Role role) {
+ std::unique_ptr<SwitchRoleBuilder> packet = SwitchRoleBuilder::Create(address, role);
+ hci_layer_->EnqueueCommand(
+ std::move(packet),
+ common::BindOnce(&impl::check_command_status<SwitchRoleStatusView>, common::Unretained(this)), handler_);
+ }
+
+ void read_default_link_policy_settings() {
+ std::unique_ptr<ReadDefaultLinkPolicySettingsBuilder> packet = ReadDefaultLinkPolicySettingsBuilder::Create();
+ hci_layer_->EnqueueCommand(
+ std::move(packet),
+ common::BindOnce(&impl::on_read_default_link_policy_settings_complete, common::Unretained(this)), handler_);
+ }
+
+ void write_default_link_policy_settings(uint16_t default_link_policy_settings) {
+ std::unique_ptr<WriteDefaultLinkPolicySettingsBuilder> packet =
+ WriteDefaultLinkPolicySettingsBuilder::Create(default_link_policy_settings);
+ hci_layer_->EnqueueCommand(
+ std::move(packet),
+ BindOnce(&AclManager::impl::check_command_complete<WriteDefaultLinkPolicySettingsCompleteView>,
+ common::Unretained(this)),
+ handler_);
+ }
+
+ void accept_connection(Address address) {
+ auto role = AcceptConnectionRequestRole::BECOME_MASTER; // We prefer to be master
+ hci_layer_->EnqueueCommand(AcceptConnectionRequestBuilder::Create(address, role),
+ common::BindOnce(&impl::on_accept_connection_status, common::Unretained(this), address),
+ handler_);
+ }
+
+ void handle_disconnect(uint16_t handle, DisconnectReason reason) {
+ ASSERT(acl_connections_.count(handle) == 1);
+ std::unique_ptr<DisconnectBuilder> packet = DisconnectBuilder::Create(handle, reason);
+ hci_layer_->EnqueueCommand(std::move(packet), BindOnce([](CommandStatusView status) { /* TODO: check? */ }),
+ handler_);
+ }
+
+ void handle_change_connection_packet_type(uint16_t handle, uint16_t packet_type) {
+ ASSERT(acl_connections_.count(handle) == 1);
+ std::unique_ptr<ChangeConnectionPacketTypeBuilder> packet =
+ ChangeConnectionPacketTypeBuilder::Create(handle, packet_type);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ BindOnce(&AclManager::impl::check_command_status<ChangeConnectionPacketTypeStatusView>,
+ common::Unretained(this)),
+ handler_);
+ }
+
+ void handle_authentication_requested(uint16_t handle) {
+ std::unique_ptr<AuthenticationRequestedBuilder> packet = AuthenticationRequestedBuilder::Create(handle);
+ hci_layer_->EnqueueCommand(
+ std::move(packet),
+ BindOnce(&AclManager::impl::check_command_status<AuthenticationRequestedStatusView>, common::Unretained(this)),
+ handler_);
+ }
+
+ void handle_set_connection_encryption(uint16_t handle, Enable enable) {
+ std::unique_ptr<SetConnectionEncryptionBuilder> packet = SetConnectionEncryptionBuilder::Create(handle, enable);
+ hci_layer_->EnqueueCommand(
+ std::move(packet),
+ BindOnce(&AclManager::impl::check_command_status<SetConnectionEncryptionStatusView>, common::Unretained(this)),
+ handler_);
+ }
+
+ void handle_change_connection_link_key(uint16_t handle) {
+ std::unique_ptr<ChangeConnectionLinkKeyBuilder> packet = ChangeConnectionLinkKeyBuilder::Create(handle);
+ hci_layer_->EnqueueCommand(
+ std::move(packet),
+ BindOnce(&AclManager::impl::check_command_status<ChangeConnectionLinkKeyStatusView>, common::Unretained(this)),
+ handler_);
+ }
+
+ void handle_read_clock_offset(uint16_t handle) {
+ std::unique_ptr<ReadClockOffsetBuilder> packet = ReadClockOffsetBuilder::Create(handle);
+ hci_layer_->EnqueueCommand(
+ std::move(packet),
+ BindOnce(&AclManager::impl::check_command_status<ReadClockOffsetStatusView>, common::Unretained(this)),
+ handler_);
+ }
+
+ void handle_hold_mode(uint16_t handle, uint16_t max_interval, uint16_t min_interval) {
+ std::unique_ptr<HoldModeBuilder> packet = HoldModeBuilder::Create(handle, max_interval, min_interval);
+ hci_layer_->EnqueueCommand(
+ std::move(packet),
+ BindOnce(&AclManager::impl::check_command_status<HoldModeStatusView>, common::Unretained(this)), handler_);
+ }
+
+ void handle_sniff_mode(uint16_t handle, uint16_t max_interval, uint16_t min_interval, int16_t attempt,
+ uint16_t timeout) {
+ std::unique_ptr<SniffModeBuilder> packet =
+ SniffModeBuilder::Create(handle, max_interval, min_interval, attempt, timeout);
+ hci_layer_->EnqueueCommand(
+ std::move(packet),
+ BindOnce(&AclManager::impl::check_command_status<SniffModeStatusView>, common::Unretained(this)), handler_);
+ }
+
+ void handle_exit_sniff_mode(uint16_t handle) {
+ std::unique_ptr<ExitSniffModeBuilder> packet = ExitSniffModeBuilder::Create(handle);
+ hci_layer_->EnqueueCommand(
+ std::move(packet),
+ BindOnce(&AclManager::impl::check_command_status<ExitSniffModeStatusView>, common::Unretained(this)), handler_);
+ }
+
+ void handle_qos_setup_mode(uint16_t handle, ServiceType service_type, uint32_t token_rate, uint32_t peak_bandwidth,
+ uint32_t latency, uint32_t delay_variation) {
+ std::unique_ptr<QosSetupBuilder> packet =
+ QosSetupBuilder::Create(handle, service_type, token_rate, peak_bandwidth, latency, delay_variation);
+ hci_layer_->EnqueueCommand(
+ std::move(packet),
+ BindOnce(&AclManager::impl::check_command_status<QosSetupStatusView>, common::Unretained(this)), handler_);
+ }
+
+ void handle_role_discovery(uint16_t handle) {
+ std::unique_ptr<RoleDiscoveryBuilder> packet = RoleDiscoveryBuilder::Create(handle);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_role_discovery_complete, common::Unretained(this)), handler_);
+ }
+
+ void handle_read_link_policy_settings(uint16_t handle) {
+ std::unique_ptr<ReadLinkPolicySettingsBuilder> packet = ReadLinkPolicySettingsBuilder::Create(handle);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_read_link_policy_settings_complete, common::Unretained(this)),
+ handler_);
+ }
+
+ void handle_write_link_policy_settings(uint16_t handle, uint16_t link_policy_settings) {
+ std::unique_ptr<WriteLinkPolicySettingsBuilder> packet =
+ WriteLinkPolicySettingsBuilder::Create(handle, link_policy_settings);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ BindOnce(&AclManager::impl::check_command_complete<WriteLinkPolicySettingsCompleteView>,
+ common::Unretained(this)),
+ handler_);
+ }
+
+ void handle_flow_specification(uint16_t handle, FlowDirection flow_direction, ServiceType service_type,
+ uint32_t token_rate, uint32_t token_bucket_size, uint32_t peak_bandwidth,
+ uint32_t access_latency) {
+ std::unique_ptr<FlowSpecificationBuilder> packet = FlowSpecificationBuilder::Create(
+ handle, flow_direction, service_type, token_rate, token_bucket_size, peak_bandwidth, access_latency);
+ hci_layer_->EnqueueCommand(
+ std::move(packet),
+ BindOnce(&AclManager::impl::check_command_status<FlowSpecificationStatusView>, common::Unretained(this)),
+ handler_);
+ }
+
+ void handle_sniff_subrating(uint16_t handle, uint16_t maximum_latency, uint16_t minimum_remote_timeout,
+ uint16_t minimum_local_timeout) {
+ std::unique_ptr<SniffSubratingBuilder> packet =
+ SniffSubratingBuilder::Create(handle, maximum_latency, minimum_remote_timeout, minimum_local_timeout);
+ hci_layer_->EnqueueCommand(
+ std::move(packet),
+ BindOnce(&AclManager::impl::check_command_complete<SniffSubratingCompleteView>, common::Unretained(this)),
+ handler_);
+ }
+
+ void handle_flush(uint16_t handle) {
+ std::unique_ptr<FlushBuilder> packet = FlushBuilder::Create(handle);
+ hci_layer_->EnqueueCommand(
+ std::move(packet),
+ BindOnce(&AclManager::impl::check_command_complete<FlushCompleteView>, common::Unretained(this)), handler_);
+ }
+
+ void handle_read_automatic_flush_timeout(uint16_t handle) {
+ std::unique_ptr<ReadAutomaticFlushTimeoutBuilder> packet = ReadAutomaticFlushTimeoutBuilder::Create(handle);
+ hci_layer_->EnqueueCommand(
+ std::move(packet), common::BindOnce(&impl::on_read_automatic_flush_timeout_complete, common::Unretained(this)),
+ handler_);
+ }
+
+ void handle_write_automatic_flush_timeout(uint16_t handle, uint16_t flush_timeout) {
+ std::unique_ptr<WriteAutomaticFlushTimeoutBuilder> packet =
+ WriteAutomaticFlushTimeoutBuilder::Create(handle, flush_timeout);
+ hci_layer_->EnqueueCommand(
+ std::move(packet),
+ BindOnce(&AclManager::impl::check_command_complete<WriteAutomaticFlushTimeoutCompleteView>,
+ common::Unretained(this)),
+ handler_);
+ }
+
+ void handle_read_transmit_power_level(uint16_t handle, TransmitPowerLevelType type) {
+ std::unique_ptr<ReadTransmitPowerLevelBuilder> packet = ReadTransmitPowerLevelBuilder::Create(handle, type);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_read_transmit_power_level_complete, common::Unretained(this)),
+ handler_);
+ }
+
+ void handle_read_link_supervision_timeout(uint16_t handle) {
+ std::unique_ptr<ReadLinkSupervisionTimeoutBuilder> packet = ReadLinkSupervisionTimeoutBuilder::Create(handle);
+ hci_layer_->EnqueueCommand(
+ std::move(packet), common::BindOnce(&impl::on_read_link_supervision_timeout_complete, common::Unretained(this)),
+ handler_);
+ }
+
+ void handle_write_link_supervision_timeout(uint16_t handle, uint16_t link_supervision_timeout) {
+ std::unique_ptr<WriteLinkSupervisionTimeoutBuilder> packet =
+ WriteLinkSupervisionTimeoutBuilder::Create(handle, link_supervision_timeout);
+ hci_layer_->EnqueueCommand(
+ std::move(packet),
+ BindOnce(&AclManager::impl::check_command_complete<WriteLinkSupervisionTimeoutCompleteView>,
+ common::Unretained(this)),
+ handler_);
+ }
+
+ void handle_read_failed_contact_counter(uint16_t handle) {
+ std::unique_ptr<ReadFailedContactCounterBuilder> packet = ReadFailedContactCounterBuilder::Create(handle);
+ hci_layer_->EnqueueCommand(
+ std::move(packet), common::BindOnce(&impl::on_read_failed_contact_counter_complete, common::Unretained(this)),
+ handler_);
+ }
+
+ void handle_reset_failed_contact_counter(uint16_t handle) {
+ std::unique_ptr<ResetFailedContactCounterBuilder> packet = ResetFailedContactCounterBuilder::Create(handle);
+ hci_layer_->EnqueueCommand(std::move(packet), BindOnce([](CommandCompleteView view) { /* TODO: check? */ }),
+ handler_);
+ }
+
+ void handle_read_link_quality(uint16_t handle) {
+ std::unique_ptr<ReadLinkQualityBuilder> packet = ReadLinkQualityBuilder::Create(handle);
+ hci_layer_->EnqueueCommand(
+ std::move(packet), common::BindOnce(&impl::on_read_link_quality_complete, common::Unretained(this)), handler_);
+ }
+
+ void handle_afh_channel_map(uint16_t handle) {
+ std::unique_ptr<ReadAfhChannelMapBuilder> packet = ReadAfhChannelMapBuilder::Create(handle);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_read_afh_channel_map_complete, common::Unretained(this)),
+ handler_);
+ }
+
+ void handle_read_rssi(uint16_t handle) {
+ std::unique_ptr<ReadRssiBuilder> packet = ReadRssiBuilder::Create(handle);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_read_rssi_complete, common::Unretained(this)), handler_);
+ }
+
+ void handle_read_clock(uint16_t handle, WhichClock which_clock) {
+ std::unique_ptr<ReadClockBuilder> packet = ReadClockBuilder::Create(handle, which_clock);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_read_clock_complete, common::Unretained(this)), handler_);
+ }
+
+ template <class T>
+ void check_command_complete(CommandCompleteView view) {
+ ASSERT(view.IsValid());
+ auto status_view = T::Create(view);
+ if (!status_view.IsValid()) {
+ LOG_ERROR("Received command complete with invalid packet, opcode 0x%02hx", view.GetCommandOpCode());
+ return;
+ }
+ ErrorCode status = status_view.GetStatus();
+ OpCode op_code = status_view.GetCommandOpCode();
+ if (status != ErrorCode::SUCCESS) {
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received command complete with error code %s, opcode 0x%02hx", error_code.c_str(), op_code);
+ return;
+ }
+ }
+
+ template <class T>
+ void check_command_status(CommandStatusView view) {
+ ASSERT(view.IsValid());
+ auto status_view = T::Create(view);
+ if (!status_view.IsValid()) {
+ LOG_ERROR("Received command status with invalid packet, opcode 0x%02hx", view.GetCommandOpCode());
+ return;
+ }
+ ErrorCode status = status_view.GetStatus();
+ OpCode op_code = status_view.GetCommandOpCode();
+ if (status != ErrorCode::SUCCESS) {
+ std::string error_code = ErrorCodeText(status);
+ LOG_ERROR("Received command status with error code %s, opcode 0x%02hx", error_code.c_str(), op_code);
+ return;
+ }
+ }
+
+ void cleanup(uint16_t handle) {
+ ASSERT(acl_connections_.count(handle) == 1);
+ auto& acl_connection = acl_connections_.find(handle)->second;
+ if (acl_connection.is_registered_) {
+ acl_connection.is_registered_ = false;
+ acl_connection.queue_->GetDownEnd()->UnregisterDequeue();
+ }
+ acl_connections_.erase(handle);
+ }
+
+ void on_accept_connection_status(Address address, CommandStatusView status) {
+ auto accept_status = AcceptConnectionRequestStatusView::Create(status);
+ ASSERT(accept_status.IsValid());
+ if (status.GetStatus() != ErrorCode::SUCCESS) {
+ cancel_connect(address);
+ }
+ }
+
+ void reject_connection(std::unique_ptr<RejectConnectionRequestBuilder> builder) {
+ hci_layer_->EnqueueCommand(std::move(builder), BindOnce([](CommandStatusView status) { /* TODO: check? */ }),
+ handler_);
+ }
+
+ void handle_register_callbacks(ConnectionCallbacks* callbacks, os::Handler* handler) {
+ ASSERT(client_callbacks_ == nullptr);
+ ASSERT(client_handler_ == nullptr);
+ client_callbacks_ = callbacks;
+ client_handler_ = handler;
+ }
+
+ void handle_register_le_callbacks(LeConnectionCallbacks* callbacks, os::Handler* handler) {
+ ASSERT(le_client_callbacks_ == nullptr);
+ ASSERT(le_client_handler_ == nullptr);
+ le_client_callbacks_ = callbacks;
+ le_client_handler_ = handler;
+ }
+
+ void handle_register_acl_manager_callbacks(AclManagerCallbacks* callbacks, os::Handler* handler) {
+ ASSERT(acl_manager_client_callbacks_ == nullptr);
+ ASSERT(acl_manager_client_handler_ == nullptr);
+ acl_manager_client_callbacks_ = callbacks;
+ acl_manager_client_handler_ = handler;
+ }
+
+ acl_connection& check_and_get_connection(uint16_t handle) {
+ auto connection = acl_connections_.find(handle);
+ ASSERT(connection != acl_connections_.end());
+ return connection->second;
+ }
+
+ AclConnection::QueueUpEnd* get_acl_queue_end(uint16_t handle) {
+ auto& connection = check_and_get_connection(handle);
+ return connection.queue_->GetUpEnd();
+ }
+
+ void RegisterCallbacks(uint16_t handle, ConnectionManagementCallbacks* callbacks, os::Handler* handler) {
+ auto& connection = check_and_get_connection(handle);
+ connection.command_complete_callbacks_ = callbacks;
+ connection.command_complete_handler_ = handler;
+ }
+
+ void RegisterDisconnectCallback(uint16_t handle, common::OnceCallback<void(ErrorCode)> on_disconnect,
+ os::Handler* handler) {
+ auto& connection = check_and_get_connection(handle);
+ connection.on_disconnect_callback_ = std::move(on_disconnect);
+ connection.disconnect_handler_ = handler;
+ if (connection.is_disconnected_) {
+ connection.call_disconnect_callback();
+ }
+ }
+
+ bool Disconnect(uint16_t handle, DisconnectReason reason) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_disconnect, common::Unretained(this), handle, reason));
+ return true;
+ }
+
+ bool ChangeConnectionPacketType(uint16_t handle, uint16_t packet_type) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(
+ BindOnce(&impl::handle_change_connection_packet_type, common::Unretained(this), handle, packet_type));
+ return true;
+ }
+
+ bool AuthenticationRequested(uint16_t handle) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_authentication_requested, common::Unretained(this), handle));
+ return true;
+ }
+
+ bool SetConnectionEncryption(uint16_t handle, Enable enable) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_set_connection_encryption, common::Unretained(this), handle, enable));
+ return true;
+ }
+
+ bool ChangeConnectionLinkKey(uint16_t handle) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_change_connection_link_key, common::Unretained(this), handle));
+ return true;
+ }
+
+ bool ReadClockOffset(uint16_t handle) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_read_clock_offset, common::Unretained(this), handle));
+ return true;
+ }
+
+ bool HoldMode(uint16_t handle, uint16_t max_interval, uint16_t min_interval) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_hold_mode, common::Unretained(this), handle, max_interval, min_interval));
+ return true;
+ }
+
+ bool SniffMode(uint16_t handle, uint16_t max_interval, uint16_t min_interval, int16_t attempt, uint16_t timeout) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_sniff_mode, common::Unretained(this), handle, max_interval, min_interval,
+ attempt, timeout));
+ return true;
+ }
+
+ bool ExitSniffMode(uint16_t handle) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_exit_sniff_mode, common::Unretained(this), handle));
+ return true;
+ }
+
+ bool QosSetup(uint16_t handle, ServiceType service_type, uint32_t token_rate, uint32_t peak_bandwidth,
+ uint32_t latency, uint32_t delay_variation) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_qos_setup_mode, common::Unretained(this), handle, service_type, token_rate,
+ peak_bandwidth, latency, delay_variation));
+ return true;
+ }
+
+ bool RoleDiscovery(uint16_t handle) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_role_discovery, common::Unretained(this), handle));
+ return true;
+ }
+
+ bool ReadLinkPolicySettings(uint16_t handle) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_read_link_policy_settings, common::Unretained(this), handle));
+ return true;
+ }
+
+ bool WriteLinkPolicySettings(uint16_t handle, uint16_t link_policy_settings) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(
+ BindOnce(&impl::handle_write_link_policy_settings, common::Unretained(this), handle, link_policy_settings));
+ return true;
+ }
+
+ bool FlowSpecification(uint16_t handle, FlowDirection flow_direction, ServiceType service_type, uint32_t token_rate,
+ uint32_t token_bucket_size, uint32_t peak_bandwidth, uint32_t access_latency) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_flow_specification, common::Unretained(this), handle, flow_direction,
+ service_type, token_rate, token_bucket_size, peak_bandwidth, access_latency));
+ return true;
+ }
+
+ bool SniffSubrating(uint16_t handle, uint16_t maximum_latency, uint16_t minimum_remote_timeout,
+ uint16_t minimum_local_timeout) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_sniff_subrating, common::Unretained(this), handle, maximum_latency,
+ minimum_remote_timeout, minimum_local_timeout));
+ return true;
+ }
+
+ bool Flush(uint16_t handle) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_flush, common::Unretained(this), handle));
+ return true;
+ }
+
+ bool ReadAutomaticFlushTimeout(uint16_t handle) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_read_automatic_flush_timeout, common::Unretained(this), handle));
+ return true;
+ }
+
+ bool WriteAutomaticFlushTimeout(uint16_t handle, uint16_t flush_timeout) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(
+ BindOnce(&impl::handle_write_automatic_flush_timeout, common::Unretained(this), handle, flush_timeout));
+ return true;
+ }
+
+ bool ReadTransmitPowerLevel(uint16_t handle, TransmitPowerLevelType type) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_read_transmit_power_level, common::Unretained(this), handle, type));
+ return true;
+ }
+
+ bool ReadLinkSupervisionTimeout(uint16_t handle) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_read_link_supervision_timeout, common::Unretained(this), handle));
+ return true;
+ }
+
+ bool WriteLinkSupervisionTimeout(uint16_t handle, uint16_t link_supervision_timeout) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_write_link_supervision_timeout, common::Unretained(this), handle,
+ link_supervision_timeout));
+ return true;
+ }
+
+ bool ReadFailedContactCounter(uint16_t handle) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_read_failed_contact_counter, common::Unretained(this), handle));
+ return true;
+ }
+
+ bool ResetFailedContactCounter(uint16_t handle) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_reset_failed_contact_counter, common::Unretained(this), handle));
+ return true;
+ }
+
+ bool ReadLinkQuality(uint16_t handle) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_read_link_quality, common::Unretained(this), handle));
+ return true;
+ }
+
+ bool ReadAfhChannelMap(uint16_t handle) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_afh_channel_map, common::Unretained(this), handle));
+ return true;
+ }
+
+ bool ReadRssi(uint16_t handle) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_read_rssi, common::Unretained(this), handle));
+ return true;
+ }
+
+ bool ReadClock(uint16_t handle, WhichClock which_clock) {
+ auto& connection = check_and_get_connection(handle);
+ if (connection.is_disconnected_) {
+ LOG_INFO("Already disconnected");
+ return false;
+ }
+ handler_->Post(BindOnce(&impl::handle_read_clock, common::Unretained(this), handle, which_clock));
+ return true;
+ }
+
+ void Finish(uint16_t handle) {
+ auto& connection = check_and_get_connection(handle);
+ ASSERT_LOG(connection.is_disconnected_, "Finish must be invoked after disconnection (handle 0x%04hx)", handle);
+ handler_->Post(BindOnce(&impl::cleanup, common::Unretained(this), handle));
+ }
+
+ const AclManager& acl_manager_;
+
+ Controller* controller_ = nullptr;
+ uint16_t max_acl_packet_credits_ = 0;
+ uint16_t acl_packet_credits_ = 0;
+ uint16_t acl_buffer_length_ = 0;
+
+ std::list<std::unique_ptr<AclPacketBuilder>> fragments_to_send_;
+ std::map<uint16_t, acl_connection>::iterator current_connection_pair_;
+
+ HciLayer* hci_layer_ = nullptr;
+ os::Handler* handler_ = nullptr;
+ ConnectionCallbacks* client_callbacks_ = nullptr;
+ os::Handler* client_handler_ = nullptr;
+ LeConnectionCallbacks* le_client_callbacks_ = nullptr;
+ os::Handler* le_client_handler_ = nullptr;
+ AclManagerCallbacks* acl_manager_client_callbacks_ = nullptr;
+ os::Handler* acl_manager_client_handler_ = nullptr;
+ common::BidiQueueEnd<AclPacketBuilder, AclPacketView>* hci_queue_end_ = nullptr;
+ std::map<uint16_t, AclManager::acl_connection> acl_connections_;
+ std::set<Address> connecting_;
+ std::set<AddressWithType> connecting_le_;
+ common::Callback<bool(Address, ClassOfDevice)> should_accept_connection_;
+ std::queue<std::pair<Address, std::unique_ptr<CreateConnectionBuilder>>> pending_outgoing_connections_;
+ size_t hci_mtu_{0};
+};
+
+AclConnection::QueueUpEnd* AclConnection::GetAclQueueEnd() const {
+ return manager_->pimpl_->get_acl_queue_end(handle_);
+}
+
+void AclConnection::RegisterCallbacks(ConnectionManagementCallbacks* callbacks, os::Handler* handler) {
+ return manager_->pimpl_->RegisterCallbacks(handle_, callbacks, handler);
+}
+
+void AclConnection::RegisterDisconnectCallback(common::OnceCallback<void(ErrorCode)> on_disconnect,
+ os::Handler* handler) {
+ return manager_->pimpl_->RegisterDisconnectCallback(handle_, std::move(on_disconnect), handler);
+}
+
+bool AclConnection::Disconnect(DisconnectReason reason) {
+ return manager_->pimpl_->Disconnect(handle_, reason);
+}
+
+bool AclConnection::ChangeConnectionPacketType(uint16_t packet_type) {
+ return manager_->pimpl_->ChangeConnectionPacketType(handle_, packet_type);
+}
+
+bool AclConnection::AuthenticationRequested() {
+ return manager_->pimpl_->AuthenticationRequested(handle_);
+}
+
+bool AclConnection::SetConnectionEncryption(Enable enable) {
+ return manager_->pimpl_->SetConnectionEncryption(handle_, enable);
+}
+
+bool AclConnection::ChangeConnectionLinkKey() {
+ return manager_->pimpl_->ChangeConnectionLinkKey(handle_);
+}
+
+bool AclConnection::ReadClockOffset() {
+ return manager_->pimpl_->ReadClockOffset(handle_);
+}
+
+bool AclConnection::HoldMode(uint16_t max_interval, uint16_t min_interval) {
+ return manager_->pimpl_->HoldMode(handle_, max_interval, min_interval);
+}
+
+bool AclConnection::SniffMode(uint16_t max_interval, uint16_t min_interval, uint16_t attempt, uint16_t timeout) {
+ return manager_->pimpl_->SniffMode(handle_, max_interval, min_interval, attempt, timeout);
+}
+
+bool AclConnection::ExitSniffMode() {
+ return manager_->pimpl_->ExitSniffMode(handle_);
+}
+
+bool AclConnection::QosSetup(ServiceType service_type, uint32_t token_rate, uint32_t peak_bandwidth, uint32_t latency,
+ uint32_t delay_variation) {
+ return manager_->pimpl_->QosSetup(handle_, service_type, token_rate, peak_bandwidth, latency, delay_variation);
+}
+
+bool AclConnection::RoleDiscovery() {
+ return manager_->pimpl_->RoleDiscovery(handle_);
+}
+
+bool AclConnection::ReadLinkPolicySettings() {
+ return manager_->pimpl_->ReadLinkPolicySettings(handle_);
+}
+
+bool AclConnection::WriteLinkPolicySettings(uint16_t link_policy_settings) {
+ return manager_->pimpl_->WriteLinkPolicySettings(handle_, link_policy_settings);
+}
+
+bool AclConnection::FlowSpecification(FlowDirection flow_direction, ServiceType service_type, uint32_t token_rate,
+ uint32_t token_bucket_size, uint32_t peak_bandwidth, uint32_t access_latency) {
+ return manager_->pimpl_->FlowSpecification(handle_, flow_direction, service_type, token_rate, token_bucket_size,
+ peak_bandwidth, access_latency);
+}
+
+bool AclConnection::SniffSubrating(uint16_t maximum_latency, uint16_t minimum_remote_timeout,
+ uint16_t minimum_local_timeout) {
+ return manager_->pimpl_->SniffSubrating(handle_, maximum_latency, minimum_remote_timeout, minimum_local_timeout);
+}
+
+bool AclConnection::Flush() {
+ return manager_->pimpl_->Flush(handle_);
+}
+
+bool AclConnection::ReadAutomaticFlushTimeout() {
+ return manager_->pimpl_->ReadAutomaticFlushTimeout(handle_);
+}
+
+bool AclConnection::WriteAutomaticFlushTimeout(uint16_t flush_timeout) {
+ return manager_->pimpl_->WriteAutomaticFlushTimeout(handle_, flush_timeout);
+}
+
+bool AclConnection::ReadTransmitPowerLevel(TransmitPowerLevelType type) {
+ return manager_->pimpl_->ReadTransmitPowerLevel(handle_, type);
+}
+
+bool AclConnection::ReadLinkSupervisionTimeout() {
+ return manager_->pimpl_->ReadLinkSupervisionTimeout(handle_);
+}
+
+bool AclConnection::WriteLinkSupervisionTimeout(uint16_t link_supervision_timeout) {
+ return manager_->pimpl_->WriteLinkSupervisionTimeout(handle_, link_supervision_timeout);
+}
+
+bool AclConnection::ReadFailedContactCounter() {
+ return manager_->pimpl_->ReadFailedContactCounter(handle_);
+}
+
+bool AclConnection::ResetFailedContactCounter() {
+ return manager_->pimpl_->ResetFailedContactCounter(handle_);
+}
+
+bool AclConnection::ReadLinkQuality() {
+ return manager_->pimpl_->ReadLinkQuality(handle_);
+}
+
+bool AclConnection::ReadAfhChannelMap() {
+ return manager_->pimpl_->ReadAfhChannelMap(handle_);
+}
+
+bool AclConnection::ReadRssi() {
+ return manager_->pimpl_->ReadRssi(handle_);
+}
+
+bool AclConnection::ReadClock(WhichClock which_clock) {
+ return manager_->pimpl_->ReadClock(handle_, which_clock);
+}
+
+void AclConnection::Finish() {
+ return manager_->pimpl_->Finish(handle_);
+}
+
+AclManager::AclManager() : pimpl_(std::make_unique<impl>(*this)) {}
+
+void AclManager::RegisterCallbacks(ConnectionCallbacks* callbacks, os::Handler* handler) {
+ ASSERT(callbacks != nullptr && handler != nullptr);
+ GetHandler()->Post(common::BindOnce(&impl::handle_register_callbacks, common::Unretained(pimpl_.get()),
+ common::Unretained(callbacks), common::Unretained(handler)));
+}
+
+void AclManager::RegisterLeCallbacks(LeConnectionCallbacks* callbacks, os::Handler* handler) {
+ ASSERT(callbacks != nullptr && handler != nullptr);
+ GetHandler()->Post(common::BindOnce(&impl::handle_register_le_callbacks, common::Unretained(pimpl_.get()),
+ common::Unretained(callbacks), common::Unretained(handler)));
+}
+
+void AclManager::RegisterAclManagerCallbacks(AclManagerCallbacks* callbacks, os::Handler* handler) {
+ ASSERT(callbacks != nullptr && handler != nullptr);
+ GetHandler()->Post(common::BindOnce(&impl::handle_register_acl_manager_callbacks, common::Unretained(pimpl_.get()),
+ common::Unretained(callbacks), common::Unretained(handler)));
+}
+
+void AclManager::CreateConnection(Address address) {
+ GetHandler()->Post(common::BindOnce(&impl::create_connection, common::Unretained(pimpl_.get()), address));
+}
+
+void AclManager::CreateLeConnection(AddressWithType address_with_type) {
+ GetHandler()->Post(
+ common::BindOnce(&impl::create_le_connection, common::Unretained(pimpl_.get()), address_with_type));
+}
+
+void AclManager::CancelConnect(Address address) {
+ GetHandler()->Post(BindOnce(&impl::cancel_connect, common::Unretained(pimpl_.get()), address));
+}
+
+void AclManager::MasterLinkKey(KeyFlag key_flag) {
+ GetHandler()->Post(BindOnce(&impl::master_link_key, common::Unretained(pimpl_.get()), key_flag));
+}
+
+void AclManager::SwitchRole(Address address, Role role) {
+ GetHandler()->Post(BindOnce(&impl::switch_role, common::Unretained(pimpl_.get()), address, role));
+}
+
+void AclManager::ReadDefaultLinkPolicySettings() {
+ GetHandler()->Post(BindOnce(&impl::read_default_link_policy_settings, common::Unretained(pimpl_.get())));
+}
+
+void AclManager::WriteDefaultLinkPolicySettings(uint16_t default_link_policy_settings) {
+ GetHandler()->Post(BindOnce(&impl::write_default_link_policy_settings, common::Unretained(pimpl_.get()),
+ default_link_policy_settings));
+}
+
+void AclManager::ListDependencies(ModuleList* list) {
+ list->add<HciLayer>();
+ list->add<Controller>();
+}
+
+void AclManager::Start() {
+ pimpl_->Start();
+}
+
+void AclManager::Stop() {
+ pimpl_->Stop();
+}
+
+std::string AclManager::ToString() const {
+ return "Acl Manager";
+}
+
+const ModuleFactory AclManager::Factory = ModuleFactory([]() { return new AclManager(); });
+
+AclManager::~AclManager() = default;
+
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/acl_manager.h b/gd/hci/acl_manager.h
new file mode 100644
index 0000000..3706aba
--- /dev/null
+++ b/gd/hci/acl_manager.h
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include "common/bidi_queue.h"
+#include "common/callback.h"
+#include "hci/address.h"
+#include "hci/address_with_type.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+namespace hci {
+
+class AclManager;
+
+class ConnectionManagementCallbacks {
+ public:
+ virtual ~ConnectionManagementCallbacks() = default;
+ // Invoked when controller sends Connection Packet Type Changed event with Success error code
+ virtual void OnConnectionPacketTypeChanged(uint16_t packet_type) = 0;
+ // Invoked when controller sends Authentication Complete event with Success error code
+ virtual void OnAuthenticationComplete() = 0;
+ // Invoked when controller sends Encryption Change event with Success error code
+ virtual void OnEncryptionChange(EncryptionEnabled enabled) = 0;
+ // Invoked when controller sends Change Connection Link Key Complete event with Success error code
+ virtual void OnChangeConnectionLinkKeyComplete() = 0;
+ // Invoked when controller sends Read Clock Offset Complete event with Success error code
+ virtual void OnReadClockOffsetComplete(uint16_t clock_offset) = 0;
+ // Invoked when controller sends Mode Change event with Success error code
+ virtual void OnModeChange(Mode current_mode, uint16_t interval) = 0;
+ // Invoked when controller sends QoS Setup Complete event with Success error code
+ virtual void OnQosSetupComplete(ServiceType service_type, uint32_t token_rate, uint32_t peak_bandwidth,
+ uint32_t latency, uint32_t delay_variation) = 0;
+ // Invoked when controller sends Flow Specification Complete event with Success error code
+ virtual void OnFlowSpecificationComplete(FlowDirection flow_direction, ServiceType service_type, uint32_t token_rate,
+ uint32_t token_bucket_size, uint32_t peak_bandwidth,
+ uint32_t access_latency) = 0;
+ // Invoked when controller sends Flush Occurred event
+ virtual void OnFlushOccurred() = 0;
+ // Invoked when controller sends Command Complete event for Role Discovery command with Success error code
+ virtual void OnRoleDiscoveryComplete(Role current_role) = 0;
+ // Invoked when controller sends Command Complete event for Read Link Policy Settings command with Success error code
+ virtual void OnReadLinkPolicySettingsComplete(uint16_t link_policy_settings) = 0;
+ // Invoked when controller sends Command Complete event for Read Automatic Flush Timeout command with Success error
+ // code
+ virtual void OnReadAutomaticFlushTimeoutComplete(uint16_t flush_timeout) = 0;
+ // Invoked when controller sends Command Complete event for Read Transmit Power Level command with Success error code
+ virtual void OnReadTransmitPowerLevelComplete(uint8_t transmit_power_level) = 0;
+ // Invoked when controller sends Command Complete event for Read Link Supervision Time out command with Success error
+ // code
+ virtual void OnReadLinkSupervisionTimeoutComplete(uint16_t link_supervision_timeout) = 0;
+ // Invoked when controller sends Command Complete event for Read Failed Contact Counter command with Success error
+ // code
+ virtual void OnReadFailedContactCounterComplete(uint16_t failed_contact_counter) = 0;
+ // Invoked when controller sends Command Complete event for Read Link Quality command with Success error code
+ virtual void OnReadLinkQualityComplete(uint8_t link_quality) = 0;
+ // Invoked when controller sends Command Complete event for Read AFH Channel Map command with Success error code
+ virtual void OnReadAfhChannelMapComplete(AfhMode afh_mode, std::array<uint8_t, 10> afh_channel_map) = 0;
+ // Invoked when controller sends Command Complete event for Read RSSI command with Success error code
+ virtual void OnReadRssiComplete(uint8_t rssi) = 0;
+ // Invoked when controller sends Command Complete event for Read Clock command with Success error code
+ virtual void OnReadClockComplete(uint32_t clock, uint16_t accuracy) = 0;
+};
+
+class AclConnection {
+ public:
+ AclConnection()
+ : manager_(nullptr), handle_(0), address_(Address::kEmpty), address_type_(AddressType::PUBLIC_DEVICE_ADDRESS){};
+ virtual ~AclConnection() = default;
+
+ virtual Address GetAddress() const {
+ return address_;
+ }
+
+ virtual AddressType GetAddressType() const {
+ return address_type_;
+ }
+
+ uint16_t GetHandle() const {
+ return handle_;
+ }
+
+ /* This return role for LE devices only, for Classic, please see |RoleDiscovery| method.
+ * TODO: split AclConnection for LE and Classic
+ */
+ Role GetRole() const {
+ return role_;
+ }
+
+ using Queue = common::BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder>;
+ using QueueUpEnd = common::BidiQueueEnd<BasePacketBuilder, PacketView<kLittleEndian>>;
+ using QueueDownEnd = common::BidiQueueEnd<PacketView<kLittleEndian>, BasePacketBuilder>;
+ virtual QueueUpEnd* GetAclQueueEnd() const;
+ virtual void RegisterCallbacks(ConnectionManagementCallbacks* callbacks, os::Handler* handler);
+ virtual void RegisterDisconnectCallback(common::OnceCallback<void(ErrorCode)> on_disconnect, os::Handler* handler);
+ virtual bool Disconnect(DisconnectReason reason);
+ virtual bool ChangeConnectionPacketType(uint16_t packet_type);
+ virtual bool AuthenticationRequested();
+ virtual bool SetConnectionEncryption(Enable enable);
+ virtual bool ChangeConnectionLinkKey();
+ virtual bool ReadClockOffset();
+ virtual bool HoldMode(uint16_t max_interval, uint16_t min_interval);
+ virtual bool SniffMode(uint16_t max_interval, uint16_t min_interval, uint16_t attempt, uint16_t timeout);
+ virtual bool ExitSniffMode();
+ virtual bool QosSetup(ServiceType service_type, uint32_t token_rate, uint32_t peak_bandwidth, uint32_t latency,
+ uint32_t delay_variation);
+ virtual bool RoleDiscovery();
+ virtual bool ReadLinkPolicySettings();
+ virtual bool WriteLinkPolicySettings(uint16_t link_policy_settings);
+ virtual bool FlowSpecification(FlowDirection flow_direction, ServiceType service_type, uint32_t token_rate,
+ uint32_t token_bucket_size, uint32_t peak_bandwidth, uint32_t access_latency);
+ virtual bool SniffSubrating(uint16_t maximum_latency, uint16_t minimum_remote_timeout,
+ uint16_t minimum_local_timeout);
+ virtual bool Flush();
+ virtual bool ReadAutomaticFlushTimeout();
+ virtual bool WriteAutomaticFlushTimeout(uint16_t flush_timeout);
+ virtual bool ReadTransmitPowerLevel(TransmitPowerLevelType type);
+ virtual bool ReadLinkSupervisionTimeout();
+ virtual bool WriteLinkSupervisionTimeout(uint16_t link_supervision_timeout);
+ virtual bool ReadFailedContactCounter();
+ virtual bool ResetFailedContactCounter();
+ virtual bool ReadLinkQuality();
+ virtual bool ReadAfhChannelMap();
+ virtual bool ReadRssi();
+ virtual bool ReadClock(WhichClock which_clock);
+
+ // Ask AclManager to clean me up. Must invoke after on_disconnect is called
+ virtual void Finish();
+
+ // TODO: API to change link settings ... ?
+
+ private:
+ friend AclManager;
+ AclConnection(const AclManager* manager, uint16_t handle, Address address)
+ : manager_(manager), handle_(handle), address_(address), address_type_(AddressType::PUBLIC_DEVICE_ADDRESS) {}
+ AclConnection(const AclManager* manager, uint16_t handle, Address address, AddressType address_type, Role role)
+ : manager_(manager), handle_(handle), address_(address), address_type_(address_type), role_(role) {}
+ const AclManager* manager_;
+ uint16_t handle_;
+ Address address_;
+ AddressType address_type_;
+ Role role_;
+ DISALLOW_COPY_AND_ASSIGN(AclConnection);
+};
+
+class ConnectionCallbacks {
+ public:
+ virtual ~ConnectionCallbacks() = default;
+ // Invoked when controller sends Connection Complete event with Success error code
+ virtual void OnConnectSuccess(std::unique_ptr<AclConnection> /* , initiated_by_local ? */) = 0;
+ // Invoked when controller sends Connection Complete event with non-Success error code
+ virtual void OnConnectFail(Address, ErrorCode reason) = 0;
+};
+
+class LeConnectionCallbacks {
+ public:
+ virtual ~LeConnectionCallbacks() = default;
+ // Invoked when controller sends Connection Complete event with Success error code
+ // AddressWithType is always equal to the object used in AclManager#CreateLeConnection
+ virtual void OnLeConnectSuccess(AddressWithType, std::unique_ptr<AclConnection> /* , initiated_by_local ? */) = 0;
+ // Invoked when controller sends Connection Complete event with non-Success error code
+ virtual void OnLeConnectFail(AddressWithType, ErrorCode reason) = 0;
+};
+
+class AclManagerCallbacks {
+ public:
+ virtual ~AclManagerCallbacks() = default;
+ // Invoked when controller sends Master Link Key Complete event with Success error code
+ virtual void OnMasterLinkKeyComplete(uint16_t connection_handle, KeyFlag key_flag) = 0;
+ // Invoked when controller sends Role Change event with Success error code
+ virtual void OnRoleChange(Address bd_addr, Role new_role) = 0;
+ // Invoked when controller sends Command Complete event for Read Default Link Policy Settings command with Success
+ // error code
+ virtual void OnReadDefaultLinkPolicySettingsComplete(uint16_t default_link_policy_settings) = 0;
+};
+
+class AclManager : public Module {
+ public:
+ AclManager();
+ // NOTE: It is necessary to forward declare a default destructor that overrides the base class one, because
+ // "struct impl" is forwarded declared in .cc and compiler needs a concrete definition of "struct impl" when
+ // compiling AclManager's destructor. Hence we need to forward declare the destructor for AclManager to delay
+ // compiling AclManager's destructor until it starts linking the .cc file.
+ ~AclManager() override;
+
+ // Should register only once when user module starts.
+ // Generates OnConnectSuccess when an incoming connection is established.
+ virtual void RegisterCallbacks(ConnectionCallbacks* callbacks, os::Handler* handler);
+
+ // Should register only once when user module starts.
+ virtual void RegisterLeCallbacks(LeConnectionCallbacks* callbacks, os::Handler* handler);
+
+ // Should register only once when user module starts.
+ virtual void RegisterAclManagerCallbacks(AclManagerCallbacks* callbacks, os::Handler* handler);
+
+ // Generates OnConnectSuccess if connected, or OnConnectFail otherwise
+ virtual void CreateConnection(Address address);
+
+ // Generates OnLeConnectSuccess if connected, or OnLeConnectFail otherwise
+ virtual void CreateLeConnection(AddressWithType address_with_type);
+
+ // Generates OnConnectFail with error code "terminated by local host 0x16" if cancelled, or OnConnectSuccess if not
+ // successfully cancelled and already connected
+ virtual void CancelConnect(Address address);
+
+ virtual void MasterLinkKey(KeyFlag key_flag);
+ virtual void SwitchRole(Address address, Role role);
+ virtual void ReadDefaultLinkPolicySettings();
+ virtual void WriteDefaultLinkPolicySettings(uint16_t default_link_policy_settings);
+
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override;
+
+ void Start() override;
+
+ void Stop() override;
+
+ std::string ToString() const override;
+
+ private:
+ friend AclConnection;
+
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+
+ struct acl_connection;
+ DISALLOW_COPY_AND_ASSIGN(AclManager);
+};
+
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/acl_manager_mock.h b/gd/hci/acl_manager_mock.h
new file mode 100644
index 0000000..e7a8c6b
--- /dev/null
+++ b/gd/hci/acl_manager_mock.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include "hci/acl_manager.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace hci {
+namespace testing {
+
+class MockAclConnection : public AclConnection {
+ public:
+ MOCK_METHOD(Address, GetAddress, (), (const, override));
+ MOCK_METHOD(AddressType, GetAddressType, (), (const, override));
+ MOCK_METHOD(void, RegisterDisconnectCallback,
+ (common::OnceCallback<void(ErrorCode)> on_disconnect, os::Handler* handler), (override));
+ MOCK_METHOD(bool, Disconnect, (DisconnectReason reason), (override));
+ MOCK_METHOD(void, Finish, (), (override));
+ QueueUpEnd* GetAclQueueEnd() const override {
+ return acl_queue_.GetUpEnd();
+ }
+ mutable common::BidiQueue<PacketView<kLittleEndian>, BasePacketBuilder> acl_queue_{10};
+};
+
+class MockAclManager : public AclManager {
+ public:
+ MOCK_METHOD(void, RegisterCallbacks, (ConnectionCallbacks * callbacks, os::Handler* handler), (override));
+ MOCK_METHOD(void, RegisterLeCallbacks, (LeConnectionCallbacks * callbacks, os::Handler* handler), (override));
+ MOCK_METHOD(void, CreateConnection, (Address address), (override));
+ MOCK_METHOD(void, CreateLeConnection, (AddressWithType address_with_type), (override));
+ MOCK_METHOD(void, CancelConnect, (Address address), (override));
+};
+
+} // namespace testing
+} // namespace hci
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/hci/acl_manager_test.cc b/gd/hci/acl_manager_test.cc
new file mode 100644
index 0000000..8b2cb32
--- /dev/null
+++ b/gd/hci/acl_manager_test.cc
@@ -0,0 +1,1015 @@
+/*
+ * Copyright 2019 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 "hci/acl_manager.h"
+
+#include <algorithm>
+#include <chrono>
+#include <future>
+#include <map>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "common/bind.h"
+#include "hci/address.h"
+#include "hci/controller.h"
+#include "hci/hci_layer.h"
+#include "os/thread.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace hci {
+namespace {
+
+using common::BidiQueue;
+using common::BidiQueueEnd;
+using packet::kLittleEndian;
+using packet::PacketView;
+using packet::RawBuilder;
+
+constexpr std::chrono::seconds kTimeout = std::chrono::seconds(2);
+
+PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+ auto bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter i(*bytes);
+ bytes->reserve(packet->size());
+ packet->Serialize(i);
+ return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+std::unique_ptr<BasePacketBuilder> NextPayload(uint16_t handle) {
+ static uint32_t packet_number = 1;
+ auto payload = std::make_unique<RawBuilder>();
+ payload->AddOctets2(handle);
+ payload->AddOctets4(packet_number++);
+ return std::move(payload);
+}
+
+std::unique_ptr<AclPacketBuilder> NextAclPacket(uint16_t handle) {
+ PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
+ BroadcastFlag broadcast_flag = BroadcastFlag::ACTIVE_SLAVE_BROADCAST;
+ return AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, NextPayload(handle));
+}
+
+class TestController : public Controller {
+ public:
+ void RegisterCompletedAclPacketsCallback(common::Callback<void(uint16_t /* handle */, uint16_t /* packets */)> cb,
+ os::Handler* handler) override {
+ acl_cb_ = cb;
+ acl_cb_handler_ = handler;
+ }
+
+ uint16_t GetControllerAclPacketLength() const override {
+ return acl_buffer_length_;
+ }
+
+ uint16_t GetControllerNumAclPacketBuffers() const override {
+ return total_acl_buffers_;
+ }
+
+ void CompletePackets(uint16_t handle, uint16_t packets) {
+ acl_cb_handler_->Post(common::BindOnce(acl_cb_, handle, packets));
+ }
+
+ uint16_t acl_buffer_length_ = 1024;
+ uint16_t total_acl_buffers_ = 2;
+ common::Callback<void(uint16_t /* handle */, uint16_t /* packets */)> acl_cb_;
+ os::Handler* acl_cb_handler_ = nullptr;
+
+ protected:
+ void Start() override {}
+ void Stop() override {}
+ void ListDependencies(ModuleList* list) override {}
+};
+
+class TestHciLayer : public HciLayer {
+ public:
+ void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+ common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) override {
+ command_queue_.push(std::move(command));
+ not_empty_.notify_all();
+ }
+
+ void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+ common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) override {
+ command_queue_.push(std::move(command));
+ command_complete_callbacks.push_front(std::move(on_complete));
+ not_empty_.notify_all();
+ }
+
+ std::unique_ptr<CommandPacketBuilder> GetLastCommand() {
+ if (command_queue_.size() == 0) {
+ return nullptr;
+ }
+ auto last = std::move(command_queue_.front());
+ command_queue_.pop();
+ return last;
+ }
+
+ ConnectionManagementCommandView GetCommandPacket(OpCode op_code) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ std::chrono::milliseconds time = std::chrono::milliseconds(3000);
+
+ ASSERT(not_empty_.wait_for(lock, time) != std::cv_status::timeout);
+ auto packet_view = GetPacketView(GetLastCommand());
+ CommandPacketView command_packet_view = CommandPacketView::Create(packet_view);
+ ConnectionManagementCommandView command = ConnectionManagementCommandView::Create(command_packet_view);
+ ASSERT(command.IsValid());
+ EXPECT_EQ(command.GetOpCode(), op_code);
+
+ return command;
+ }
+
+ void RegisterEventHandler(EventCode event_code, common::Callback<void(EventPacketView)> event_handler,
+ os::Handler* handler) override {
+ registered_events_[event_code] = event_handler;
+ }
+
+ void UnregisterEventHandler(EventCode event_code) override {
+ registered_events_.erase(event_code);
+ }
+
+ void RegisterLeEventHandler(SubeventCode subevent_code, common::Callback<void(LeMetaEventView)> event_handler,
+ os::Handler* handler) override {
+ registered_le_events_[subevent_code] = event_handler;
+ }
+
+ void UnregisterLeEventHandler(SubeventCode subevent_code) {
+ registered_le_events_.erase(subevent_code);
+ }
+
+ void IncomingEvent(std::unique_ptr<EventPacketBuilder> event_builder) {
+ auto packet = GetPacketView(std::move(event_builder));
+ EventPacketView event = EventPacketView::Create(packet);
+ EXPECT_TRUE(event.IsValid());
+ EventCode event_code = event.GetEventCode();
+ EXPECT_TRUE(registered_events_.find(event_code) != registered_events_.end());
+ registered_events_[event_code].Run(event);
+ }
+
+ void IncomingLeMetaEvent(std::unique_ptr<LeMetaEventBuilder> event_builder) {
+ auto packet = GetPacketView(std::move(event_builder));
+ EventPacketView event = EventPacketView::Create(packet);
+ LeMetaEventView meta_event_view = LeMetaEventView::Create(event);
+ EXPECT_TRUE(meta_event_view.IsValid());
+ SubeventCode subevent_code = meta_event_view.GetSubeventCode();
+ EXPECT_TRUE(registered_le_events_.find(subevent_code) != registered_le_events_.end());
+ registered_le_events_[subevent_code].Run(meta_event_view);
+ }
+
+ void IncomingAclData(uint16_t handle) {
+ os::Handler* hci_handler = GetHandler();
+ auto* queue_end = acl_queue_.GetDownEnd();
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ queue_end->RegisterEnqueue(hci_handler,
+ common::Bind(
+ [](decltype(queue_end) queue_end, uint16_t handle, std::promise<void> promise) {
+ auto packet = GetPacketView(NextAclPacket(handle));
+ AclPacketView acl2 = AclPacketView::Create(packet);
+ queue_end->UnregisterEnqueue();
+ promise.set_value();
+ return std::make_unique<AclPacketView>(acl2);
+ },
+ queue_end, handle, common::Passed(std::move(promise))));
+ auto status = future.wait_for(kTimeout);
+ ASSERT_EQ(status, std::future_status::ready);
+ }
+
+ void AssertNoOutgoingAclData() {
+ auto queue_end = acl_queue_.GetDownEnd();
+ EXPECT_EQ(queue_end->TryDequeue(), nullptr);
+ }
+
+ void CommandCompleteCallback(EventPacketView event) {
+ CommandCompleteView complete_view = CommandCompleteView::Create(event);
+ ASSERT(complete_view.IsValid());
+ std::move(command_complete_callbacks.front()).Run(complete_view);
+ command_complete_callbacks.pop_front();
+ }
+
+ PacketView<kLittleEndian> OutgoingAclData() {
+ auto queue_end = acl_queue_.GetDownEnd();
+ std::unique_ptr<AclPacketBuilder> received;
+ do {
+ received = queue_end->TryDequeue();
+ } while (received == nullptr);
+
+ return GetPacketView(std::move(received));
+ }
+
+ BidiQueueEnd<AclPacketBuilder, AclPacketView>* GetAclQueueEnd() override {
+ return acl_queue_.GetUpEnd();
+ }
+
+ void ListDependencies(ModuleList* list) override {}
+ void Start() override {}
+ void Stop() override {}
+
+ private:
+ std::map<EventCode, common::Callback<void(EventPacketView)>> registered_events_;
+ std::map<SubeventCode, common::Callback<void(LeMetaEventView)>> registered_le_events_;
+ std::list<base::OnceCallback<void(CommandCompleteView)>> command_complete_callbacks;
+ BidiQueue<AclPacketView, AclPacketBuilder> acl_queue_{3 /* TODO: Set queue depth */};
+
+ std::queue<std::unique_ptr<CommandPacketBuilder>> command_queue_;
+ mutable std::mutex mutex_;
+ std::condition_variable not_empty_;
+};
+
+class AclManagerNoCallbacksTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ test_hci_layer_ = new TestHciLayer; // Ownership is transferred to registry
+ test_controller_ = new TestController;
+ fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_);
+ fake_registry_.InjectTestModule(&Controller::Factory, test_controller_);
+ client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory);
+ EXPECT_NE(client_handler_, nullptr);
+ fake_registry_.Start<AclManager>(&thread_);
+ acl_manager_ = static_cast<AclManager*>(fake_registry_.GetModuleUnderTest(&AclManager::Factory));
+ Address::FromString("A1:A2:A3:A4:A5:A6", remote);
+ }
+
+ void TearDown() override {
+ fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20));
+ fake_registry_.StopAll();
+ }
+
+ TestModuleRegistry fake_registry_;
+ TestHciLayer* test_hci_layer_ = nullptr;
+ TestController* test_controller_ = nullptr;
+ os::Thread& thread_ = fake_registry_.GetTestThread();
+ AclManager* acl_manager_ = nullptr;
+ os::Handler* client_handler_ = nullptr;
+ Address remote;
+
+ std::future<void> GetConnectionFuture() {
+ ASSERT_LOG(mock_connection_callback_.connection_promise_ == nullptr, "Promises promises ... Only one at a time");
+ mock_connection_callback_.connection_promise_ = std::make_unique<std::promise<void>>();
+ return mock_connection_callback_.connection_promise_->get_future();
+ }
+
+ std::future<void> GetLeConnectionFuture() {
+ ASSERT_LOG(mock_le_connection_callbacks_.le_connection_promise_ == nullptr,
+ "Promises promises ... Only one at a time");
+ mock_le_connection_callbacks_.le_connection_promise_ = std::make_unique<std::promise<void>>();
+ return mock_le_connection_callbacks_.le_connection_promise_->get_future();
+ }
+
+ std::shared_ptr<AclConnection> GetLastConnection() {
+ return mock_connection_callback_.connections_.back();
+ }
+
+ std::shared_ptr<AclConnection> GetLastLeConnection() {
+ return mock_le_connection_callbacks_.le_connections_.back();
+ }
+
+ void SendAclData(uint16_t handle, std::shared_ptr<AclConnection> connection) {
+ auto queue_end = connection->GetAclQueueEnd();
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ queue_end->RegisterEnqueue(client_handler_,
+ common::Bind(
+ [](decltype(queue_end) queue_end, uint16_t handle, std::promise<void> promise) {
+ queue_end->UnregisterEnqueue();
+ promise.set_value();
+ return NextPayload(handle);
+ },
+ queue_end, handle, common::Passed(std::move(promise))));
+ auto status = future.wait_for(kTimeout);
+ ASSERT_EQ(status, std::future_status::ready);
+ }
+
+ class MockConnectionCallback : public ConnectionCallbacks {
+ public:
+ void OnConnectSuccess(std::unique_ptr<AclConnection> connection) override {
+ // Convert to std::shared_ptr during push_back()
+ connections_.push_back(std::move(connection));
+ if (connection_promise_ != nullptr) {
+ connection_promise_->set_value();
+ connection_promise_.reset();
+ }
+ }
+ MOCK_METHOD(void, OnConnectFail, (Address, ErrorCode reason), (override));
+
+ std::list<std::shared_ptr<AclConnection>> connections_;
+ std::unique_ptr<std::promise<void>> connection_promise_;
+ } mock_connection_callback_;
+
+ class MockLeConnectionCallbacks : public LeConnectionCallbacks {
+ public:
+ void OnLeConnectSuccess(AddressWithType address_with_type, std::unique_ptr<AclConnection> connection) override {
+ le_connections_.push_back(std::move(connection));
+ if (le_connection_promise_ != nullptr) {
+ le_connection_promise_->set_value();
+ le_connection_promise_.reset();
+ }
+ }
+ MOCK_METHOD(void, OnLeConnectFail, (AddressWithType, ErrorCode reason), (override));
+
+ std::list<std::shared_ptr<AclConnection>> le_connections_;
+ std::unique_ptr<std::promise<void>> le_connection_promise_;
+ } mock_le_connection_callbacks_;
+
+ class MockAclManagerCallbacks : public AclManagerCallbacks {
+ public:
+ MOCK_METHOD(void, OnMasterLinkKeyComplete, (uint16_t connection_handle, KeyFlag key_flag), (override));
+ MOCK_METHOD(void, OnRoleChange, (Address bd_addr, Role new_role), (override));
+ MOCK_METHOD(void, OnReadDefaultLinkPolicySettingsComplete, (uint16_t default_link_policy_settings), (override));
+ } mock_acl_manager_callbacks_;
+};
+
+class AclManagerTest : public AclManagerNoCallbacksTest {
+ protected:
+ void SetUp() override {
+ AclManagerNoCallbacksTest::SetUp();
+ acl_manager_->RegisterCallbacks(&mock_connection_callback_, client_handler_);
+ acl_manager_->RegisterLeCallbacks(&mock_le_connection_callbacks_, client_handler_);
+ acl_manager_->RegisterAclManagerCallbacks(&mock_acl_manager_callbacks_, client_handler_);
+ }
+};
+
+class AclManagerWithConnectionTest : public AclManagerTest {
+ protected:
+ void SetUp() override {
+ AclManagerTest::SetUp();
+ test_hci_layer_->RegisterEventHandler(
+ EventCode::COMMAND_COMPLETE,
+ base::Bind(&TestHciLayer::CommandCompleteCallback, common::Unretained(test_hci_layer_)), nullptr);
+
+ handle_ = 0x123;
+ acl_manager_->CreateConnection(remote);
+
+ // Wait for the connection request
+ std::unique_ptr<CommandPacketBuilder> last_command;
+ do {
+ last_command = test_hci_layer_->GetLastCommand();
+ } while (last_command == nullptr);
+
+ auto first_connection = GetConnectionFuture();
+ test_hci_layer_->IncomingEvent(
+ ConnectionCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, remote, LinkType::ACL, Enable::DISABLED));
+
+ auto first_connection_status = first_connection.wait_for(kTimeout);
+ ASSERT_EQ(first_connection_status, std::future_status::ready);
+
+ connection_ = GetLastConnection();
+ connection_->RegisterCallbacks(&mock_connection_management_callbacks_, client_handler_);
+ }
+
+ uint16_t handle_;
+ std::shared_ptr<AclConnection> connection_;
+
+ class MockConnectionManagementCallbacks : public ConnectionManagementCallbacks {
+ public:
+ MOCK_METHOD1(OnConnectionPacketTypeChanged, void(uint16_t packet_type));
+ MOCK_METHOD0(OnAuthenticationComplete, void());
+ MOCK_METHOD1(OnEncryptionChange, void(EncryptionEnabled enabled));
+ MOCK_METHOD0(OnChangeConnectionLinkKeyComplete, void());
+ MOCK_METHOD1(OnReadClockOffsetComplete, void(uint16_t clock_offse));
+ MOCK_METHOD2(OnModeChange, void(Mode current_mode, uint16_t interval));
+ MOCK_METHOD5(OnQosSetupComplete, void(ServiceType service_type, uint32_t token_rate, uint32_t peak_bandwidth,
+ uint32_t latency, uint32_t delay_variation));
+ MOCK_METHOD6(OnFlowSpecificationComplete,
+ void(FlowDirection flow_direction, ServiceType service_type, uint32_t token_rate,
+ uint32_t token_bucket_size, uint32_t peak_bandwidth, uint32_t access_latency));
+ MOCK_METHOD0(OnFlushOccurred, void());
+ MOCK_METHOD1(OnRoleDiscoveryComplete, void(Role current_role));
+ MOCK_METHOD1(OnReadLinkPolicySettingsComplete, void(uint16_t link_policy_settings));
+ MOCK_METHOD1(OnReadAutomaticFlushTimeoutComplete, void(uint16_t flush_timeout));
+ MOCK_METHOD1(OnReadTransmitPowerLevelComplete, void(uint8_t transmit_power_level));
+ MOCK_METHOD1(OnReadLinkSupervisionTimeoutComplete, void(uint16_t link_supervision_timeout));
+ MOCK_METHOD1(OnReadFailedContactCounterComplete, void(uint16_t failed_contact_counter));
+ MOCK_METHOD1(OnReadLinkQualityComplete, void(uint8_t link_quality));
+ MOCK_METHOD2(OnReadAfhChannelMapComplete, void(AfhMode afh_mode, std::array<uint8_t, 10> afh_channel_map));
+ MOCK_METHOD1(OnReadRssiComplete, void(uint8_t rssi));
+ MOCK_METHOD2(OnReadClockComplete, void(uint32_t clock, uint16_t accuracy));
+ } mock_connection_management_callbacks_;
+};
+
+TEST_F(AclManagerTest, startup_teardown) {}
+
+TEST_F(AclManagerNoCallbacksTest, acl_connection_before_registered_callbacks) {
+ ClassOfDevice class_of_device;
+
+ test_hci_layer_->IncomingEvent(
+ ConnectionRequestBuilder::Create(remote, class_of_device, ConnectionRequestLinkType::ACL));
+ fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
+ fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20));
+ fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
+ auto last_command = test_hci_layer_->GetLastCommand();
+ auto packet = GetPacketView(std::move(last_command));
+ CommandPacketView command = CommandPacketView::Create(packet);
+ EXPECT_TRUE(command.IsValid());
+ OpCode op_code = command.GetOpCode();
+ EXPECT_EQ(op_code, OpCode::REJECT_CONNECTION_REQUEST);
+}
+
+TEST_F(AclManagerTest, invoke_registered_callback_connection_complete_success) {
+ uint16_t handle = 1;
+
+ acl_manager_->CreateConnection(remote);
+
+ // Wait for the connection request
+ std::unique_ptr<CommandPacketBuilder> last_command;
+ do {
+ last_command = test_hci_layer_->GetLastCommand();
+ } while (last_command == nullptr);
+
+ auto first_connection = GetConnectionFuture();
+
+ test_hci_layer_->IncomingEvent(
+ ConnectionCompleteBuilder::Create(ErrorCode::SUCCESS, handle, remote, LinkType::ACL, Enable::DISABLED));
+
+ auto first_connection_status = first_connection.wait_for(kTimeout);
+ ASSERT_EQ(first_connection_status, std::future_status::ready);
+
+ std::shared_ptr<AclConnection> connection = GetLastConnection();
+ ASSERT_EQ(connection->GetAddress(), remote);
+}
+
+TEST_F(AclManagerTest, invoke_registered_callback_connection_complete_fail) {
+ uint16_t handle = 0x123;
+
+ acl_manager_->CreateConnection(remote);
+
+ // Wait for the connection request
+ std::unique_ptr<CommandPacketBuilder> last_command;
+ do {
+ last_command = test_hci_layer_->GetLastCommand();
+ } while (last_command == nullptr);
+
+ EXPECT_CALL(mock_connection_callback_, OnConnectFail(remote, ErrorCode::PAGE_TIMEOUT));
+ test_hci_layer_->IncomingEvent(
+ ConnectionCompleteBuilder::Create(ErrorCode::PAGE_TIMEOUT, handle, remote, LinkType::ACL, Enable::DISABLED));
+ fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
+ fake_registry_.SynchronizeModuleHandler(&AclManager::Factory, std::chrono::milliseconds(20));
+ fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
+}
+
+TEST_F(AclManagerTest, invoke_registered_callback_le_connection_complete_success) {
+ AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
+ acl_manager_->CreateLeConnection(remote_with_type);
+
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_CREATE_CONNECTION);
+ auto le_connection_management_command_view = LeConnectionManagementCommandView::Create(packet);
+ auto command_view = LeCreateConnectionView::Create(le_connection_management_command_view);
+ ASSERT(command_view.IsValid());
+ EXPECT_EQ(command_view.GetPeerAddress(), remote);
+ EXPECT_EQ(command_view.GetPeerAddressType(), AddressType::PUBLIC_DEVICE_ADDRESS);
+
+ auto first_connection = GetLeConnectionFuture();
+
+ test_hci_layer_->IncomingLeMetaEvent(
+ LeConnectionCompleteBuilder::Create(ErrorCode::SUCCESS, 0x123, Role::SLAVE, AddressType::PUBLIC_DEVICE_ADDRESS,
+ remote, 0x0100, 0x0010, 0x0011, MasterClockAccuracy::PPM_30));
+
+ auto first_connection_status = first_connection.wait_for(kTimeout);
+ ASSERT_EQ(first_connection_status, std::future_status::ready);
+
+ std::shared_ptr<AclConnection> connection = GetLastLeConnection();
+ ASSERT_EQ(connection->GetAddress(), remote);
+}
+
+TEST_F(AclManagerTest, invoke_registered_callback_le_connection_complete_fail) {
+ AddressWithType remote_with_type(remote, AddressType::PUBLIC_DEVICE_ADDRESS);
+ acl_manager_->CreateLeConnection(remote_with_type);
+
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_CREATE_CONNECTION);
+ auto le_connection_management_command_view = LeConnectionManagementCommandView::Create(packet);
+ auto command_view = LeCreateConnectionView::Create(le_connection_management_command_view);
+ ASSERT(command_view.IsValid());
+ EXPECT_EQ(command_view.GetPeerAddress(), remote);
+ EXPECT_EQ(command_view.GetPeerAddressType(), AddressType::PUBLIC_DEVICE_ADDRESS);
+
+ EXPECT_CALL(mock_le_connection_callbacks_,
+ OnLeConnectFail(remote_with_type, ErrorCode::CONNECTION_REJECTED_LIMITED_RESOURCES));
+ test_hci_layer_->IncomingLeMetaEvent(LeConnectionCompleteBuilder::Create(
+ ErrorCode::CONNECTION_REJECTED_LIMITED_RESOURCES, 0x123, Role::SLAVE, AddressType::PUBLIC_DEVICE_ADDRESS, remote,
+ 0x0100, 0x0010, 0x0011, MasterClockAccuracy::PPM_30));
+}
+
+TEST_F(AclManagerTest, invoke_registered_callback_disconnection_complete) {
+ uint16_t handle = 0x123;
+
+ acl_manager_->CreateConnection(remote);
+
+ // Wait for the connection request
+ std::unique_ptr<CommandPacketBuilder> last_command;
+ do {
+ last_command = test_hci_layer_->GetLastCommand();
+ } while (last_command == nullptr);
+
+ auto first_connection = GetConnectionFuture();
+
+ test_hci_layer_->IncomingEvent(
+ ConnectionCompleteBuilder::Create(ErrorCode::SUCCESS, handle, remote, LinkType::ACL, Enable::DISABLED));
+
+ auto first_connection_status = first_connection.wait_for(kTimeout);
+ ASSERT_EQ(first_connection_status, std::future_status::ready);
+
+ std::shared_ptr<AclConnection> connection = GetLastConnection();
+
+ // Register the disconnect handler
+ std::promise<ErrorCode> promise;
+ auto future = promise.get_future();
+ connection->RegisterDisconnectCallback(
+ common::BindOnce([](std::promise<ErrorCode> promise, ErrorCode reason) { promise.set_value(reason); },
+ std::move(promise)),
+ client_handler_);
+
+ test_hci_layer_->IncomingEvent(
+ DisconnectionCompleteBuilder::Create(ErrorCode::SUCCESS, handle, ErrorCode::REMOTE_USER_TERMINATED_CONNECTION));
+
+ auto disconnection_status = future.wait_for(kTimeout);
+ ASSERT_EQ(disconnection_status, std::future_status::ready);
+ ASSERT_EQ(ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, future.get());
+
+ fake_registry_.SynchronizeModuleHandler(&HciLayer::Factory, std::chrono::milliseconds(20));
+}
+
+TEST_F(AclManagerTest, acl_connection_finish_after_disconnected) {
+ uint16_t handle = 0x123;
+
+ acl_manager_->CreateConnection(remote);
+
+ // Wait for the connection request
+ std::unique_ptr<CommandPacketBuilder> last_command;
+ do {
+ last_command = test_hci_layer_->GetLastCommand();
+ } while (last_command == nullptr);
+
+ auto first_connection = GetConnectionFuture();
+
+ test_hci_layer_->IncomingEvent(
+ ConnectionCompleteBuilder::Create(ErrorCode::SUCCESS, handle, remote, LinkType::ACL, Enable::DISABLED));
+
+ auto first_connection_status = first_connection.wait_for(kTimeout);
+ ASSERT_EQ(first_connection_status, std::future_status::ready);
+
+ std::shared_ptr<AclConnection> connection = GetLastConnection();
+
+ // Register the disconnect handler
+ std::promise<ErrorCode> promise;
+ auto future = promise.get_future();
+ connection->RegisterDisconnectCallback(
+ common::BindOnce([](std::promise<ErrorCode> promise, ErrorCode reason) { promise.set_value(reason); },
+ std::move(promise)),
+ client_handler_);
+
+ test_hci_layer_->IncomingEvent(DisconnectionCompleteBuilder::Create(
+ ErrorCode::SUCCESS, handle, ErrorCode::REMOTE_DEVICE_TERMINATED_CONNECTION_POWER_OFF));
+
+ auto disconnection_status = future.wait_for(kTimeout);
+ ASSERT_EQ(disconnection_status, std::future_status::ready);
+ ASSERT_EQ(ErrorCode::REMOTE_DEVICE_TERMINATED_CONNECTION_POWER_OFF, future.get());
+
+ connection->Finish();
+}
+
+TEST_F(AclManagerTest, acl_send_data_one_connection) {
+ uint16_t handle = 0x123;
+
+ acl_manager_->CreateConnection(remote);
+
+ // Wait for the connection request
+ std::unique_ptr<CommandPacketBuilder> last_command;
+ do {
+ last_command = test_hci_layer_->GetLastCommand();
+ } while (last_command == nullptr);
+
+ auto first_connection = GetConnectionFuture();
+
+ test_hci_layer_->IncomingEvent(
+ ConnectionCompleteBuilder::Create(ErrorCode::SUCCESS, handle, remote, LinkType::ACL, Enable::DISABLED));
+
+ auto first_connection_status = first_connection.wait_for(kTimeout);
+ ASSERT_EQ(first_connection_status, std::future_status::ready);
+
+ std::shared_ptr<AclConnection> connection = GetLastConnection();
+
+ // Register the disconnect handler
+ connection->RegisterDisconnectCallback(
+ common::Bind([](std::shared_ptr<AclConnection> conn, ErrorCode) { conn->Finish(); }, connection),
+ client_handler_);
+
+ // Send a packet from HCI
+ test_hci_layer_->IncomingAclData(handle);
+ auto queue_end = connection->GetAclQueueEnd();
+
+ std::unique_ptr<PacketView<kLittleEndian>> received;
+ do {
+ received = queue_end->TryDequeue();
+ } while (received == nullptr);
+
+ PacketView<kLittleEndian> received_packet = *received;
+
+ // Send a packet from the connection
+ SendAclData(handle, connection);
+
+ auto sent_packet = test_hci_layer_->OutgoingAclData();
+
+ // Send another packet from the connection
+ SendAclData(handle, connection);
+
+ sent_packet = test_hci_layer_->OutgoingAclData();
+ connection->Disconnect(DisconnectReason::AUTHENTICATION_FAILURE);
+}
+
+TEST_F(AclManagerTest, acl_send_data_credits) {
+ uint16_t handle = 0x123;
+
+ acl_manager_->CreateConnection(remote);
+
+ // Wait for the connection request
+ std::unique_ptr<CommandPacketBuilder> last_command;
+ do {
+ last_command = test_hci_layer_->GetLastCommand();
+ } while (last_command == nullptr);
+
+ auto first_connection = GetConnectionFuture();
+ test_hci_layer_->IncomingEvent(
+ ConnectionCompleteBuilder::Create(ErrorCode::SUCCESS, handle, remote, LinkType::ACL, Enable::DISABLED));
+
+ auto first_connection_status = first_connection.wait_for(kTimeout);
+ ASSERT_EQ(first_connection_status, std::future_status::ready);
+
+ std::shared_ptr<AclConnection> connection = GetLastConnection();
+
+ // Register the disconnect handler
+ connection->RegisterDisconnectCallback(
+ common::BindOnce([](std::shared_ptr<AclConnection> conn, ErrorCode) { conn->Finish(); }, connection),
+ client_handler_);
+
+ // Use all the credits
+ for (uint16_t credits = 0; credits < test_controller_->total_acl_buffers_; credits++) {
+ // Send a packet from the connection
+ SendAclData(handle, connection);
+
+ auto sent_packet = test_hci_layer_->OutgoingAclData();
+ }
+
+ // Send another packet from the connection
+ SendAclData(handle, connection);
+
+ test_hci_layer_->AssertNoOutgoingAclData();
+
+ test_controller_->CompletePackets(handle, 1);
+
+ auto after_credits_sent_packet = test_hci_layer_->OutgoingAclData();
+
+ connection->Disconnect(DisconnectReason::AUTHENTICATION_FAILURE);
+}
+
+TEST_F(AclManagerWithConnectionTest, send_switch_role) {
+ acl_manager_->SwitchRole(connection_->GetAddress(), Role::SLAVE);
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::SWITCH_ROLE);
+ auto command_view = SwitchRoleView::Create(packet);
+ ASSERT(command_view.IsValid());
+ EXPECT_EQ(command_view.GetBdAddr(), connection_->GetAddress());
+ EXPECT_EQ(command_view.GetRole(), Role::SLAVE);
+
+ EXPECT_CALL(mock_acl_manager_callbacks_, OnRoleChange(connection_->GetAddress(), Role::SLAVE));
+ test_hci_layer_->IncomingEvent(RoleChangeBuilder::Create(ErrorCode::SUCCESS, connection_->GetAddress(), Role::SLAVE));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_default_link_policy_settings) {
+ acl_manager_->ReadDefaultLinkPolicySettings();
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_DEFAULT_LINK_POLICY_SETTINGS);
+ auto command_view = ReadDefaultLinkPolicySettingsView::Create(packet);
+ ASSERT(command_view.IsValid());
+
+ EXPECT_CALL(mock_acl_manager_callbacks_, OnReadDefaultLinkPolicySettingsComplete(0x07));
+ uint8_t num_packets = 1;
+ test_hci_layer_->IncomingEvent(
+ ReadDefaultLinkPolicySettingsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, 0x07));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_write_default_link_policy_settings) {
+ acl_manager_->WriteDefaultLinkPolicySettings(0x05);
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::WRITE_DEFAULT_LINK_POLICY_SETTINGS);
+ auto command_view = WriteDefaultLinkPolicySettingsView::Create(packet);
+ ASSERT(command_view.IsValid());
+ EXPECT_EQ(command_view.GetDefaultLinkPolicySettings(), 0x05);
+
+ uint8_t num_packets = 1;
+ test_hci_layer_->IncomingEvent(
+ WriteDefaultLinkPolicySettingsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_change_connection_packet_type) {
+ connection_->ChangeConnectionPacketType(0xEE1C);
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::CHANGE_CONNECTION_PACKET_TYPE);
+ auto command_view = ChangeConnectionPacketTypeView::Create(packet);
+ ASSERT(command_view.IsValid());
+ EXPECT_EQ(command_view.GetPacketType(), 0xEE1C);
+
+ EXPECT_CALL(mock_connection_management_callbacks_, OnConnectionPacketTypeChanged(0xEE1C));
+ test_hci_layer_->IncomingEvent(ConnectionPacketTypeChangedBuilder::Create(ErrorCode::SUCCESS, handle_, 0xEE1C));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_authentication_requested) {
+ connection_->AuthenticationRequested();
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::AUTHENTICATION_REQUESTED);
+ auto command_view = AuthenticationRequestedView::Create(packet);
+ ASSERT(command_view.IsValid());
+
+ EXPECT_CALL(mock_connection_management_callbacks_, OnAuthenticationComplete);
+ test_hci_layer_->IncomingEvent(AuthenticationCompleteBuilder::Create(ErrorCode::SUCCESS, handle_));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_clock_offset) {
+ connection_->ReadClockOffset();
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_CLOCK_OFFSET);
+ auto command_view = ReadClockOffsetView::Create(packet);
+ ASSERT(command_view.IsValid());
+
+ EXPECT_CALL(mock_connection_management_callbacks_, OnReadClockOffsetComplete(0x0123));
+ test_hci_layer_->IncomingEvent(ReadClockOffsetCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, 0x0123));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_hold_mode) {
+ connection_->HoldMode(0x0500, 0x0020);
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::HOLD_MODE);
+ auto command_view = HoldModeView::Create(packet);
+ ASSERT(command_view.IsValid());
+ EXPECT_EQ(command_view.GetHoldModeMaxInterval(), 0x0500);
+ EXPECT_EQ(command_view.GetHoldModeMinInterval(), 0x0020);
+
+ EXPECT_CALL(mock_connection_management_callbacks_, OnModeChange(Mode::HOLD, 0x0020));
+ test_hci_layer_->IncomingEvent(ModeChangeBuilder::Create(ErrorCode::SUCCESS, handle_, Mode::HOLD, 0x0020));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_sniff_mode) {
+ connection_->SniffMode(0x0500, 0x0020, 0x0040, 0x0014);
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::SNIFF_MODE);
+ auto command_view = SniffModeView::Create(packet);
+ ASSERT(command_view.IsValid());
+ EXPECT_EQ(command_view.GetSniffMaxInterval(), 0x0500);
+ EXPECT_EQ(command_view.GetSniffMinInterval(), 0x0020);
+ EXPECT_EQ(command_view.GetSniffAttempt(), 0x0040);
+ EXPECT_EQ(command_view.GetSniffTimeout(), 0x0014);
+
+ EXPECT_CALL(mock_connection_management_callbacks_, OnModeChange(Mode::SNIFF, 0x0028));
+ test_hci_layer_->IncomingEvent(ModeChangeBuilder::Create(ErrorCode::SUCCESS, handle_, Mode::SNIFF, 0x0028));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_exit_sniff_mode) {
+ connection_->ExitSniffMode();
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::EXIT_SNIFF_MODE);
+ auto command_view = ExitSniffModeView::Create(packet);
+ ASSERT(command_view.IsValid());
+
+ EXPECT_CALL(mock_connection_management_callbacks_, OnModeChange(Mode::ACTIVE, 0x00));
+ test_hci_layer_->IncomingEvent(ModeChangeBuilder::Create(ErrorCode::SUCCESS, handle_, Mode::ACTIVE, 0x00));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_qos_setup) {
+ connection_->QosSetup(ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231);
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::QOS_SETUP);
+ auto command_view = QosSetupView::Create(packet);
+ ASSERT(command_view.IsValid());
+ EXPECT_EQ(command_view.GetServiceType(), ServiceType::BEST_EFFORT);
+ EXPECT_EQ(command_view.GetTokenRate(), 0x1234);
+ EXPECT_EQ(command_view.GetPeakBandwidth(), 0x1233);
+ EXPECT_EQ(command_view.GetLatency(), 0x1232);
+ EXPECT_EQ(command_view.GetDelayVariation(), 0x1231);
+
+ EXPECT_CALL(mock_connection_management_callbacks_,
+ OnQosSetupComplete(ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231));
+ test_hci_layer_->IncomingEvent(QosSetupCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, ServiceType::BEST_EFFORT,
+ 0x1234, 0x1233, 0x1232, 0x1231));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_flow_specification) {
+ connection_->FlowSpecification(FlowDirection::OUTGOING_FLOW, ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232,
+ 0x1231);
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::FLOW_SPECIFICATION);
+ auto command_view = FlowSpecificationView::Create(packet);
+ ASSERT(command_view.IsValid());
+ EXPECT_EQ(command_view.GetFlowDirection(), FlowDirection::OUTGOING_FLOW);
+ EXPECT_EQ(command_view.GetServiceType(), ServiceType::BEST_EFFORT);
+ EXPECT_EQ(command_view.GetTokenRate(), 0x1234);
+ EXPECT_EQ(command_view.GetTokenBucketSize(), 0x1233);
+ EXPECT_EQ(command_view.GetPeakBandwidth(), 0x1232);
+ EXPECT_EQ(command_view.GetAccessLatency(), 0x1231);
+
+ EXPECT_CALL(mock_connection_management_callbacks_,
+ OnFlowSpecificationComplete(FlowDirection::OUTGOING_FLOW, ServiceType::BEST_EFFORT, 0x1234, 0x1233,
+ 0x1232, 0x1231));
+ test_hci_layer_->IncomingEvent(
+ FlowSpecificationCompleteBuilder::Create(ErrorCode::SUCCESS, handle_, FlowDirection::OUTGOING_FLOW,
+ ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_flush) {
+ connection_->Flush();
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::FLUSH);
+ auto command_view = FlushView::Create(packet);
+ ASSERT(command_view.IsValid());
+
+ EXPECT_CALL(mock_connection_management_callbacks_, OnFlushOccurred());
+ test_hci_layer_->IncomingEvent(FlushOccurredBuilder::Create(handle_));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_role_discovery) {
+ connection_->RoleDiscovery();
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::ROLE_DISCOVERY);
+ auto command_view = RoleDiscoveryView::Create(packet);
+ ASSERT(command_view.IsValid());
+
+ EXPECT_CALL(mock_connection_management_callbacks_, OnRoleDiscoveryComplete(Role::MASTER));
+ uint8_t num_packets = 1;
+ test_hci_layer_->IncomingEvent(
+ RoleDiscoveryCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, Role::MASTER));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_link_policy_settings) {
+ connection_->ReadLinkPolicySettings();
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_LINK_POLICY_SETTINGS);
+ auto command_view = ReadLinkPolicySettingsView::Create(packet);
+ ASSERT(command_view.IsValid());
+
+ EXPECT_CALL(mock_connection_management_callbacks_, OnReadLinkPolicySettingsComplete(0x07));
+ uint8_t num_packets = 1;
+ test_hci_layer_->IncomingEvent(
+ ReadLinkPolicySettingsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x07));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_write_link_policy_settings) {
+ connection_->WriteLinkPolicySettings(0x05);
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::WRITE_LINK_POLICY_SETTINGS);
+ auto command_view = WriteLinkPolicySettingsView::Create(packet);
+ ASSERT(command_view.IsValid());
+ EXPECT_EQ(command_view.GetLinkPolicySettings(), 0x05);
+
+ uint8_t num_packets = 1;
+ test_hci_layer_->IncomingEvent(
+ WriteLinkPolicySettingsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_sniff_subrating) {
+ connection_->SniffSubrating(0x1234, 0x1235, 0x1236);
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::SNIFF_SUBRATING);
+ auto command_view = SniffSubratingView::Create(packet);
+ ASSERT(command_view.IsValid());
+ EXPECT_EQ(command_view.GetMaximumLatency(), 0x1234);
+ EXPECT_EQ(command_view.GetMinimumRemoteTimeout(), 0x1235);
+ EXPECT_EQ(command_view.GetMinimumLocalTimeout(), 0x1236);
+
+ uint8_t num_packets = 1;
+ test_hci_layer_->IncomingEvent(SniffSubratingCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_automatic_flush_timeout) {
+ connection_->ReadAutomaticFlushTimeout();
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_AUTOMATIC_FLUSH_TIMEOUT);
+ auto command_view = ReadAutomaticFlushTimeoutView::Create(packet);
+ ASSERT(command_view.IsValid());
+
+ EXPECT_CALL(mock_connection_management_callbacks_, OnReadAutomaticFlushTimeoutComplete(0x07ff));
+ uint8_t num_packets = 1;
+ test_hci_layer_->IncomingEvent(
+ ReadAutomaticFlushTimeoutCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x07ff));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_write_automatic_flush_timeout) {
+ connection_->WriteAutomaticFlushTimeout(0x07FF);
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::WRITE_AUTOMATIC_FLUSH_TIMEOUT);
+ auto command_view = WriteAutomaticFlushTimeoutView::Create(packet);
+ ASSERT(command_view.IsValid());
+ EXPECT_EQ(command_view.GetFlushTimeout(), 0x07FF);
+
+ uint8_t num_packets = 1;
+ test_hci_layer_->IncomingEvent(
+ WriteAutomaticFlushTimeoutCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_transmit_power_level) {
+ connection_->ReadTransmitPowerLevel(TransmitPowerLevelType::CURRENT);
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_TRANSMIT_POWER_LEVEL);
+ auto command_view = ReadTransmitPowerLevelView::Create(packet);
+ ASSERT(command_view.IsValid());
+ EXPECT_EQ(command_view.GetType(), TransmitPowerLevelType::CURRENT);
+
+ EXPECT_CALL(mock_connection_management_callbacks_, OnReadTransmitPowerLevelComplete(0x07));
+ uint8_t num_packets = 1;
+ test_hci_layer_->IncomingEvent(
+ ReadTransmitPowerLevelCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x07));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_link_supervision_timeout) {
+ connection_->ReadLinkSupervisionTimeout();
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_LINK_SUPERVISION_TIMEOUT);
+ auto command_view = ReadLinkSupervisionTimeoutView::Create(packet);
+ ASSERT(command_view.IsValid());
+
+ EXPECT_CALL(mock_connection_management_callbacks_, OnReadLinkSupervisionTimeoutComplete(0x5677));
+ uint8_t num_packets = 1;
+ test_hci_layer_->IncomingEvent(
+ ReadLinkSupervisionTimeoutCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x5677));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_write_link_supervision_timeout) {
+ connection_->WriteLinkSupervisionTimeout(0x5678);
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::WRITE_LINK_SUPERVISION_TIMEOUT);
+ auto command_view = WriteLinkSupervisionTimeoutView::Create(packet);
+ ASSERT(command_view.IsValid());
+ EXPECT_EQ(command_view.GetLinkSupervisionTimeout(), 0x5678);
+
+ uint8_t num_packets = 1;
+ test_hci_layer_->IncomingEvent(
+ WriteLinkSupervisionTimeoutCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_failed_contact_counter) {
+ connection_->ReadFailedContactCounter();
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_FAILED_CONTACT_COUNTER);
+ auto command_view = ReadFailedContactCounterView::Create(packet);
+ ASSERT(command_view.IsValid());
+
+ EXPECT_CALL(mock_connection_management_callbacks_, OnReadFailedContactCounterComplete(0x00));
+ uint8_t num_packets = 1;
+ test_hci_layer_->IncomingEvent(
+ ReadFailedContactCounterCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x00));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_reset_failed_contact_counter) {
+ connection_->ResetFailedContactCounter();
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::RESET_FAILED_CONTACT_COUNTER);
+ auto command_view = ResetFailedContactCounterView::Create(packet);
+ ASSERT(command_view.IsValid());
+
+ uint8_t num_packets = 1;
+ test_hci_layer_->IncomingEvent(
+ ResetFailedContactCounterCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_link_quality) {
+ connection_->ReadLinkQuality();
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_LINK_QUALITY);
+ auto command_view = ReadLinkQualityView::Create(packet);
+ ASSERT(command_view.IsValid());
+
+ EXPECT_CALL(mock_connection_management_callbacks_, OnReadLinkQualityComplete(0xa9));
+ uint8_t num_packets = 1;
+ test_hci_layer_->IncomingEvent(
+ ReadLinkQualityCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0xa9));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_afh_channel_map) {
+ connection_->ReadAfhChannelMap();
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_AFH_CHANNEL_MAP);
+ auto command_view = ReadAfhChannelMapView::Create(packet);
+ ASSERT(command_view.IsValid());
+ std::array<uint8_t, 10> afh_channel_map = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09};
+
+ EXPECT_CALL(mock_connection_management_callbacks_,
+ OnReadAfhChannelMapComplete(AfhMode::AFH_ENABLED, afh_channel_map));
+ uint8_t num_packets = 1;
+ test_hci_layer_->IncomingEvent(ReadAfhChannelMapCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_,
+ AfhMode::AFH_ENABLED, afh_channel_map));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_rssi) {
+ connection_->ReadRssi();
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_RSSI);
+ auto command_view = ReadRssiView::Create(packet);
+ ASSERT(command_view.IsValid());
+
+ EXPECT_CALL(mock_connection_management_callbacks_, OnReadRssiComplete(0x00));
+ uint8_t num_packets = 1;
+ test_hci_layer_->IncomingEvent(ReadRssiCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x00));
+}
+
+TEST_F(AclManagerWithConnectionTest, send_read_clock) {
+ connection_->ReadClock(WhichClock::LOCAL);
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::READ_CLOCK);
+ auto command_view = ReadClockView::Create(packet);
+ ASSERT(command_view.IsValid());
+ EXPECT_EQ(command_view.GetWhichClock(), WhichClock::LOCAL);
+
+ EXPECT_CALL(mock_connection_management_callbacks_, OnReadClockComplete(0x00002e6a, 0x0000));
+ uint8_t num_packets = 1;
+ test_hci_layer_->IncomingEvent(
+ ReadClockCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, handle_, 0x00002e6a, 0x0000));
+}
+
+} // namespace
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/address.cc b/gd/hci/address.cc
new file mode 100644
index 0000000..db0695d
--- /dev/null
+++ b/gd/hci/address.cc
@@ -0,0 +1,92 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "hci/address.h"
+
+#include <stdint.h>
+#include <algorithm>
+#include <sstream>
+#include <vector>
+
+namespace bluetooth {
+namespace hci {
+
+static_assert(sizeof(Address) == 6, "Address must be 6 bytes long!");
+
+const Address Address::kAny{{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};
+const Address Address::kEmpty{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
+
+Address::Address(const uint8_t (&addr)[6]) {
+ std::copy(addr, addr + kLength, address);
+};
+
+std::string Address::ToString() const {
+ char buffer[] = "00:00:00:00:00:00";
+ std::snprintf(&buffer[0], sizeof(buffer), "%02x:%02x:%02x:%02x:%02x:%02x", address[5], address[4], address[3],
+ address[2], address[1], address[0]);
+ std::string str(buffer);
+ return str;
+}
+
+bool Address::FromString(const std::string& from, Address& to) {
+ Address new_addr;
+ if (from.length() != 17) {
+ return false;
+ }
+
+ std::istringstream stream(from);
+ std::string token;
+ int index = 0;
+ while (getline(stream, token, ':')) {
+ if (index >= 6) {
+ return false;
+ }
+
+ if (token.length() != 2) {
+ return false;
+ }
+
+ char* temp = nullptr;
+ new_addr.address[5 - index] = strtol(token.c_str(), &temp, 16);
+ if (*temp != '\0') {
+ return false;
+ }
+
+ index++;
+ }
+
+ if (index != 6) {
+ return false;
+ }
+
+ to = new_addr;
+ return true;
+}
+
+size_t Address::FromOctets(const uint8_t* from) {
+ std::copy(from, from + kLength, address);
+ return kLength;
+};
+
+bool Address::IsValidAddress(const std::string& address) {
+ Address tmp;
+ return Address::FromString(address, tmp);
+}
+
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/address.h b/gd/hci/address.h
new file mode 100644
index 0000000..3bc507f
--- /dev/null
+++ b/gd/hci/address.h
@@ -0,0 +1,94 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <cstring>
+#include <string>
+
+namespace bluetooth {
+namespace hci {
+
+class Address final {
+ public:
+ static constexpr unsigned int kLength = 6;
+
+ uint8_t address[kLength];
+
+ Address() = default;
+ Address(const uint8_t (&addr)[6]);
+
+ bool operator<(const Address& rhs) const {
+ return (std::memcmp(address, rhs.address, sizeof(address)) < 0);
+ }
+ bool operator==(const Address& rhs) const {
+ return (std::memcmp(address, rhs.address, sizeof(address)) == 0);
+ }
+ bool operator>(const Address& rhs) const {
+ return (rhs < *this);
+ }
+ bool operator<=(const Address& rhs) const {
+ return !(*this > rhs);
+ }
+ bool operator>=(const Address& rhs) const {
+ return !(*this < rhs);
+ }
+ bool operator!=(const Address& rhs) const {
+ return !(*this == rhs);
+ }
+
+ bool IsEmpty() const {
+ return *this == kEmpty;
+ }
+
+ std::string ToString() const;
+
+ // Converts |string| to Address and places it in |to|. If |from| does
+ // not represent a Bluetooth address, |to| is not modified and this function
+ // returns false. Otherwise, it returns true.
+ static bool FromString(const std::string& from, Address& to);
+
+ // Copies |from| raw Bluetooth address octets to the local object.
+ // Returns the number of copied octets - should be always Address::kLength
+ size_t FromOctets(const uint8_t* from);
+
+ static bool IsValidAddress(const std::string& address);
+
+ static const Address kEmpty; // 00:00:00:00:00:00
+ static const Address kAny; // FF:FF:FF:FF:FF:FF
+};
+
+inline std::ostream& operator<<(std::ostream& os, const Address& a) {
+ os << a.ToString();
+ return os;
+}
+
+} // namespace hci
+} // namespace bluetooth
+
+namespace std {
+template <>
+struct hash<bluetooth::hci::Address> {
+ std::size_t operator()(const bluetooth::hci::Address& val) const {
+ static_assert(sizeof(uint64_t) >= bluetooth::hci::Address::kLength);
+ uint64_t int_addr = 0;
+ memcpy(reinterpret_cast<uint8_t*>(&int_addr), val.address, bluetooth::hci::Address::kLength);
+ return std::hash<uint64_t>{}(int_addr);
+ }
+};
+} // namespace std
\ No newline at end of file
diff --git a/gd/hci/address_unittest.cc b/gd/hci/address_unittest.cc
new file mode 100644
index 0000000..17ecd3a
--- /dev/null
+++ b/gd/hci/address_unittest.cc
@@ -0,0 +1,232 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 <unordered_map>
+
+#include <gtest/gtest.h>
+
+#include "hci/address.h"
+
+using bluetooth::hci::Address;
+
+static const char* test_addr = "bc:9a:78:56:34:12";
+static const char* test_addr2 = "21:43:65:87:a9:cb";
+
+TEST(AddressUnittest, test_constructor_array) {
+ Address bdaddr({0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc});
+
+ ASSERT_EQ(0x12, bdaddr.address[0]);
+ ASSERT_EQ(0x34, bdaddr.address[1]);
+ ASSERT_EQ(0x56, bdaddr.address[2]);
+ ASSERT_EQ(0x78, bdaddr.address[3]);
+ ASSERT_EQ(0x9A, bdaddr.address[4]);
+ ASSERT_EQ(0xBC, bdaddr.address[5]);
+
+ std::string ret = bdaddr.ToString();
+
+ ASSERT_STREQ(test_addr, ret.c_str());
+}
+
+TEST(AddressUnittest, test_is_empty) {
+ Address empty;
+ Address::FromString("00:00:00:00:00:00", empty);
+ ASSERT_TRUE(empty.IsEmpty());
+
+ Address not_empty;
+ Address::FromString("00:00:00:00:00:01", not_empty);
+ ASSERT_FALSE(not_empty.IsEmpty());
+}
+
+TEST(AddressUnittest, test_to_from_str) {
+ Address bdaddr;
+ Address::FromString(test_addr, bdaddr);
+
+ ASSERT_EQ(0x12, bdaddr.address[0]);
+ ASSERT_EQ(0x34, bdaddr.address[1]);
+ ASSERT_EQ(0x56, bdaddr.address[2]);
+ ASSERT_EQ(0x78, bdaddr.address[3]);
+ ASSERT_EQ(0x9A, bdaddr.address[4]);
+ ASSERT_EQ(0xBC, bdaddr.address[5]);
+
+ std::string ret = bdaddr.ToString();
+
+ ASSERT_STREQ(test_addr, ret.c_str());
+}
+
+TEST(AddressUnittest, test_from_octets) {
+ static const uint8_t test_addr_array[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc};
+
+ Address bdaddr;
+ size_t expected_result = Address::kLength;
+ ASSERT_EQ(expected_result, bdaddr.FromOctets(test_addr_array));
+
+ ASSERT_EQ(0x12, bdaddr.address[0]);
+ ASSERT_EQ(0x34, bdaddr.address[1]);
+ ASSERT_EQ(0x56, bdaddr.address[2]);
+ ASSERT_EQ(0x78, bdaddr.address[3]);
+ ASSERT_EQ(0x9A, bdaddr.address[4]);
+ ASSERT_EQ(0xBC, bdaddr.address[5]);
+
+ std::string ret = bdaddr.ToString();
+
+ ASSERT_STREQ(test_addr, ret.c_str());
+}
+
+TEST(AddressTest, test_equals) {
+ Address bdaddr1;
+ Address bdaddr2;
+ Address bdaddr3;
+ Address::FromString(test_addr, bdaddr1);
+ Address::FromString(test_addr, bdaddr2);
+ EXPECT_TRUE(bdaddr1 == bdaddr2);
+ EXPECT_FALSE(bdaddr1 != bdaddr2);
+ EXPECT_TRUE(bdaddr1 == bdaddr1);
+ EXPECT_FALSE(bdaddr1 != bdaddr1);
+
+ Address::FromString(test_addr2, bdaddr3);
+ EXPECT_FALSE(bdaddr2 == bdaddr3);
+ EXPECT_TRUE(bdaddr2 != bdaddr3);
+}
+
+TEST(AddressTest, test_less_than) {
+ Address bdaddr1;
+ Address bdaddr2;
+ Address bdaddr3;
+ Address::FromString(test_addr, bdaddr1);
+ Address::FromString(test_addr, bdaddr2);
+ EXPECT_FALSE(bdaddr1 < bdaddr2);
+ EXPECT_FALSE(bdaddr1 < bdaddr1);
+
+ Address::FromString(test_addr2, bdaddr3);
+ EXPECT_TRUE(bdaddr2 < bdaddr3);
+ EXPECT_FALSE(bdaddr3 < bdaddr2);
+}
+
+TEST(AddressTest, test_more_than) {
+ Address bdaddr1;
+ Address bdaddr2;
+ Address bdaddr3;
+ Address::FromString(test_addr, bdaddr1);
+ Address::FromString(test_addr, bdaddr2);
+ EXPECT_FALSE(bdaddr1 > bdaddr2);
+ EXPECT_FALSE(bdaddr1 > bdaddr1);
+
+ Address::FromString(test_addr2, bdaddr3);
+ EXPECT_FALSE(bdaddr2 > bdaddr3);
+ EXPECT_TRUE(bdaddr3 > bdaddr2);
+}
+
+TEST(AddressTest, test_less_than_or_equal) {
+ Address bdaddr1;
+ Address bdaddr2;
+ Address bdaddr3;
+ Address::FromString(test_addr, bdaddr1);
+ Address::FromString(test_addr, bdaddr2);
+ EXPECT_TRUE(bdaddr1 <= bdaddr2);
+ EXPECT_TRUE(bdaddr1 <= bdaddr1);
+
+ Address::FromString(test_addr2, bdaddr3);
+ EXPECT_TRUE(bdaddr2 <= bdaddr3);
+ EXPECT_FALSE(bdaddr3 <= bdaddr2);
+}
+
+TEST(AddressTest, test_more_than_or_equal) {
+ Address bdaddr1;
+ Address bdaddr2;
+ Address bdaddr3;
+ Address::FromString(test_addr, bdaddr1);
+ Address::FromString(test_addr, bdaddr2);
+ EXPECT_TRUE(bdaddr1 >= bdaddr2);
+ EXPECT_TRUE(bdaddr1 >= bdaddr1);
+
+ Address::FromString(test_addr2, bdaddr3);
+ EXPECT_FALSE(bdaddr2 >= bdaddr3);
+ EXPECT_TRUE(bdaddr3 >= bdaddr2);
+}
+
+TEST(AddressTest, test_copy) {
+ Address bdaddr1;
+ Address bdaddr2;
+ Address::FromString(test_addr, bdaddr1);
+ bdaddr2 = bdaddr1;
+
+ EXPECT_TRUE(bdaddr1 == bdaddr2);
+}
+
+TEST(AddressTest, IsValidAddress) {
+ EXPECT_FALSE(Address::IsValidAddress(""));
+ EXPECT_FALSE(Address::IsValidAddress("000000000000"));
+ EXPECT_FALSE(Address::IsValidAddress("00:00:00:00:0000"));
+ EXPECT_FALSE(Address::IsValidAddress("00:00:00:00:00:0"));
+ EXPECT_FALSE(Address::IsValidAddress("00:00:00:00:00:0;"));
+ EXPECT_TRUE(Address::IsValidAddress("00:00:00:00:00:00"));
+ EXPECT_TRUE(Address::IsValidAddress("AB:cd:00:00:00:00"));
+ EXPECT_FALSE(Address::IsValidAddress("aB:cD:eF:Gh:iJ:Kl"));
+}
+
+TEST(AddressTest, BdAddrFromString) {
+ Address addr;
+ memset(&addr, 0, sizeof(addr));
+
+ EXPECT_TRUE(Address::FromString("00:00:00:00:00:00", addr));
+ const Address result0 = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
+ EXPECT_EQ(0, memcmp(&addr, &result0, sizeof(addr)));
+
+ EXPECT_TRUE(Address::FromString("ab:01:4C:d5:21:9f", addr));
+ const Address result1 = {{0x9f, 0x21, 0xd5, 0x4c, 0x01, 0xab}};
+ EXPECT_EQ(0, memcmp(&addr, &result1, sizeof(addr)));
+}
+
+TEST(AddressTest, BdAddrFromStringToStringEquivalent) {
+ std::string address = "c1:c2:c3:d1:d2:d3";
+ Address addr;
+
+ EXPECT_TRUE(Address::FromString(address, addr));
+ EXPECT_EQ(addr.ToString(), address);
+}
+
+TEST(AddressTest, BdAddrSameValueSameOrder) {
+ Address addr1{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ Address addr2{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ // Test if two addresses with same byte value have the same hash
+ struct std::hash<bluetooth::hci::Address> hasher;
+ EXPECT_EQ(hasher(addr1), hasher(addr2));
+ // Test if two addresses with the same hash and the same value, they will
+ // still map to the same value
+ std::unordered_map<Address, int> data = {};
+ data[addr1] = 5;
+ data[addr2] = 8;
+ EXPECT_EQ(data[addr1], data[addr2]);
+}
+
+TEST(AddressTest, BdAddrHashDifferentForDifferentAddressesZeroAddr) {
+ Address addr1{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ struct std::hash<Address> hasher;
+ EXPECT_NE(hasher(addr1), hasher(Address::kEmpty));
+}
+
+TEST(AddressTest, BdAddrHashDifferentForDifferentAddressesFullAddr) {
+ Address addr1{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ struct std::hash<Address> hasher;
+ EXPECT_NE(hasher(addr1), hasher(Address::kAny));
+}
+
+TEST(AddressTest, BdAddrHashDifferentForDifferentAddressesZeroAndFullAddr) {
+ struct std::hash<Address> hasher;
+ EXPECT_NE(hasher(Address::kEmpty), hasher(Address::kAny));
+}
diff --git a/gd/hci/address_with_type.h b/gd/hci/address_with_type.h
new file mode 100644
index 0000000..bed2cf2
--- /dev/null
+++ b/gd/hci/address_with_type.h
@@ -0,0 +1,96 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <sstream>
+#include <string>
+#include <utility>
+
+#include "hci/address.h"
+#include "hci/hci_packets.h"
+
+namespace bluetooth {
+namespace hci {
+
+class AddressWithType final {
+ public:
+ AddressWithType(Address address, AddressType address_type) : address_(address), address_type_(address_type) {}
+
+ explicit AddressWithType() : address_(Address::kEmpty), address_type_(AddressType::PUBLIC_DEVICE_ADDRESS) {}
+
+ inline Address GetAddress() const {
+ return address_;
+ }
+
+ inline AddressType GetAddressType() const {
+ return address_type_;
+ }
+
+ bool operator<(const AddressWithType& rhs) const {
+ return address_ < rhs.address_ && address_type_ < rhs.address_type_;
+ }
+ bool operator==(const AddressWithType& rhs) const {
+ return address_ == rhs.address_ && address_type_ == rhs.address_type_;
+ }
+ bool operator>(const AddressWithType& rhs) const {
+ return (rhs < *this);
+ }
+ bool operator<=(const AddressWithType& rhs) const {
+ return !(*this > rhs);
+ }
+ bool operator>=(const AddressWithType& rhs) const {
+ return !(*this < rhs);
+ }
+ bool operator!=(const AddressWithType& rhs) const {
+ return !(*this == rhs);
+ }
+
+ std::string ToString() const {
+ std::stringstream ss;
+ ss << address_ << "[" << AddressTypeText(address_type_) << "]";
+ return ss.str();
+ }
+
+ private:
+ Address address_;
+ AddressType address_type_;
+};
+
+inline std::ostream& operator<<(std::ostream& os, const AddressWithType& a) {
+ os << a.ToString();
+ return os;
+}
+
+} // namespace hci
+} // namespace bluetooth
+
+namespace std {
+template <>
+struct hash<bluetooth::hci::AddressWithType> {
+ std::size_t operator()(const bluetooth::hci::AddressWithType& val) const {
+ static_assert(sizeof(uint64_t) >= (sizeof(bluetooth::hci::Address) + sizeof(bluetooth::hci::AddressType)));
+ uint64_t int_addr = 0;
+ memcpy(reinterpret_cast<uint8_t*>(&int_addr), val.GetAddress().address, sizeof(bluetooth::hci::Address));
+ bluetooth::hci::AddressType address_type = val.GetAddressType();
+ memcpy(reinterpret_cast<uint8_t*>(&int_addr) + sizeof(bluetooth::hci::Address), &address_type,
+ sizeof(address_type));
+ return std::hash<uint64_t>{}(int_addr);
+ }
+};
+} // namespace std
\ No newline at end of file
diff --git a/gd/hci/address_with_type_test.cc b/gd/hci/address_with_type_test.cc
new file mode 100644
index 0000000..f1e5a60
--- /dev/null
+++ b/gd/hci/address_with_type_test.cc
@@ -0,0 +1,68 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 <unordered_map>
+
+#include <gtest/gtest.h>
+
+#include "hci/address.h"
+#include "hci/address_with_type.h"
+#include "hci/hci_packets.h"
+
+namespace bluetooth {
+namespace hci {
+
+TEST(AddressWithTypeTest, AddressWithTypeSameValueSameOrder) {
+ Address addr1{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ AddressType type1 = AddressType::PUBLIC_DEVICE_ADDRESS;
+ AddressWithType address_with_type_1(addr1, type1);
+ Address addr2{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ AddressType type2 = AddressType::PUBLIC_DEVICE_ADDRESS;
+ AddressWithType address_with_type_2(addr2, type2);
+ // Test if two address with type with same byte value have the same hash
+ struct std::hash<bluetooth::hci::AddressWithType> hasher;
+ EXPECT_EQ(hasher(address_with_type_1), hasher(address_with_type_2));
+ // Test if two address with type with the same hash and the same value, they will
+ // still map to the same value
+ std::unordered_map<AddressWithType, int> data = {};
+ data[address_with_type_1] = 5;
+ data[address_with_type_2] = 8;
+ EXPECT_EQ(data[address_with_type_1], data[address_with_type_2]);
+}
+
+TEST(AddressWithTypeTest, HashDifferentDiffAddrSameType) {
+ Address addr{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ AddressType type = AddressType::PUBLIC_IDENTITY_ADDRESS;
+ AddressWithType address_with_type(addr, type);
+ struct std::hash<AddressWithType> hasher;
+ EXPECT_NE(hasher(address_with_type), hasher(AddressWithType(Address::kEmpty, AddressType::PUBLIC_IDENTITY_ADDRESS)));
+}
+
+TEST(AddressWithTypeTest, HashDifferentSameAddressDiffType) {
+ Address addr1{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ AddressType type1 = AddressType::PUBLIC_DEVICE_ADDRESS;
+ AddressWithType address_with_type_1(addr1, type1);
+ Address addr2{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ AddressType type2 = AddressType::PUBLIC_IDENTITY_ADDRESS;
+ AddressWithType address_with_type_2(addr2, type2);
+ struct std::hash<bluetooth::hci::AddressWithType> hasher;
+ EXPECT_NE(hasher(address_with_type_1), hasher(address_with_type_2));
+}
+
+} // namespace hci
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/hci/cert/api.proto b/gd/hci/cert/api.proto
new file mode 100644
index 0000000..cf47743
--- /dev/null
+++ b/gd/hci/cert/api.proto
@@ -0,0 +1,46 @@
+syntax = "proto3";
+
+package bluetooth.hci.cert;
+
+import "google/protobuf/empty.proto";
+import "facade/common.proto";
+
+service AclManagerCert {
+ rpc SetPageScanMode(PageScanMode) returns (google.protobuf.Empty) {}
+ rpc SetIncomingConnectionPolicy(IncomingConnectionPolicy) returns (google.protobuf.Empty) {}
+ rpc Connect(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
+ rpc Disconnect(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
+ rpc FetchConnectionComplete(facade.EventStreamRequest) returns (stream ConnectionEvent) {}
+ rpc FetchDisconnection(facade.EventStreamRequest) returns (stream DisconnectionEvent) {}
+ rpc FetchConnectionFailed(facade.EventStreamRequest) returns (stream ConnectionFailedEvent) {}
+ rpc SendAclData(AclData) returns (google.protobuf.Empty) {}
+ rpc FetchAclData(facade.EventStreamRequest) returns (stream AclData) {}
+}
+
+message PageScanMode {
+ bool enabled = 1;
+}
+
+message IncomingConnectionPolicy {
+ facade.BluetoothAddress remote = 1;
+ bool accepted = 2;
+}
+
+message ConnectionEvent {
+ facade.BluetoothAddress remote = 1;
+}
+
+message DisconnectionEvent {
+ facade.BluetoothAddress remote = 1;
+ uint32 reason = 2;
+}
+
+message ConnectionFailedEvent {
+ facade.BluetoothAddress remote = 1;
+ uint32 reason = 2;
+}
+
+message AclData {
+ facade.BluetoothAddress remote = 1;
+ bytes payload = 2;
+}
diff --git a/gd/hci/cert/cert.cc b/gd/hci/cert/cert.cc
new file mode 100644
index 0000000..3ca100f
--- /dev/null
+++ b/gd/hci/cert/cert.cc
@@ -0,0 +1,358 @@
+/*
+ * Copyright 2019 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 "hci/cert/cert.h"
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <set>
+
+#include "common/blocking_queue.h"
+#include "grpc/grpc_event_stream.h"
+#include "hci/cert/api.grpc.pb.h"
+#include "hci/classic_security_manager.h"
+#include "hci/controller.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "os/queue.h"
+#include "packet/raw_builder.h"
+
+using ::grpc::ServerAsyncResponseWriter;
+using ::grpc::ServerAsyncWriter;
+using ::grpc::ServerContext;
+
+using ::bluetooth::common::Bind;
+using ::bluetooth::common::BindOnce;
+using ::bluetooth::facade::EventStreamRequest;
+using ::bluetooth::packet::RawBuilder;
+
+namespace bluetooth {
+namespace hci {
+namespace cert {
+
+class AclManagerCertService : public AclManagerCert::Service {
+ public:
+ AclManagerCertService(Controller* controller, HciLayer* hci_layer, ::bluetooth::os::Handler* facade_handler)
+ : controller_(controller), hci_layer_(hci_layer), handler_(facade_handler),
+ acl_queue_end_(hci_layer_->GetAclQueueEnd()) {
+ hci_layer_->RegisterEventHandler(EventCode::CONNECTION_COMPLETE,
+ Bind(&AclManagerCertService::on_connection_complete, common::Unretained(this)),
+ handler_);
+ hci_layer_->RegisterEventHandler(EventCode::DISCONNECTION_COMPLETE,
+ Bind(&AclManagerCertService::on_disconnection_complete, common::Unretained(this)),
+ handler_);
+ hci_layer_->RegisterEventHandler(EventCode::CONNECTION_REQUEST,
+ Bind(&AclManagerCertService::on_incoming_connection, common::Unretained(this)),
+ handler_);
+ hci_layer_->RegisterEventHandler(
+ EventCode::CONNECTION_PACKET_TYPE_CHANGED,
+ Bind(&AclManagerCertService::on_connection_packet_type_changed, common::Unretained(this)), handler_);
+ hci_layer_->RegisterEventHandler(EventCode::QOS_SETUP_COMPLETE,
+ Bind(&AclManagerCertService::on_qos_setup_complete, common::Unretained(this)),
+ handler_);
+ hci_layer_->RegisterEventHandler(EventCode::ROLE_CHANGE,
+ Bind(&AclManagerCertService::on_role_change, common::Unretained(this)), handler_);
+
+ controller_->RegisterCompletedAclPacketsCallback(common::Bind([](uint16_t, uint16_t) { /* TODO check */ }),
+ handler_);
+ acl_queue_end_->RegisterDequeue(handler_,
+ Bind(&AclManagerCertService::on_incoming_packet, common::Unretained(this)));
+ }
+
+ void on_incoming_packet() {
+ auto packet = acl_queue_end_->TryDequeue();
+ ASSERT(packet->IsValid());
+ AclData acl_data;
+ if (connected_devices_.find(packet->GetHandle()) == connected_devices_.end()) {
+ LOG_ERROR("Can't find remote device");
+ return;
+ }
+ auto address = connected_devices_[packet->GetHandle()];
+ acl_data.mutable_remote()->set_address(address.ToString());
+ std::string data = std::string(packet->begin(), packet->end());
+ acl_data.set_payload(data);
+ acl_stream_.OnIncomingEvent(acl_data);
+ }
+
+ ~AclManagerCertService() {
+ acl_queue_end_->UnregisterDequeue();
+ hci_layer_->UnregisterEventHandler(EventCode::CONNECTION_REQUEST);
+ hci_layer_->UnregisterEventHandler(EventCode::DISCONNECTION_COMPLETE);
+ hci_layer_->UnregisterEventHandler(EventCode::CONNECTION_COMPLETE);
+ }
+
+ void on_connection_complete(EventPacketView packet) {
+ ConnectionCompleteView connection_complete = ConnectionCompleteView::Create(std::move(packet));
+ ASSERT(connection_complete.IsValid());
+ auto status = connection_complete.GetStatus();
+ auto address = connection_complete.GetBdAddr();
+ auto handle = connection_complete.GetConnectionHandle();
+ if (status == ErrorCode::SUCCESS) {
+ connected_devices_.emplace(handle, address);
+ ConnectionEvent event;
+ event.mutable_remote()->set_address(address.ToString());
+ connection_complete_stream_.OnIncomingEvent(event);
+ } else {
+ ConnectionFailedEvent event;
+ event.mutable_remote()->set_address(address.ToString());
+ event.set_reason(static_cast<uint32_t>(connection_complete.GetStatus()));
+ connection_failed_stream_.OnIncomingEvent(event);
+ }
+ }
+
+ void on_disconnection_complete(EventPacketView packet) {
+ DisconnectionCompleteView disconnection_complete = DisconnectionCompleteView::Create(std::move(packet));
+ ASSERT(disconnection_complete.IsValid());
+ auto status = disconnection_complete.GetStatus();
+ auto handle = disconnection_complete.GetConnectionHandle();
+ auto device = connected_devices_.find(handle);
+
+ ASSERT(device != connected_devices_.end());
+ auto address = device->second;
+ if (status == ErrorCode::SUCCESS) {
+ connected_devices_.erase(handle);
+ DisconnectionEvent event;
+ event.mutable_remote()->set_address(address.ToString());
+ event.set_reason(static_cast<uint32_t>(disconnection_complete.GetReason()));
+ disconnection_stream_.OnIncomingEvent(event);
+ }
+ }
+
+ void on_incoming_connection(EventPacketView packet) {
+ ConnectionRequestView request = ConnectionRequestView::Create(packet);
+ ASSERT(request.IsValid());
+ Address address = request.GetBdAddr();
+ if (accepted_devices_.find(address) != accepted_devices_.end()) {
+ auto role = AcceptConnectionRequestRole::BECOME_MASTER; // We prefer to be master
+ hci_layer_->EnqueueCommand(AcceptConnectionRequestBuilder::Create(address, role),
+ common::BindOnce([](CommandStatusView status) { /* TODO: check? */ }), handler_);
+ } else {
+ auto reason = RejectConnectionReason::LIMITED_RESOURCES;
+ auto builder = RejectConnectionRequestBuilder::Create(address, reason);
+ hci_layer_->EnqueueCommand(std::move(builder), BindOnce([](CommandStatusView status) { /* TODO: check? */ }),
+ handler_);
+ }
+ }
+
+ void on_connection_packet_type_changed(EventPacketView packet) { /*TODO*/
+ }
+
+ void on_qos_setup_complete(EventPacketView packet) { /*TODO*/
+ }
+
+ void on_role_change(EventPacketView packet) { /*TODO*/
+ }
+
+ using EventStream = ::bluetooth::grpc::GrpcEventStream<AclData, AclPacketView>;
+
+ ::grpc::Status SetPageScanMode(::grpc::ServerContext* context, const ::bluetooth::hci::cert::PageScanMode* request,
+ ::google::protobuf::Empty* response) override {
+ ScanEnable scan_enable = request->enabled() ? ScanEnable::PAGE_SCAN_ONLY : ScanEnable::NO_SCANS;
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ hci_layer_->EnqueueCommand(
+ WriteScanEnableBuilder::Create(scan_enable),
+ common::BindOnce([](std::promise<void> promise, CommandCompleteView) { promise.set_value(); },
+ std::move(promise)),
+ handler_);
+ future.wait();
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SetIncomingConnectionPolicy(::grpc::ServerContext* context,
+ const ::bluetooth::hci::cert::IncomingConnectionPolicy* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ Address peer;
+ ASSERT(Address::FromString(request->remote().address(), peer));
+ if (request->accepted()) {
+ accepted_devices_.insert(peer);
+ } else {
+ accepted_devices_.erase(peer);
+ }
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status Connect(::grpc::ServerContext* context, const facade::BluetoothAddress* remote,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+
+ uint16_t packet_type = 0x4408 /* DM 1,3,5 */ | 0x8810 /*DH 1,3,5 */;
+ PageScanRepetitionMode page_scan_repetition_mode = PageScanRepetitionMode::R1;
+ uint16_t clock_offset = 0;
+ ClockOffsetValid clock_offset_valid = ClockOffsetValid::INVALID;
+ CreateConnectionRoleSwitch allow_role_switch = CreateConnectionRoleSwitch::ALLOW_ROLE_SWITCH;
+
+ Address peer;
+ ASSERT(Address::FromString(remote->address(), peer));
+ std::unique_ptr<CreateConnectionBuilder> packet = CreateConnectionBuilder::Create(
+ peer, packet_type, page_scan_repetition_mode, clock_offset, clock_offset_valid, allow_role_switch);
+
+ hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce([](CommandStatusView status) {
+ ASSERT(status.IsValid());
+ ASSERT(status.GetCommandOpCode() == OpCode::CREATE_CONNECTION);
+ }),
+ handler_);
+
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status Disconnect(::grpc::ServerContext* context, const facade::BluetoothAddress* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ Address peer;
+ Address::FromString(request->address(), peer);
+ uint16_t handle = find_connected_device_handle_by_address(peer);
+ if (handle == kInvalidHandle) {
+ return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid address");
+ }
+
+ DisconnectReason reason = DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION;
+ std::unique_ptr<DisconnectBuilder> packet = DisconnectBuilder::Create(handle, reason);
+ hci_layer_->EnqueueCommand(std::move(packet), BindOnce([](CommandStatusView status) { /* TODO: check? */ }),
+ handler_);
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendAclData(::grpc::ServerContext* context, const AclData* request,
+ ::google::protobuf::Empty* response) override {
+ Address peer;
+ Address::FromString(request->remote().address(), peer);
+ auto handle = find_connected_device_handle_by_address(peer);
+ if (handle == kInvalidHandle) {
+ return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid address");
+ }
+
+ constexpr PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
+ constexpr BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
+ std::unique_ptr<RawBuilder> packet = std::make_unique<RawBuilder>();
+ auto req_string = request->payload();
+ packet->AddOctets(std::vector<uint8_t>(req_string.begin(), req_string.end()));
+ auto acl_packet = AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(packet));
+ acl_enqueue_buffer_.Enqueue(std::move(acl_packet), handler_);
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status FetchAclData(::grpc::ServerContext* context, const facade::EventStreamRequest* request,
+ ::grpc::ServerWriter<AclData>* writer) override {
+ return acl_stream_.HandleRequest(context, request, writer);
+ }
+
+ ::grpc::Status FetchConnectionComplete(::grpc::ServerContext* context, const EventStreamRequest* request,
+ ::grpc::ServerWriter<ConnectionEvent>* writer) override {
+ return connection_complete_stream_.HandleRequest(context, request, writer);
+ };
+
+ ::grpc::Status FetchConnectionFailed(::grpc::ServerContext* context, const EventStreamRequest* request,
+ ::grpc::ServerWriter<ConnectionFailedEvent>* writer) override {
+ return connection_failed_stream_.HandleRequest(context, request, writer);
+ };
+
+ ::grpc::Status FetchDisconnection(::grpc::ServerContext* context,
+ const ::bluetooth::facade::EventStreamRequest* request,
+ ::grpc::ServerWriter<DisconnectionEvent>* writer) override {
+ return disconnection_stream_.HandleRequest(context, request, writer);
+ }
+
+ private:
+ Controller* controller_;
+ HciLayer* hci_layer_;
+ ::bluetooth::os::Handler* handler_;
+ common::BidiQueueEnd<AclPacketBuilder, AclPacketView>* acl_queue_end_;
+ os::EnqueueBuffer<AclPacketBuilder> acl_enqueue_buffer_{acl_queue_end_};
+ mutable std::mutex mutex_;
+ std::set<Address> accepted_devices_;
+ std::map<uint16_t /* handle */, Address> connected_devices_;
+
+ constexpr static uint16_t kInvalidHandle = 0xffff;
+
+ uint16_t find_connected_device_handle_by_address(Address address) {
+ for (auto device : connected_devices_) {
+ if (device.second == address) {
+ return device.first;
+ }
+ }
+ return kInvalidHandle; // Can't find
+ }
+
+ class ConnectionCompleteStreamCallback
+ : public ::bluetooth::grpc::GrpcEventStreamCallback<ConnectionEvent, ConnectionEvent> {
+ public:
+ void OnWriteResponse(ConnectionEvent* response, const ConnectionEvent& connection) override {
+ response->CopyFrom(connection);
+ }
+ } connection_complete_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<ConnectionEvent, ConnectionEvent> connection_complete_stream_{
+ &connection_complete_stream_callback_};
+
+ class ConnectionFailedStreamCallback
+ : public ::bluetooth::grpc::GrpcEventStreamCallback<ConnectionFailedEvent, ConnectionFailedEvent> {
+ public:
+ void OnWriteResponse(ConnectionFailedEvent* response, const ConnectionFailedEvent& event) override {
+ response->CopyFrom(event);
+ }
+ } connection_failed_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<ConnectionFailedEvent, ConnectionFailedEvent> connection_failed_stream_{
+ &connection_failed_stream_callback_};
+
+ class DisconnectionStreamCallback
+ : public ::bluetooth::grpc::GrpcEventStreamCallback<DisconnectionEvent, DisconnectionEvent> {
+ public:
+ void OnWriteResponse(DisconnectionEvent* response, const DisconnectionEvent& event) override {
+ response->CopyFrom(event);
+ }
+ } disconnection_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<DisconnectionEvent, DisconnectionEvent> disconnection_stream_{
+ &disconnection_stream_callback_};
+
+ class AclStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<AclData, AclData> {
+ public:
+ void OnWriteResponse(AclData* response, const AclData& event) override {
+ response->CopyFrom(event);
+ }
+
+ } acl_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<AclData, AclData> acl_stream_{&acl_stream_callback_};
+};
+
+void AclManagerCertModule::ListDependencies(ModuleList* list) {
+ ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
+ list->add<Controller>();
+ list->add<HciLayer>();
+ list->add<ClassicSecurityManager>();
+}
+
+void AclManagerCertModule::Start() {
+ ::bluetooth::grpc::GrpcFacadeModule::Start();
+ service_ = new AclManagerCertService(GetDependency<Controller>(), GetDependency<HciLayer>(), GetHandler());
+}
+
+void AclManagerCertModule::Stop() {
+ delete service_;
+ ::bluetooth::grpc::GrpcFacadeModule::Stop();
+}
+
+::grpc::Service* AclManagerCertModule::GetService() const {
+ return service_;
+}
+
+const ModuleFactory AclManagerCertModule::Factory =
+ ::bluetooth::ModuleFactory([]() { return new AclManagerCertModule(); });
+
+} // namespace cert
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/cert/cert.h b/gd/hci/cert/cert.h
new file mode 100644
index 0000000..e3ecf46
--- /dev/null
+++ b/gd/hci/cert/cert.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <grpc++/grpc++.h>
+
+#include "grpc/grpc_module.h"
+#include "hci/acl_manager.h"
+
+namespace bluetooth {
+namespace hci {
+namespace cert {
+
+class AclManagerCertService;
+
+class AclManagerCertModule : public ::bluetooth::grpc::GrpcFacadeModule {
+ public:
+ static const ModuleFactory Factory;
+
+ void ListDependencies(ModuleList* list) override;
+ void Start() override;
+ void Stop() override;
+ ::grpc::Service* GetService() const override;
+
+ private:
+ AclManagerCertService* service_;
+};
+
+} // namespace cert
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/cert/simple_hci_test.py b/gd/hci/cert/simple_hci_test.py
new file mode 100644
index 0000000..5cfd0ee
--- /dev/null
+++ b/gd/hci/cert/simple_hci_test.py
@@ -0,0 +1,346 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 - 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.
+
+from __future__ import print_function
+
+import os
+import sys
+sys.path.append(os.environ['ANDROID_BUILD_TOP'] + '/system/bt/gd')
+
+from cert.gd_base_test import GdBaseTestClass
+from cert.event_stream import EventStream
+from cert import rootservice_pb2 as cert_rootservice_pb2
+from facade import common_pb2
+from facade import rootservice_pb2 as facade_rootservice_pb2
+from google.protobuf import empty_pb2
+from hci import facade_pb2 as hci_facade_pb2
+from hci.cert import api_pb2 as hci_cert_pb2
+from hci.cert import api_pb2_grpc as hci_cert_pb2_grpc
+
+class SimpleHciTest(GdBaseTestClass):
+
+ def setup_test(self):
+ self.device_under_test = self.gd_devices[0]
+ self.cert_device = self.gd_cert_devices[0]
+
+ self.device_under_test.rootservice.StartStack(
+ facade_rootservice_pb2.StartStackRequest(
+ module_under_test=facade_rootservice_pb2.BluetoothModule.Value('HCI'),
+ )
+ )
+ self.cert_device.rootservice.StartStack(
+ cert_rootservice_pb2.StartStackRequest(
+ module_to_test=cert_rootservice_pb2.BluetoothModule.Value('HCI'),
+ )
+ )
+
+ self.device_under_test.wait_channel_ready()
+ self.cert_device.wait_channel_ready()
+
+ self.device_under_test.hci.SetPageScanMode(
+ hci_facade_pb2.PageScanMode(enabled=True)
+ )
+ self.cert_device.hci.SetPageScanMode(
+ hci_cert_pb2.PageScanMode(enabled=True)
+ )
+
+ dut_address = self.device_under_test.controller_read_only_property.ReadLocalAddress(empty_pb2.Empty()).address
+ self.device_under_test.address = dut_address
+ cert_address = self.cert_device.controller_read_only_property.ReadLocalAddress(empty_pb2.Empty()).address
+ self.cert_device.address = cert_address
+
+ self.dut_connection_complete_stream = self.device_under_test.hci.connection_complete_stream
+ self.dut_disconnection_stream = self.device_under_test.hci.disconnection_stream
+ self.dut_connection_failed_stream = self.device_under_test.hci.connection_failed_stream
+ self.dut_command_complete_stream = self.device_under_test.hci_classic_security.command_complete_stream
+
+ self.dut_address = common_pb2.BluetoothAddress(
+ address=self.device_under_test.address)
+ self.cert_address = common_pb2.BluetoothAddress(
+ address=self.cert_device.address)
+
+ def teardown_test(self):
+ self.device_under_test.rootservice.StopStack(
+ facade_rootservice_pb2.StopStackRequest()
+ )
+ self.cert_device.rootservice.StopStack(
+ cert_rootservice_pb2.StopStackRequest()
+ )
+
+ def test_none_event(self):
+ self.dut_connection_complete_stream.clear_event_buffer()
+ self.dut_connection_complete_stream.subscribe()
+ self.dut_connection_complete_stream.assert_none()
+ self.dut_connection_complete_stream.unsubscribe()
+
+ def _connect_from_dut(self):
+ policy = hci_cert_pb2.IncomingConnectionPolicy(
+ remote=self.dut_address,
+ accepted=True
+ )
+ self.cert_device.hci.SetIncomingConnectionPolicy(policy)
+
+ self.dut_connection_complete_stream.subscribe()
+ self.device_under_test.hci.Connect(self.cert_address)
+ self.dut_connection_complete_stream.assert_event_occurs(
+ lambda event: self._get_handle(event)
+ )
+ self.dut_connection_complete_stream.unsubscribe()
+
+ def _disconnect_from_dut(self):
+ self.dut_disconnection_stream.subscribe()
+ self.device_under_test.hci.Disconnect(self.cert_address)
+ self.dut_disconnection_stream.assert_event_occurs(
+ lambda event: event.remote.address == self.cert_device.address
+ )
+
+ def _get_handle(self, event):
+ if event.remote.address == self.cert_device.address:
+ self.connection_handle = event.connection_handle
+ return True
+ return False
+
+ def test_connect_disconnect_send_acl(self):
+ self._connect_from_dut()
+
+ cert_acl_stream = self.cert_device.hci.acl_stream
+ cert_acl_stream.subscribe()
+ acl_data = hci_facade_pb2.AclData(remote=self.cert_address, payload=b'123')
+ self.device_under_test.hci.SendAclData(acl_data)
+ self.device_under_test.hci.SendAclData(acl_data)
+ self.device_under_test.hci.SendAclData(acl_data)
+ cert_acl_stream.assert_event_occurs(
+ lambda packet : b'123' in packet.payload
+ and packet.remote == self.dut_address
+ )
+ cert_acl_stream.unsubscribe()
+
+ self._disconnect_from_dut()
+
+ def test_connect_disconnect_receive_acl(self):
+ self._connect_from_dut()
+
+ self.device_under_test.hci.acl_stream.subscribe()
+ acl_data = hci_cert_pb2.AclData(remote=self.dut_address, payload=b'123')
+ self.cert_device.hci.SendAclData(acl_data)
+ self.cert_device.hci.SendAclData(acl_data)
+ self.cert_device.hci.SendAclData(acl_data)
+ self.device_under_test.hci.acl_stream.assert_event_occurs(
+ lambda packet : b'123' in packet.payload
+ and packet.remote == self.cert_address
+ )
+ self.device_under_test.hci.acl_stream.unsubscribe()
+
+ self._disconnect_from_dut()
+
+ def test_reject_connection_request(self):
+ self.dut_connection_failed_stream.subscribe()
+ self.device_under_test.hci.Connect(self.cert_address)
+ self.dut_connection_failed_stream.assert_event_occurs(
+ lambda event : event.remote == self.cert_address
+ )
+ self.dut_connection_failed_stream.unsubscribe()
+
+ def test_send_classic_security_command(self):
+ self._connect_from_dut()
+ self.dut_command_complete_stream.subscribe()
+
+ self.device_under_test.hci.AuthenticationRequested(self.cert_address)
+
+ # Link request
+ self.device_under_test.hci_classic_security.LinkKeyRequestNegativeReply(self.cert_address)
+ self.dut_command_complete_stream.assert_event_occurs(
+ lambda event: event.command_opcode == 0x040c
+ )
+
+ # Pin code request
+ message = hci_facade_pb2.PinCodeRequestReplyMessage(
+ remote=self.cert_address,
+ len=4,
+ pin_code=bytes("1234", encoding = "ASCII")
+ )
+ self.device_under_test.hci_classic_security.PinCodeRequestReply(message)
+ self.dut_command_complete_stream.assert_event_occurs(
+ lambda event: event.command_opcode == 0x040d
+ )
+ self.device_under_test.hci_classic_security.PinCodeRequestNegativeReply(self.cert_address)
+ self.dut_command_complete_stream.assert_event_occurs(
+ lambda event: event.command_opcode == 0x040e
+ )
+
+ # IO capability request
+ message = hci_facade_pb2.IoCapabilityRequestReplyMessage(
+ remote=self.cert_address,
+ io_capability=0,
+ oob_present=0,
+ authentication_requirements=0
+ )
+ self.device_under_test.hci_classic_security.IoCapabilityRequestReply(message)
+ self.dut_command_complete_stream.assert_event_occurs(
+ lambda event: event.command_opcode == 0x042b
+ )
+
+ # message = hci_facade_pb2.IoCapabilityRequestNegativeReplyMessage(
+ # remote=self.cert_address,
+ # reason=1
+ # )
+ # # link_layer_controller.cc(447)] Check failed: security_manager_.GetAuthenticationAddress() == peer
+ # self.device_under_test.hci_classic_security.IoCapabilityRequestNegativeReply(message)
+
+ # User confirm request
+ self.device_under_test.hci_classic_security.UserConfirmationRequestReply(self.cert_address)
+ self.dut_command_complete_stream.assert_event_occurs(
+ lambda event: event.command_opcode == 0x042c
+ )
+
+ message = hci_facade_pb2.LinkKeyRequestReplyMessage(
+ remote=self.cert_address,
+ link_key=bytes("4C68384139F574D836BCF34E9DFB01BF", encoding = "ASCII")
+ )
+ self.device_under_test.hci_classic_security.LinkKeyRequestReply(message)
+ self.dut_command_complete_stream.assert_event_occurs(
+ lambda event: event.command_opcode == 0x040b
+ )
+
+ self.device_under_test.hci_classic_security.UserConfirmationRequestNegativeReply(self.cert_address)
+ self.dut_command_complete_stream.assert_event_occurs(
+ lambda event: event.command_opcode == 0x042d
+ )
+
+ # User passkey request
+ message = hci_facade_pb2.UserPasskeyRequestReplyMessage(
+ remote=self.cert_address,
+ passkey=999999,
+ )
+ self.device_under_test.hci_classic_security.UserPasskeyRequestReply(message)
+ self.dut_command_complete_stream.assert_event_occurs(
+ lambda event: event.command_opcode == 0x042e
+ )
+
+ self.device_under_test.hci_classic_security.UserPasskeyRequestNegativeReply(self.cert_address)
+ self.dut_command_complete_stream.assert_event_occurs(
+ lambda event: event.command_opcode == 0x042f
+ )
+
+ # Remote OOB data request
+ message = hci_facade_pb2.RemoteOobDataRequestReplyMessage(
+ remote=self.cert_address,
+ c=b'\x19\x20\x21\x22\x23\x24\x25\x26\x19\x20\x21\x22\x23\x24\x25\x26',
+ r=b'\x30\x31\x32\x33\x34\x35\x36\x37\x30\x31\x32\x33\x34\x35\x36\x37',
+ )
+ self.device_under_test.hci_classic_security.RemoteOobDataRequestReply(message)
+ self.dut_command_complete_stream.assert_event_occurs(
+ lambda event: event.command_opcode == 0x0430
+ )
+ self.device_under_test.hci_classic_security.RemoteOobDataRequestNegativeReply(self.cert_address)
+ self.dut_command_complete_stream.assert_event_occurs(
+ lambda event: event.command_opcode == 0x0433
+ )
+
+ # Read/Write/Delete link key
+ message = hci_facade_pb2.ReadStoredLinkKeyMessage(
+ remote=self.cert_address,
+ read_all_flag = 0,
+ )
+ self.device_under_test.hci_classic_security.ReadStoredLinkKey(message)
+ self.dut_command_complete_stream.assert_event_occurs(
+ lambda event: event.command_opcode == 0x0c0d
+ )
+
+ message = hci_facade_pb2.WriteStoredLinkKeyMessage(
+ num_keys_to_write=1,
+ remote=self.cert_address,
+ link_keys=bytes("4C68384139F574D836BCF34E9DFB01BF", encoding = "ASCII"),
+ )
+ self.device_under_test.hci_classic_security.WriteStoredLinkKey(message)
+
+ self.dut_command_complete_stream.assert_event_occurs(
+ lambda event: event.command_opcode == 0x0c11
+ )
+
+ message = hci_facade_pb2.DeleteStoredLinkKeyMessage(
+ remote=self.cert_address,
+ delete_all_flag = 0,
+ )
+ self.device_under_test.hci_classic_security.DeleteStoredLinkKey(message)
+ self.dut_command_complete_stream.assert_event_occurs(
+ lambda event: event.command_opcode == 0x0c12
+ )
+
+ # Refresh Encryption Key
+ message = hci_facade_pb2.RefreshEncryptionKeyMessage(
+ connection_handle=self.connection_handle,
+ )
+ self.device_under_test.hci_classic_security.RefreshEncryptionKey(message)
+
+ # Read/Write Simple Pairing Mode
+ self.device_under_test.hci_classic_security.ReadSimplePairingMode(empty_pb2.Empty())
+ self.dut_command_complete_stream.assert_event_occurs(
+ lambda event: event.command_opcode == 0x0c55
+ )
+
+ message = hci_facade_pb2.WriteSimplePairingModeMessage(
+ simple_pairing_mode=1,
+ )
+ self.device_under_test.hci_classic_security.WriteSimplePairingMode(message)
+ self.dut_command_complete_stream.assert_event_occurs(
+ lambda event: event.command_opcode == 0x0c56
+ )
+
+ # Read local oob data
+ self.device_under_test.hci_classic_security.ReadLocalOobData(empty_pb2.Empty())
+ self.dut_command_complete_stream.assert_event_occurs(
+ lambda event: event.command_opcode == 0x0c57
+ )
+
+ # Send keypress notification
+ message = hci_facade_pb2.SendKeypressNotificationMessage(
+ remote=self.cert_address,
+ notification_type=1,
+ )
+ self.device_under_test.hci_classic_security.SendKeypressNotification(message)
+ self.dut_command_complete_stream.assert_event_occurs(
+ lambda event: event.command_opcode == 0x0c60
+ )
+
+ # Read local oob extended data
+ self.device_under_test.hci_classic_security.ReadLocalOobExtendedData(empty_pb2.Empty())
+ self.dut_command_complete_stream.assert_event_occurs(
+ lambda event: event.command_opcode == 0x0c7d
+ )
+
+ # Read Encryption key size
+ message = hci_facade_pb2.ReadEncryptionKeySizeMessage(
+ connection_handle=self.connection_handle,
+ )
+ self.device_under_test.hci_classic_security.ReadEncryptionKeySize(message)
+ self.dut_command_complete_stream.assert_event_occurs(
+ lambda event: event.command_opcode == 0x1408
+ )
+
+ self.dut_command_complete_stream.unsubscribe()
+ self._disconnect_from_dut()
+
+ def test_interal_hci_command(self):
+ self._connect_from_dut()
+ self.device_under_test.hci.TestInternalHciCommands(empty_pb2.Empty())
+ self.device_under_test.hci.TestInternalHciLeCommands(empty_pb2.Empty())
+ self._disconnect_from_dut()
+
+ def test_classic_connection_management_command(self):
+ self._connect_from_dut()
+ self.device_under_test.hci.TestClassicConnectionManagementCommands(self.cert_address)
+ self._disconnect_from_dut()
\ No newline at end of file
diff --git a/gd/hci/class_of_device.cc b/gd/hci/class_of_device.cc
new file mode 100644
index 0000000..36dd292
--- /dev/null
+++ b/gd/hci/class_of_device.cc
@@ -0,0 +1,97 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "class_of_device.h"
+
+#include <stdint.h>
+#include <algorithm>
+#include <sstream>
+#include <vector>
+
+#include "os/log.h"
+
+namespace bluetooth {
+namespace hci {
+
+static_assert(sizeof(ClassOfDevice) == ClassOfDevice::kLength, "ClassOfDevice must be 3 bytes long!");
+
+ClassOfDevice::ClassOfDevice(const uint8_t (&class_of_device)[kLength]) {
+ std::copy(class_of_device, class_of_device + kLength, cod);
+};
+
+std::string ClassOfDevice::ToString() const {
+ char buffer[] = "000-0-00";
+ std::snprintf(&buffer[0], sizeof(buffer), "%03x-%01x-%02x", (static_cast<uint16_t>(cod[2]) << 4) | cod[1] >> 4,
+ cod[1] & 0x0f, cod[0]);
+ std::string str(buffer);
+ return str;
+}
+
+bool ClassOfDevice::FromString(const std::string& from, ClassOfDevice& to) {
+ ClassOfDevice new_cod;
+ if (from.length() != 8) return false;
+
+ std::istringstream stream(from);
+ std::string token;
+ int index = 0;
+ uint16_t values[3];
+
+ while (getline(stream, token, '-')) {
+ if (index >= 3) {
+ return false;
+ }
+
+ if (index == 0 && token.length() != 3) {
+ return false;
+ } else if (index == 1 && token.length() != 1) {
+ return false;
+ } else if (index == 2 && token.length() != 2) {
+ return false;
+ }
+ char* temp = nullptr;
+ values[index] = strtol(token.c_str(), &temp, 16);
+ if (*temp != '\0') {
+ return false;
+ }
+
+ index++;
+ }
+
+ if (index != 3) {
+ return false;
+ }
+
+ new_cod.cod[0] = values[2];
+ new_cod.cod[1] = values[1] | ((values[0] & 0xf) << 4);
+ new_cod.cod[2] = values[0] >> 4;
+
+ to = new_cod;
+ return true;
+}
+
+size_t ClassOfDevice::FromOctets(const uint8_t* from) {
+ std::copy(from, from + kLength, cod);
+ return kLength;
+};
+
+bool ClassOfDevice::IsValid(const std::string& cod) {
+ ClassOfDevice tmp;
+ return ClassOfDevice::FromString(cod, tmp);
+}
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/class_of_device.h b/gd/hci/class_of_device.h
new file mode 100644
index 0000000..b44a45e
--- /dev/null
+++ b/gd/hci/class_of_device.h
@@ -0,0 +1,63 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <string>
+
+namespace bluetooth {
+namespace hci {
+
+class ClassOfDevice final {
+ public:
+ static constexpr unsigned int kLength = 3;
+
+ uint8_t cod[kLength];
+
+ ClassOfDevice() = default;
+ ClassOfDevice(const uint8_t (&class_of_device)[kLength]);
+
+ bool operator==(const ClassOfDevice& rhs) const {
+ return (std::memcmp(cod, rhs.cod, sizeof(cod)) == 0);
+ }
+
+ bool operator!=(const ClassOfDevice& rhs) const {
+ return std::memcmp(cod, rhs.cod, sizeof(cod)) != 0;
+ }
+
+ std::string ToString() const;
+
+ // Converts |string| to ClassOfDevice and places it in |to|. If |from| does
+ // not represent a Class of Device, |to| is not modified and this function
+ // returns false. Otherwise, it returns true.
+ static bool FromString(const std::string& from, ClassOfDevice& to);
+
+ // Copies |from| raw Class of Device octets to the local object.
+ // Returns the number of copied octets (always ClassOfDevice::kLength)
+ size_t FromOctets(const uint8_t* from);
+
+ static bool IsValid(const std::string& class_of_device);
+};
+
+inline std::ostream& operator<<(std::ostream& os, const ClassOfDevice& c) {
+ os << c.ToString();
+ return os;
+}
+
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/class_of_device_unittest.cc b/gd/hci/class_of_device_unittest.cc
new file mode 100644
index 0000000..85472dd
--- /dev/null
+++ b/gd/hci/class_of_device_unittest.cc
@@ -0,0 +1,98 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 <gtest/gtest.h>
+
+#include "hci/class_of_device.h"
+
+using bluetooth::hci::ClassOfDevice;
+
+static const char* test_class = "efc-d-ab";
+static const uint8_t test_bytes[]{0xab, 0xcd, 0xef};
+
+TEST(ClassOfDeviceUnittest, test_constructor_array) {
+ ClassOfDevice cod(test_bytes);
+
+ ASSERT_EQ(test_bytes[0], cod.cod[0]);
+ ASSERT_EQ(test_bytes[1], cod.cod[1]);
+ ASSERT_EQ(test_bytes[2], cod.cod[2]);
+
+ std::string ret = cod.ToString();
+
+ ASSERT_STREQ(test_class, ret.c_str());
+}
+
+TEST(ClassOfDeviceUnittest, test_to_from_str) {
+ ClassOfDevice cod;
+ ClassOfDevice::FromString(test_class, cod);
+
+ ASSERT_EQ(test_bytes[0], cod.cod[0]);
+ ASSERT_EQ(test_bytes[1], cod.cod[1]);
+ ASSERT_EQ(test_bytes[2], cod.cod[2]);
+
+ std::string ret = cod.ToString();
+
+ ASSERT_STREQ(test_class, ret.c_str());
+}
+
+TEST(ClassOfDeviceUnittest, test_from_octets) {
+ ClassOfDevice cod;
+ size_t expected_result = ClassOfDevice::kLength;
+ ASSERT_EQ(expected_result, cod.FromOctets(test_bytes));
+
+ ASSERT_EQ(test_bytes[0], cod.cod[0]);
+ ASSERT_EQ(test_bytes[1], cod.cod[1]);
+ ASSERT_EQ(test_bytes[2], cod.cod[2]);
+
+ std::string ret = cod.ToString();
+
+ ASSERT_STREQ(test_class, ret.c_str());
+}
+
+TEST(ClassOfDeviceTest, test_copy) {
+ ClassOfDevice cod1;
+ ClassOfDevice cod2;
+ ClassOfDevice::FromString(test_class, cod1);
+ cod2 = cod1;
+
+ ASSERT_EQ(cod1.cod[0], cod2.cod[0]);
+ ASSERT_EQ(cod1.cod[1], cod2.cod[1]);
+ ASSERT_EQ(cod1.cod[2], cod2.cod[2]);
+}
+
+TEST(ClassOfDeviceTest, IsValid) {
+ EXPECT_FALSE(ClassOfDevice::IsValid(""));
+ EXPECT_FALSE(ClassOfDevice::IsValid("000000"));
+ EXPECT_FALSE(ClassOfDevice::IsValid("00-00-00"));
+ EXPECT_FALSE(ClassOfDevice::IsValid("000-0-0"));
+ EXPECT_TRUE(ClassOfDevice::IsValid("000-0-00"));
+ EXPECT_TRUE(ClassOfDevice::IsValid("ABc-d-00"));
+ EXPECT_TRUE(ClassOfDevice::IsValid("aBc-D-eF"));
+}
+
+TEST(ClassOfDeviceTest, classOfDeviceFromString) {
+ ClassOfDevice cod;
+
+ EXPECT_TRUE(ClassOfDevice::FromString("000-0-00", cod));
+ const ClassOfDevice result0 = {{0x00, 0x00, 0x00}};
+ EXPECT_EQ(0, memcmp(&cod, &result0, sizeof(cod)));
+
+ EXPECT_TRUE(ClassOfDevice::FromString("ab2-1-4C", cod));
+ const ClassOfDevice result1 = {{0x4c, 0x21, 0xab}};
+ EXPECT_EQ(0, memcmp(&cod, &result1, sizeof(cod)));
+}
diff --git a/gd/hci/classic_device.h b/gd/hci/classic_device.h
new file mode 100644
index 0000000..53ff0ba
--- /dev/null
+++ b/gd/hci/classic_device.h
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+#pragma once
+
+#include "hci/device.h"
+
+namespace bluetooth::hci {
+
+/**
+ * A device representing a CLASSIC device.
+ *
+ * <p>This can be a CLASSIC only or a piece of a DUAL MODE device.
+ */
+class ClassicDevice : public Device {
+ protected:
+ friend class DeviceDatabase;
+ explicit ClassicDevice(Address address) : Device(address, DeviceType::CLASSIC) {}
+};
+
+} // namespace bluetooth::hci
diff --git a/gd/hci/classic_security_manager.cc b/gd/hci/classic_security_manager.cc
new file mode 100644
index 0000000..07aae77
--- /dev/null
+++ b/gd/hci/classic_security_manager.cc
@@ -0,0 +1,376 @@
+/*
+ * Copyright 2019 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 "classic_security_manager.h"
+
+#include <future>
+#include <set>
+#include <utility>
+#include "os/log.h"
+
+#include "acl_manager.h"
+#include "common/bidi_queue.h"
+#include "hci/controller.h"
+#include "hci/hci_layer.h"
+
+namespace bluetooth {
+namespace hci {
+
+using common::Bind;
+using common::BindOnce;
+
+struct ClassicSecurityManager::impl {
+ impl(ClassicSecurityManager& classic_security_manager) : classic_security_manager_(classic_security_manager) {}
+
+ void Start() {
+ hci_layer_ = classic_security_manager_.GetDependency<HciLayer>();
+ handler_ = classic_security_manager_.GetHandler();
+ hci_layer_->RegisterEventHandler(EventCode::IO_CAPABILITY_REQUEST,
+ Bind(&impl::on_request_event, common::Unretained(this)), handler_);
+ hci_layer_->RegisterEventHandler(EventCode::LINK_KEY_REQUEST,
+ Bind(&impl::on_request_event, common::Unretained(this)), handler_);
+ hci_layer_->RegisterEventHandler(EventCode::PIN_CODE_REQUEST,
+ Bind(&impl::on_request_event, common::Unretained(this)), handler_);
+ hci_layer_->RegisterEventHandler(EventCode::ENCRYPTION_KEY_REFRESH_COMPLETE,
+ Bind(&impl::on_complete_event, common::Unretained(this)), handler_);
+ hci_layer_->RegisterEventHandler(EventCode::LINK_KEY_NOTIFICATION,
+ Bind(&impl::on_link_key_notification, common::Unretained(this)), handler_);
+ }
+
+ void Stop() {
+ hci_layer_->UnregisterEventHandler(EventCode::IO_CAPABILITY_REQUEST);
+ handler_ = nullptr;
+ hci_layer_ = nullptr;
+ }
+
+ void handle_register_callbacks(ClassicSecurityCommandCallbacks* callbacks, os::Handler* handler) {
+ ASSERT(client_callbacks_ == nullptr);
+ ASSERT(client_handler_ == nullptr);
+ client_callbacks_ = callbacks;
+ client_handler_ = handler;
+ }
+
+ void link_key_request_reply(Address address, common::LinkKey link_key) {
+ std::array<uint8_t, 16> link_key_array;
+ std::copy(std::begin(link_key.link_key), std::end(link_key.link_key), std::begin(link_key_array));
+
+ std::unique_ptr<LinkKeyRequestReplyBuilder> packet = LinkKeyRequestReplyBuilder::Create(address, link_key_array);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+ }
+
+ void link_key_request_negative_reply(Address address) {
+ std::unique_ptr<LinkKeyRequestNegativeReplyBuilder> packet = LinkKeyRequestNegativeReplyBuilder::Create(address);
+
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+ }
+
+ void pin_code_request_reply(Address address, uint8_t len, std::string pin_code) {
+ ASSERT(len > 0 && len <= 16 && pin_code.length() == len);
+ // fill remaining char with 0
+ pin_code.append(std::string(16 - len, '0'));
+ std::array<uint8_t, 16> pin_code_array;
+ std::copy(std::begin(pin_code), std::end(pin_code), std::begin(pin_code_array));
+
+ std::unique_ptr<PinCodeRequestReplyBuilder> packet =
+ PinCodeRequestReplyBuilder::Create(address, len, pin_code_array);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+ }
+
+ void pin_code_request_negative_reply(Address address) {
+ std::unique_ptr<PinCodeRequestNegativeReplyBuilder> packet = PinCodeRequestNegativeReplyBuilder::Create(address);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+ }
+
+ void io_capability_request_reply(Address address, IoCapability io_capability, OobDataPresent oob_present,
+ AuthenticationRequirements authentication_requirements) {
+ std::unique_ptr<IoCapabilityRequestReplyBuilder> packet =
+ IoCapabilityRequestReplyBuilder::Create(address, io_capability, oob_present, authentication_requirements);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+ }
+
+ void io_capability_request_negative_reply(Address address, ErrorCode reason) {
+ std::unique_ptr<IoCapabilityRequestNegativeReplyBuilder> packet =
+ IoCapabilityRequestNegativeReplyBuilder::Create(address, reason);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+ }
+
+ void user_confirmation_request_reply(Address address) {
+ std::unique_ptr<UserConfirmationRequestReplyBuilder> packet = UserConfirmationRequestReplyBuilder::Create(address);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+ }
+
+ void user_confirmation_request_negative_reply(Address address) {
+ std::unique_ptr<UserConfirmationRequestNegativeReplyBuilder> packet =
+ UserConfirmationRequestNegativeReplyBuilder::Create(address);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+ }
+
+ void user_passkey_request_reply(Address address, uint32_t passkey) {
+ ASSERT(passkey <= 999999);
+ std::unique_ptr<UserPasskeyRequestReplyBuilder> packet = UserPasskeyRequestReplyBuilder::Create(address, passkey);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+ }
+
+ void user_passkey_request_negative_reply(Address address) {
+ std::unique_ptr<UserPasskeyRequestNegativeReplyBuilder> packet =
+ UserPasskeyRequestNegativeReplyBuilder::Create(address);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+ }
+
+ void remote_oob_data_request_reply(Address address, std::array<uint8_t, 16> c, std::array<uint8_t, 16> r) {
+ std::unique_ptr<RemoteOobDataRequestReplyBuilder> packet = RemoteOobDataRequestReplyBuilder::Create(address, c, r);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+ }
+
+ void remote_oob_data_request_negative_reply(Address address) {
+ std::unique_ptr<RemoteOobDataRequestNegativeReplyBuilder> packet =
+ RemoteOobDataRequestNegativeReplyBuilder::Create(address);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+ }
+
+ void read_stored_link_key(Address address, ReadStoredLinkKeyReadAllFlag read_all_flag) {
+ std::unique_ptr<ReadStoredLinkKeyBuilder> packet = ReadStoredLinkKeyBuilder::Create(address, read_all_flag);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+ }
+
+ void write_stored_link_key(std::vector<KeyAndAddress> keys) {
+ std::unique_ptr<WriteStoredLinkKeyBuilder> packet = WriteStoredLinkKeyBuilder::Create(keys);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+ }
+
+ void delete_stored_link_key(Address address, DeleteStoredLinkKeyDeleteAllFlag delete_all_flag) {
+ std::unique_ptr<DeleteStoredLinkKeyBuilder> packet = DeleteStoredLinkKeyBuilder::Create(address, delete_all_flag);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+ }
+
+ void refresh_encryption_key(uint16_t connection_handle) {
+ std::unique_ptr<RefreshEncryptionKeyBuilder> packet = RefreshEncryptionKeyBuilder::Create(connection_handle);
+ hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce([](CommandStatusView status) { /* TODO: check? */ }),
+ handler_);
+ }
+
+ void read_simple_pairing_mode() {
+ std::unique_ptr<ReadSimplePairingModeBuilder> packet = ReadSimplePairingModeBuilder::Create();
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+ }
+
+ void write_simple_pairing_mode(Enable connection_handle) {
+ std::unique_ptr<WriteSimplePairingModeBuilder> packet = WriteSimplePairingModeBuilder::Create(connection_handle);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+ }
+
+ void read_local_oob_data() {
+ std::unique_ptr<ReadLocalOobDataBuilder> packet = ReadLocalOobDataBuilder::Create();
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+ }
+
+ void send_keypress_notification(Address address, KeypressNotificationType notification_type) {
+ std::unique_ptr<SendKeypressNotificationBuilder> packet =
+ SendKeypressNotificationBuilder::Create(address, notification_type);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+ }
+
+ void read_local_oob_extended_data() {
+ std::unique_ptr<ReadLocalOobExtendedDataBuilder> packet = ReadLocalOobExtendedDataBuilder::Create();
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+ }
+
+ void read_encryption_key_size(uint16_t connection_handle) {
+ std::unique_ptr<ReadEncryptionKeySizeBuilder> packet = ReadEncryptionKeySizeBuilder::Create(connection_handle);
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::on_command_complete, common::Unretained(this)), handler_);
+ }
+
+ // TODO remove
+ void on_request_event(EventPacketView packet) {
+ EventCode event_code = packet.GetEventCode();
+ LOG_DEBUG("receive request %d", (uint8_t)event_code);
+ }
+
+ // TODO remove
+ void on_complete_event(EventPacketView packet) {
+ EventCode event_code = packet.GetEventCode();
+ LOG_DEBUG("receive complete event %d", (uint8_t)event_code);
+ }
+
+ void on_link_key_notification(EventPacketView packet) {
+ auto view = LinkKeyNotificationView::Create(packet);
+ ASSERT(view.IsValid());
+ LOG_DEBUG("receive link key notification, key type %d", (uint8_t)view.GetKeyType());
+ }
+
+ void on_command_complete(CommandCompleteView status) {
+ if (client_handler_ != nullptr) {
+ client_handler_->Post(common::BindOnce(&ClassicSecurityCommandCallbacks::OnCommandComplete,
+ common::Unretained(client_callbacks_), status));
+ }
+ }
+
+ ClassicSecurityManager& classic_security_manager_;
+
+ Controller* controller_ = nullptr;
+
+ HciLayer* hci_layer_ = nullptr;
+ os::Handler* handler_ = nullptr;
+ ClassicSecurityCommandCallbacks* client_callbacks_ = nullptr;
+ os::Handler* client_handler_ = nullptr;
+};
+
+ClassicSecurityManager::ClassicSecurityManager() : pimpl_(std::make_unique<impl>(*this)) {}
+
+bool ClassicSecurityManager::RegisterCallbacks(ClassicSecurityCommandCallbacks* callbacks, os::Handler* handler) {
+ ASSERT(callbacks != nullptr && handler != nullptr);
+ GetHandler()->Post(common::BindOnce(&impl::handle_register_callbacks, common::Unretained(pimpl_.get()),
+ common::Unretained(callbacks), common::Unretained(handler)));
+ return true;
+}
+
+void ClassicSecurityManager::LinkKeyRequestReply(Address address, common::LinkKey link_key) {
+ GetHandler()->Post(BindOnce(&impl::link_key_request_reply, common::Unretained(pimpl_.get()), address, link_key));
+}
+
+void ClassicSecurityManager::LinkKeyRequestNegativeReply(Address address) {
+ GetHandler()->Post(BindOnce(&impl::link_key_request_negative_reply, common::Unretained(pimpl_.get()), address));
+}
+
+void ClassicSecurityManager::PinCodeRequestReply(Address address, uint8_t len, std::string pin_code) {
+ GetHandler()->Post(BindOnce(&impl::pin_code_request_reply, common::Unretained(pimpl_.get()), address, len, pin_code));
+}
+
+void ClassicSecurityManager::PinCodeRequestNegativeReply(Address address) {
+ GetHandler()->Post(BindOnce(&impl::pin_code_request_negative_reply, common::Unretained(pimpl_.get()), address));
+}
+
+void ClassicSecurityManager::IoCapabilityRequestReply(Address address, IoCapability io_capability,
+ OobDataPresent oob_present,
+ AuthenticationRequirements authentication_requirements) {
+ GetHandler()->Post(BindOnce(&impl::io_capability_request_reply, common::Unretained(pimpl_.get()), address,
+ io_capability, oob_present, authentication_requirements));
+}
+
+void ClassicSecurityManager::IoCapabilityRequestNegativeReply(Address address, ErrorCode reason) {
+ GetHandler()->Post(
+ BindOnce(&impl::io_capability_request_negative_reply, common::Unretained(pimpl_.get()), address, reason));
+}
+
+void ClassicSecurityManager::UserConfirmationRequestReply(Address address) {
+ GetHandler()->Post(BindOnce(&impl::user_confirmation_request_reply, common::Unretained(pimpl_.get()), address));
+}
+
+void ClassicSecurityManager::UserConfirmationRequestNegativeReply(Address address) {
+ GetHandler()->Post(
+ BindOnce(&impl::user_confirmation_request_negative_reply, common::Unretained(pimpl_.get()), address));
+}
+
+void ClassicSecurityManager::UserPasskeyRequestReply(bluetooth::hci::Address address, uint32_t passkey) {
+ GetHandler()->Post(BindOnce(&impl::user_passkey_request_reply, common::Unretained(pimpl_.get()), address, passkey));
+}
+
+void ClassicSecurityManager::UserPasskeyRequestNegativeReply(Address address) {
+ GetHandler()->Post(BindOnce(&impl::user_passkey_request_negative_reply, common::Unretained(pimpl_.get()), address));
+}
+
+void ClassicSecurityManager::RemoteOobDataRequestReply(Address address, std::array<uint8_t, 16> c,
+ std::array<uint8_t, 16> r) {
+ GetHandler()->Post(BindOnce(&impl::remote_oob_data_request_reply, common::Unretained(pimpl_.get()), address, c, r));
+}
+
+void ClassicSecurityManager::RemoteOobDataRequestNegativeReply(Address address) {
+ GetHandler()->Post(
+ BindOnce(&impl::remote_oob_data_request_negative_reply, common::Unretained(pimpl_.get()), address));
+}
+
+void ClassicSecurityManager::ReadStoredLinkKey(Address address, ReadStoredLinkKeyReadAllFlag read_all_flag) {
+ GetHandler()->Post(BindOnce(&impl::read_stored_link_key, common::Unretained(pimpl_.get()), address, read_all_flag));
+}
+
+void ClassicSecurityManager::WriteStoredLinkKey(std::vector<KeyAndAddress> keys) {
+ GetHandler()->Post(BindOnce(&impl::write_stored_link_key, common::Unretained(pimpl_.get()), keys));
+}
+
+void ClassicSecurityManager::DeleteStoredLinkKey(Address address, DeleteStoredLinkKeyDeleteAllFlag delete_all_flag) {
+ GetHandler()->Post(
+ BindOnce(&impl::delete_stored_link_key, common::Unretained(pimpl_.get()), address, delete_all_flag));
+}
+
+void ClassicSecurityManager::RefreshEncryptionKey(uint16_t connection_handle) {
+ GetHandler()->Post(BindOnce(&impl::refresh_encryption_key, common::Unretained(pimpl_.get()), connection_handle));
+}
+void ClassicSecurityManager::ReadSimplePairingMode() {
+ GetHandler()->Post(BindOnce(&impl::read_simple_pairing_mode, common::Unretained(pimpl_.get())));
+}
+
+void ClassicSecurityManager::WriteSimplePairingMode(Enable simple_pairing_mode) {
+ GetHandler()->Post(BindOnce(&impl::write_simple_pairing_mode, common::Unretained(pimpl_.get()), simple_pairing_mode));
+}
+
+void ClassicSecurityManager::ReadLocalOobData() {
+ GetHandler()->Post(BindOnce(&impl::read_local_oob_data, common::Unretained(pimpl_.get())));
+}
+
+void ClassicSecurityManager::SendKeypressNotification(Address address, KeypressNotificationType notification_type) {
+ GetHandler()->Post(
+ BindOnce(&impl::send_keypress_notification, common::Unretained(pimpl_.get()), address, notification_type));
+}
+
+void ClassicSecurityManager::ReadLocalOobExtendedData() {
+ GetHandler()->Post(BindOnce(&impl::read_local_oob_extended_data, common::Unretained(pimpl_.get())));
+}
+
+void ClassicSecurityManager::ReadEncryptionKeySize(uint16_t connection_handle) {
+ GetHandler()->Post(BindOnce(&impl::read_encryption_key_size, common::Unretained(pimpl_.get()), connection_handle));
+}
+
+void ClassicSecurityManager::ListDependencies(ModuleList* list) {
+ list->add<HciLayer>();
+}
+
+void ClassicSecurityManager::Start() {
+ pimpl_->Start();
+}
+
+void ClassicSecurityManager::Stop() {
+ pimpl_->Stop();
+}
+
+std::string ClassicSecurityManager::ToString() const {
+ return "Classic Security Manager";
+}
+
+const ModuleFactory ClassicSecurityManager::Factory = ModuleFactory([]() { return new ClassicSecurityManager(); });
+
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/classic_security_manager.h b/gd/hci/classic_security_manager.h
new file mode 100644
index 0000000..22b4ae1
--- /dev/null
+++ b/gd/hci/classic_security_manager.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "common/link_key.h"
+#include "hci/address.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+
+namespace bluetooth {
+namespace hci {
+
+class ClassicSecurityCommandCallbacks {
+ public:
+ virtual ~ClassicSecurityCommandCallbacks() = default;
+ // Invoked when controller sends Command Complete event
+ virtual void OnCommandComplete(CommandCompleteView status) = 0;
+};
+
+class ClassicSecurityManager : public Module {
+ public:
+ ClassicSecurityManager();
+
+ bool RegisterCallbacks(ClassicSecurityCommandCallbacks* callbacks, os::Handler* handler);
+
+ void LinkKeyRequestReply(Address address, common::LinkKey link_key);
+ void LinkKeyRequestNegativeReply(Address address);
+ void PinCodeRequestReply(Address address, uint8_t len, std::string pin_code);
+ void PinCodeRequestNegativeReply(Address address);
+ void IoCapabilityRequestReply(Address address, IoCapability io_capability, OobDataPresent oob_present,
+ AuthenticationRequirements authentication_requirements);
+ void IoCapabilityRequestNegativeReply(Address address, ErrorCode reason);
+ void UserConfirmationRequestReply(Address address);
+ void UserConfirmationRequestNegativeReply(Address address);
+ void UserPasskeyRequestReply(Address address, uint32_t passkey);
+ void UserPasskeyRequestNegativeReply(Address address);
+ void RemoteOobDataRequestReply(Address address, std::array<uint8_t, 16> c, std::array<uint8_t, 16> r);
+ void RemoteOobDataRequestNegativeReply(Address address);
+ void ReadStoredLinkKey(Address address, ReadStoredLinkKeyReadAllFlag read_all_flag);
+ void WriteStoredLinkKey(std::vector<KeyAndAddress> keys);
+ void DeleteStoredLinkKey(Address address, DeleteStoredLinkKeyDeleteAllFlag delete_all_flag);
+ void RefreshEncryptionKey(uint16_t connection_handle);
+ void ReadSimplePairingMode();
+ void WriteSimplePairingMode(Enable simple_pairing_mode);
+ void ReadLocalOobData();
+ void SendKeypressNotification(Address address, KeypressNotificationType notification_type);
+ void ReadLocalOobExtendedData();
+ void ReadEncryptionKeySize(uint16_t connection_handle);
+
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override;
+
+ void Start() override;
+
+ void Stop() override;
+
+ std::string ToString() const override;
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+};
+
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/classic_security_manager_test.cc b/gd/hci/classic_security_manager_test.cc
new file mode 100644
index 0000000..b2c936e
--- /dev/null
+++ b/gd/hci/classic_security_manager_test.cc
@@ -0,0 +1,420 @@
+/*
+ * Copyright 2019 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 "hci/classic_security_manager.h"
+
+#include <condition_variable>
+#include "gtest/gtest.h"
+
+#include "common/bind.h"
+#include "hci/hci_layer.h"
+#include "os/thread.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace hci {
+namespace {
+
+using common::BidiQueue;
+using common::BidiQueueEnd;
+using common::OnceCallback;
+using os::Handler;
+using os::Thread;
+using packet::RawBuilder;
+
+PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+ auto bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter i(*bytes);
+ bytes->reserve(packet->size());
+ packet->Serialize(i);
+ return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+class CommandQueueEntry {
+ public:
+ CommandQueueEntry(std::unique_ptr<CommandPacketBuilder> command_packet,
+ OnceCallback<void(CommandCompleteView)> on_complete_function, Handler* handler)
+ : command(std::move(command_packet)), waiting_for_status_(false), on_complete(std::move(on_complete_function)),
+ caller_handler(handler) {}
+
+ CommandQueueEntry(std::unique_ptr<CommandPacketBuilder> command_packet,
+ OnceCallback<void(CommandStatusView)> on_status_function, Handler* handler)
+ : command(std::move(command_packet)), waiting_for_status_(true), on_status(std::move(on_status_function)),
+ caller_handler(handler) {}
+
+ std::unique_ptr<CommandPacketBuilder> command;
+ bool waiting_for_status_;
+ OnceCallback<void(CommandStatusView)> on_status;
+ OnceCallback<void(CommandCompleteView)> on_complete;
+ Handler* caller_handler;
+};
+
+class TestHciLayer : public HciLayer {
+ public:
+ void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command, OnceCallback<void(CommandStatusView)> on_status,
+ Handler* handler) override {
+ auto command_queue_entry = std::make_unique<CommandQueueEntry>(std::move(command), std::move(on_status), handler);
+ command_queue_.push(std::move(command_queue_entry));
+ }
+
+ void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+ OnceCallback<void(CommandCompleteView)> on_complete, Handler* handler) override {
+ auto command_queue_entry = std::make_unique<CommandQueueEntry>(std::move(command), std::move(on_complete), handler);
+ command_queue_.push(std::move(command_queue_entry));
+ }
+
+ std::unique_ptr<CommandQueueEntry> GetLastCommand() {
+ EXPECT_FALSE(command_queue_.empty());
+ auto last = std::move(command_queue_.front());
+ command_queue_.pop();
+ return last;
+ }
+
+ void RegisterEventHandler(EventCode event_code, common::Callback<void(EventPacketView)> event_handler,
+ Handler* handler) override {
+ registered_events_[event_code] = event_handler;
+ }
+
+ void UnregisterEventHandler(EventCode event_code) override {
+ registered_events_.erase(event_code);
+ }
+
+ void IncomingEvent(std::unique_ptr<EventPacketBuilder> event_builder) {
+ auto packet = GetPacketView(std::move(event_builder));
+ EventPacketView event = EventPacketView::Create(packet);
+ EXPECT_TRUE(event.IsValid());
+ EventCode event_code = event.GetEventCode();
+ EXPECT_TRUE(registered_events_.find(event_code) != registered_events_.end());
+ registered_events_[event_code].Run(event);
+ }
+
+ void ListDependencies(ModuleList* list) override {}
+ void Start() override {}
+ void Stop() override {}
+
+ private:
+ std::map<EventCode, common::Callback<void(EventPacketView)>> registered_events_;
+ std::queue<std::unique_ptr<CommandQueueEntry>> command_queue_;
+};
+
+class ClassicSecurityManagerTest : public ::testing::Test, public ::bluetooth::hci::ClassicSecurityCommandCallbacks {
+ protected:
+ void SetUp() override {
+ test_hci_layer_ = new TestHciLayer;
+ handler_ = new Handler(&thread_);
+ fake_registry_.InjectTestModule(&TestHciLayer::Factory, test_hci_layer_);
+ fake_registry_.Start<ClassicSecurityManager>(&thread_);
+ classic_security_manager_ =
+ static_cast<ClassicSecurityManager*>(fake_registry_.GetModuleUnderTest(&ClassicSecurityManager::Factory));
+ classic_security_manager_->RegisterCallbacks(this, handler_);
+ test_hci_layer_->RegisterEventHandler(
+ EventCode::COMMAND_COMPLETE, base::Bind(&ClassicSecurityManagerTest::ExpectCommand, common::Unretained(this)),
+ nullptr);
+ test_hci_layer_->RegisterEventHandler(
+ EventCode::COMMAND_STATUS,
+ base::Bind(&ClassicSecurityManagerTest::ExpectCommandStatus, common::Unretained(this)), nullptr);
+
+ Address::FromString("A1:A2:A3:A4:A5:A6", remote);
+ }
+
+ void TearDown() override {
+ handler_->Clear();
+ delete handler_;
+ fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20));
+ fake_registry_.StopAll();
+ command_complete_ = false;
+ }
+
+ void ExpectCommand(EventPacketView packet) {
+ CommandCompleteView command_complete_view = CommandCompleteView::Create(std::move(packet));
+ auto last_command_queue_entry = test_hci_layer_->GetLastCommand();
+ auto last_command = std::move(last_command_queue_entry->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ CommandPacketView command_packet_view = CommandPacketView::Create(command_packet);
+
+ // verify command complete event match last command opcode
+ EXPECT_TRUE(command_packet_view.IsValid());
+ EXPECT_TRUE(command_complete_view.IsValid());
+ EXPECT_EQ(command_packet_view.GetOpCode(), command_complete_view.GetCommandOpCode());
+
+ // verify callback triggered
+ auto caller_handler = last_command_queue_entry->caller_handler;
+ caller_handler->Post(BindOnce(std::move(last_command_queue_entry->on_complete), std::move(command_complete_view)));
+ std::unique_lock<std::mutex> lock(mutex_);
+ EXPECT_FALSE(callback_done.wait_for(lock, std::chrono::seconds(3)) == std::cv_status::timeout);
+
+ command_complete_ = true;
+ }
+
+ void ExpectCommandStatus(EventPacketView packet) {
+ CommandStatusView command_status_view = CommandStatusView::Create(std::move(packet));
+ auto last_command_queue_entry = test_hci_layer_->GetLastCommand();
+ auto last_command = std::move(last_command_queue_entry->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ CommandPacketView command_packet_view = CommandPacketView::Create(command_packet);
+
+ // verify command complete event match last command opcode
+ EXPECT_TRUE(command_packet_view.IsValid());
+ EXPECT_TRUE(command_status_view.IsValid());
+ EXPECT_EQ(command_packet_view.GetOpCode(), command_status_view.GetCommandOpCode());
+
+ command_complete_ = true;
+ }
+
+ void OnCommandComplete(CommandCompleteView status) override {
+ callback_done.notify_one();
+ }
+
+ TestModuleRegistry fake_registry_;
+ TestHciLayer* test_hci_layer_ = nullptr;
+ os::Thread& thread_ = fake_registry_.GetTestThread();
+ Handler* handler_ = nullptr;
+ ClassicSecurityManager* classic_security_manager_ = nullptr;
+ Address remote;
+ mutable std::mutex mutex_;
+ std::condition_variable callback_done;
+ bool command_complete_ = false;
+};
+
+TEST_F(ClassicSecurityManagerTest, startup_teardown) {}
+
+TEST_F(ClassicSecurityManagerTest, send_link_key_request_reply) {
+ common::LinkKey link_key;
+ common::LinkKey::FromString("4c68384139f574d836bcf34e9dfb01bf\0", link_key);
+ classic_security_manager_->LinkKeyRequestReply(remote, link_key);
+ EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+ auto payload = std::make_unique<RawBuilder>();
+ test_hci_layer_->IncomingEvent(
+ CommandCompleteBuilder::Create(0x01, OpCode::LINK_KEY_REQUEST_REPLY, std::move(payload)));
+ EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_link_key_request_negative_reply) {
+ classic_security_manager_->LinkKeyRequestNegativeReply(remote);
+ EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+ auto payload = std::make_unique<RawBuilder>();
+ test_hci_layer_->IncomingEvent(
+ CommandCompleteBuilder::Create(0x01, OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY, std::move(payload)));
+ EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_pin_code_request_reply) {
+ classic_security_manager_->PinCodeRequestReply(remote, 6, "123456");
+ EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+ auto payload = std::make_unique<RawBuilder>();
+ test_hci_layer_->IncomingEvent(
+ CommandCompleteBuilder::Create(0x01, OpCode::PIN_CODE_REQUEST_REPLY, std::move(payload)));
+ EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_pin_code_request_negative_reply) {
+ classic_security_manager_->PinCodeRequestNegativeReply(remote);
+ EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+ auto payload = std::make_unique<RawBuilder>();
+ test_hci_layer_->IncomingEvent(
+ CommandCompleteBuilder::Create(0x01, OpCode::PIN_CODE_REQUEST_NEGATIVE_REPLY, std::move(payload)));
+ EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_io_capability_request_reply) {
+ IoCapability io_capability = (IoCapability)0x00;
+ OobDataPresent oob_present = (OobDataPresent)0x00;
+ AuthenticationRequirements authentication_requirements = (AuthenticationRequirements)0x00;
+ classic_security_manager_->IoCapabilityRequestReply(remote, io_capability, oob_present, authentication_requirements);
+ EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+ auto payload = std::make_unique<RawBuilder>();
+ test_hci_layer_->IncomingEvent(
+ CommandCompleteBuilder::Create(0x01, OpCode::IO_CAPABILITY_REQUEST_REPLY, std::move(payload)));
+ EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_io_capability_request_negative_reply) {
+ ErrorCode reason = (ErrorCode)0x01;
+ classic_security_manager_->IoCapabilityRequestNegativeReply(remote, reason);
+ EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+ auto payload = std::make_unique<RawBuilder>();
+ test_hci_layer_->IncomingEvent(
+ CommandCompleteBuilder::Create(0x01, OpCode::IO_CAPABILITY_REQUEST_NEGATIVE_REPLY, std::move(payload)));
+ EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_user_confirmation_request_reply) {
+ classic_security_manager_->UserConfirmationRequestReply(remote);
+ EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+ auto payload = std::make_unique<RawBuilder>();
+ test_hci_layer_->IncomingEvent(
+ CommandCompleteBuilder::Create(0x01, OpCode::USER_CONFIRMATION_REQUEST_REPLY, std::move(payload)));
+ EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_user_confirmation_request_negative_reply) {
+ classic_security_manager_->UserConfirmationRequestNegativeReply(remote);
+ EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+ auto payload = std::make_unique<RawBuilder>();
+ test_hci_layer_->IncomingEvent(
+ CommandCompleteBuilder::Create(0x01, OpCode::USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY, std::move(payload)));
+ EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_user_passkey_request_reply) {
+ classic_security_manager_->UserPasskeyRequestReply(remote, 999999);
+ EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+ auto payload = std::make_unique<RawBuilder>();
+ test_hci_layer_->IncomingEvent(
+ CommandCompleteBuilder::Create(0x01, OpCode::USER_PASSKEY_REQUEST_REPLY, std::move(payload)));
+ EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_user_passkey_request_negative_reply) {
+ classic_security_manager_->UserPasskeyRequestNegativeReply(remote);
+ EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+ auto payload = std::make_unique<RawBuilder>();
+ test_hci_layer_->IncomingEvent(
+ CommandCompleteBuilder::Create(0x01, OpCode::USER_PASSKEY_REQUEST_NEGATIVE_REPLY, std::move(payload)));
+ EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_remote_oob_data_request_reply) {
+ std::array<uint8_t, 16> c;
+ std::array<uint8_t, 16> r;
+ for (int i = 0; i < 16; i++) {
+ c[i] = (uint8_t)i;
+ r[i] = (uint8_t)i + 16;
+ }
+ classic_security_manager_->RemoteOobDataRequestReply(remote, c, r);
+ EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+ auto payload = std::make_unique<RawBuilder>();
+ test_hci_layer_->IncomingEvent(
+ CommandCompleteBuilder::Create(0x01, OpCode::REMOTE_OOB_DATA_REQUEST_REPLY, std::move(payload)));
+ EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_remote_oob_data_request_negative_reply) {
+ classic_security_manager_->RemoteOobDataRequestNegativeReply(remote);
+ EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+ auto payload = std::make_unique<RawBuilder>();
+ test_hci_layer_->IncomingEvent(
+ CommandCompleteBuilder::Create(0x01, OpCode::REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY, std::move(payload)));
+ EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_read_stored_link_key) {
+ ReadStoredLinkKeyReadAllFlag read_all_flag = (ReadStoredLinkKeyReadAllFlag)0x01;
+ classic_security_manager_->ReadStoredLinkKey(remote, read_all_flag);
+ EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+ auto payload = std::make_unique<RawBuilder>();
+ test_hci_layer_->IncomingEvent(
+ CommandCompleteBuilder::Create(0x01, OpCode::READ_STORED_LINK_KEY, std::move(payload)));
+ EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_delete_stored_link_key) {
+ DeleteStoredLinkKeyDeleteAllFlag delete_all_flag = (DeleteStoredLinkKeyDeleteAllFlag)0x01;
+ classic_security_manager_->DeleteStoredLinkKey(remote, delete_all_flag);
+ EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+ auto payload = std::make_unique<RawBuilder>();
+ test_hci_layer_->IncomingEvent(
+ CommandCompleteBuilder::Create(0x01, OpCode::DELETE_STORED_LINK_KEY, std::move(payload)));
+ EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_refresh_encryption_key) {
+ classic_security_manager_->RefreshEncryptionKey(0x01);
+ EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+ auto payload = std::make_unique<RawBuilder>();
+ test_hci_layer_->IncomingEvent(
+ CommandStatusBuilder::Create(ErrorCode::SUCCESS, 0x01, OpCode::REFRESH_ENCRYPTION_KEY, std::move(payload)));
+ EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_read_simple_pairing_mode) {
+ classic_security_manager_->ReadSimplePairingMode();
+ EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+ auto payload = std::make_unique<RawBuilder>();
+ test_hci_layer_->IncomingEvent(
+ CommandCompleteBuilder::Create(0x01, OpCode::READ_SIMPLE_PAIRING_MODE, std::move(payload)));
+ EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_write_simple_pairing_mode) {
+ Enable simple_pairing_mode = (Enable)0x01;
+ classic_security_manager_->WriteSimplePairingMode(simple_pairing_mode);
+ EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+ auto payload = std::make_unique<RawBuilder>();
+ test_hci_layer_->IncomingEvent(
+ CommandCompleteBuilder::Create(0x01, OpCode::WRITE_SIMPLE_PAIRING_MODE, std::move(payload)));
+ EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_read_local_oob_data) {
+ classic_security_manager_->ReadLocalOobData();
+ EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+ auto payload = std::make_unique<RawBuilder>();
+ test_hci_layer_->IncomingEvent(CommandCompleteBuilder::Create(0x01, OpCode::READ_LOCAL_OOB_DATA, std::move(payload)));
+ EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_keypress_notification) {
+ KeypressNotificationType notification_type = (KeypressNotificationType)0x01;
+ classic_security_manager_->SendKeypressNotification(remote, notification_type);
+ EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+ auto payload = std::make_unique<RawBuilder>();
+ test_hci_layer_->IncomingEvent(
+ CommandCompleteBuilder::Create(0x01, OpCode::SEND_KEYPRESS_NOTIFICATION, std::move(payload)));
+ EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_read_local_oob_extended_data) {
+ classic_security_manager_->ReadLocalOobExtendedData();
+ EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+ auto payload = std::make_unique<RawBuilder>();
+ test_hci_layer_->IncomingEvent(
+ CommandCompleteBuilder::Create(0x01, OpCode::READ_LOCAL_OOB_EXTENDED_DATA, std::move(payload)));
+ EXPECT_TRUE(command_complete_);
+}
+
+TEST_F(ClassicSecurityManagerTest, send_read_encryption_key_size) {
+ classic_security_manager_->ReadEncryptionKeySize(0x01);
+ EXPECT_TRUE(fake_registry_.SynchronizeModuleHandler(&ClassicSecurityManager::Factory, std::chrono::milliseconds(20)));
+
+ auto payload = std::make_unique<RawBuilder>();
+ test_hci_layer_->IncomingEvent(
+ CommandCompleteBuilder::Create(0x01, OpCode::READ_ENCRYPTION_KEY_SIZE, std::move(payload)));
+ EXPECT_TRUE(command_complete_);
+}
+
+} // namespace
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/controller.cc b/gd/hci/controller.cc
new file mode 100644
index 0000000..1bd6150
--- /dev/null
+++ b/gd/hci/controller.cc
@@ -0,0 +1,866 @@
+/*
+ * Copyright 2019 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 "hci/controller.h"
+
+#include <future>
+#include <memory>
+#include <utility>
+
+#include "common/bind.h"
+#include "common/callback.h"
+#include "hci/hci_layer.h"
+
+namespace bluetooth {
+namespace hci {
+
+using common::Bind;
+using common::BindOnce;
+using common::Callback;
+using common::Closure;
+using common::OnceCallback;
+using common::OnceClosure;
+using os::Handler;
+
+struct Controller::impl {
+ impl(Controller& module) : module_(module) {}
+
+ void Start(hci::HciLayer* hci) {
+ hci_ = hci;
+ hci_->RegisterEventHandler(EventCode::NUMBER_OF_COMPLETED_PACKETS,
+ Bind(&Controller::impl::NumberOfCompletedPackets, common::Unretained(this)),
+ module_.GetHandler());
+
+ hci_->EnqueueCommand(ReadLocalNameBuilder::Create(),
+ BindOnce(&Controller::impl::read_local_name_complete_handler, common::Unretained(this)),
+ module_.GetHandler());
+ hci_->EnqueueCommand(
+ ReadLocalVersionInformationBuilder::Create(),
+ BindOnce(&Controller::impl::read_local_version_information_complete_handler, common::Unretained(this)),
+ module_.GetHandler());
+ hci_->EnqueueCommand(
+ ReadLocalSupportedCommandsBuilder::Create(),
+ BindOnce(&Controller::impl::read_local_supported_commands_complete_handler, common::Unretained(this)),
+ module_.GetHandler());
+ hci_->EnqueueCommand(
+ ReadLocalSupportedFeaturesBuilder::Create(),
+ BindOnce(&Controller::impl::read_local_supported_features_complete_handler, common::Unretained(this)),
+ module_.GetHandler());
+
+ // Wait for all extended features read
+ std::promise<void> features_promise;
+ auto features_future = features_promise.get_future();
+ hci_->EnqueueCommand(ReadLocalExtendedFeaturesBuilder::Create(0x00),
+ BindOnce(&Controller::impl::read_local_extended_features_complete_handler,
+ common::Unretained(this), std::move(features_promise)),
+ module_.GetHandler());
+ features_future.wait();
+
+ hci_->EnqueueCommand(ReadBufferSizeBuilder::Create(),
+ BindOnce(&Controller::impl::read_buffer_size_complete_handler, common::Unretained(this)),
+ module_.GetHandler());
+
+ hci_->EnqueueCommand(LeReadBufferSizeBuilder::Create(),
+ BindOnce(&Controller::impl::le_read_buffer_size_handler, common::Unretained(this)),
+ module_.GetHandler());
+
+ hci_->EnqueueCommand(
+ LeReadLocalSupportedFeaturesBuilder::Create(),
+ BindOnce(&Controller::impl::le_read_local_supported_features_handler, common::Unretained(this)),
+ module_.GetHandler());
+
+ hci_->EnqueueCommand(LeReadSupportedStatesBuilder::Create(),
+ BindOnce(&Controller::impl::le_read_supported_states_handler, common::Unretained(this)),
+ module_.GetHandler());
+
+ if (is_supported(OpCode::LE_READ_MAXIMUM_DATA_LENGTH)) {
+ hci_->EnqueueCommand(LeReadMaximumDataLengthBuilder::Create(),
+ BindOnce(&Controller::impl::le_read_maximum_data_length_handler, common::Unretained(this)),
+ module_.GetHandler());
+ }
+ if (is_supported(OpCode::LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH)) {
+ hci_->EnqueueCommand(
+ LeReadMaximumAdvertisingDataLengthBuilder::Create(),
+ BindOnce(&Controller::impl::le_read_maximum_advertising_data_length_handler, common::Unretained(this)),
+ module_.GetHandler());
+ }
+ if (is_supported(OpCode::LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS)) {
+ hci_->EnqueueCommand(
+ LeReadNumberOfSupportedAdvertisingSetsBuilder::Create(),
+ BindOnce(&Controller::impl::le_read_number_of_supported_advertising_sets_handler, common::Unretained(this)),
+ module_.GetHandler());
+ }
+
+ hci_->EnqueueCommand(LeGetVendorCapabilitiesBuilder::Create(),
+ BindOnce(&Controller::impl::le_get_vendor_capabilities_handler, common::Unretained(this)),
+ module_.GetHandler());
+
+ // We only need to synchronize the last read. Make BD_ADDR to be the last one.
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ hci_->EnqueueCommand(
+ ReadBdAddrBuilder::Create(),
+ BindOnce(&Controller::impl::read_controller_mac_address_handler, common::Unretained(this), std::move(promise)),
+ module_.GetHandler());
+ future.wait();
+ }
+
+ void Stop() {
+ hci_->UnregisterEventHandler(EventCode::NUMBER_OF_COMPLETED_PACKETS);
+ hci_ = nullptr;
+ }
+
+ void NumberOfCompletedPackets(EventPacketView event) {
+ ASSERT(acl_credits_handler_ != nullptr);
+ auto complete_view = NumberOfCompletedPacketsView::Create(event);
+ ASSERT(complete_view.IsValid());
+ for (auto completed_packets : complete_view.GetCompletedPackets()) {
+ uint16_t handle = completed_packets.connection_handle_;
+ uint16_t credits = completed_packets.host_num_of_completed_packets_;
+ acl_credits_handler_->Post(Bind(acl_credits_callback_, handle, credits));
+ }
+ }
+
+ void RegisterCompletedAclPacketsCallback(Callback<void(uint16_t /* handle */, uint16_t /* packets */)> cb,
+ Handler* handler) {
+ ASSERT(acl_credits_handler_ == nullptr);
+ acl_credits_callback_ = cb;
+ acl_credits_handler_ = handler;
+ }
+
+ void read_local_name_complete_handler(CommandCompleteView view) {
+ auto complete_view = ReadLocalNameCompleteView::Create(view);
+ ASSERT(complete_view.IsValid());
+ ErrorCode status = complete_view.GetStatus();
+ ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+ std::array<uint8_t, 248> local_name_array = complete_view.GetLocalName();
+
+ local_name_ = std::string(local_name_array.begin(), local_name_array.end());
+ // erase \0
+ local_name_.erase(std::find(local_name_.begin(), local_name_.end(), '\0'), local_name_.end());
+ }
+
+ void read_local_version_information_complete_handler(CommandCompleteView view) {
+ auto complete_view = ReadLocalVersionInformationCompleteView::Create(view);
+ ASSERT(complete_view.IsValid());
+ ErrorCode status = complete_view.GetStatus();
+ ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+
+ local_version_information_ = complete_view.GetLocalVersionInformation();
+ }
+
+ void read_local_supported_commands_complete_handler(CommandCompleteView view) {
+ auto complete_view = ReadLocalSupportedCommandsCompleteView::Create(view);
+ ASSERT(complete_view.IsValid());
+ ErrorCode status = complete_view.GetStatus();
+ ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+ local_supported_commands_ = complete_view.GetSupportedCommands();
+ }
+
+ void read_local_supported_features_complete_handler(CommandCompleteView view) {
+ auto complete_view = ReadLocalSupportedFeaturesCompleteView::Create(view);
+ ASSERT(complete_view.IsValid());
+ ErrorCode status = complete_view.GetStatus();
+ ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+ local_supported_features_ = complete_view.GetLmpFeatures();
+ }
+
+ void read_local_extended_features_complete_handler(std::promise<void> promise, CommandCompleteView view) {
+ auto complete_view = ReadLocalExtendedFeaturesCompleteView::Create(view);
+ ASSERT(complete_view.IsValid());
+ ErrorCode status = complete_view.GetStatus();
+ ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+ uint8_t page_number = complete_view.GetPageNumber();
+ maximum_page_number_ = complete_view.GetMaximumPageNumber();
+ extended_lmp_features_array_.push_back(complete_view.GetExtendedLmpFeatures());
+
+ // Query all extended features
+ if (page_number < maximum_page_number_) {
+ page_number++;
+ hci_->EnqueueCommand(ReadLocalExtendedFeaturesBuilder::Create(page_number),
+ BindOnce(&Controller::impl::read_local_extended_features_complete_handler,
+ common::Unretained(this), std::move(promise)),
+ module_.GetHandler());
+ } else {
+ promise.set_value();
+ }
+ }
+
+ void read_buffer_size_complete_handler(CommandCompleteView view) {
+ auto complete_view = ReadBufferSizeCompleteView::Create(view);
+ ASSERT(complete_view.IsValid());
+ ErrorCode status = complete_view.GetStatus();
+ ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+ acl_buffer_length_ = complete_view.GetAclDataPacketLength();
+ acl_buffers_ = complete_view.GetTotalNumAclDataPackets();
+
+ sco_buffer_length_ = complete_view.GetSynchronousDataPacketLength();
+ sco_buffers_ = complete_view.GetTotalNumSynchronousDataPackets();
+ }
+
+ void read_controller_mac_address_handler(std::promise<void> promise, CommandCompleteView view) {
+ auto complete_view = ReadBdAddrCompleteView::Create(view);
+ ASSERT(complete_view.IsValid());
+ ErrorCode status = complete_view.GetStatus();
+ ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+ mac_address_ = complete_view.GetBdAddr();
+ promise.set_value();
+ }
+
+ void le_read_buffer_size_handler(CommandCompleteView view) {
+ auto complete_view = LeReadBufferSizeCompleteView::Create(view);
+ ASSERT(complete_view.IsValid());
+ ErrorCode status = complete_view.GetStatus();
+ ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+ le_buffer_size_ = complete_view.GetLeBufferSize();
+ }
+
+ void le_read_local_supported_features_handler(CommandCompleteView view) {
+ auto complete_view = LeReadLocalSupportedFeaturesCompleteView::Create(view);
+ ASSERT(complete_view.IsValid());
+ ErrorCode status = complete_view.GetStatus();
+ ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+ le_local_supported_features_ = complete_view.GetLeFeatures();
+ }
+
+ void le_read_supported_states_handler(CommandCompleteView view) {
+ auto complete_view = LeReadSupportedStatesCompleteView::Create(view);
+ ASSERT(complete_view.IsValid());
+ ErrorCode status = complete_view.GetStatus();
+ ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+ le_supported_states_ = complete_view.GetLeStates();
+ }
+
+ void le_read_maximum_data_length_handler(CommandCompleteView view) {
+ auto complete_view = LeReadMaximumDataLengthCompleteView::Create(view);
+ ASSERT(complete_view.IsValid());
+ ErrorCode status = complete_view.GetStatus();
+ ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+ le_maximum_data_length_ = complete_view.GetLeMaximumDataLength();
+ }
+
+ void le_read_maximum_advertising_data_length_handler(CommandCompleteView view) {
+ auto complete_view = LeReadMaximumAdvertisingDataLengthCompleteView::Create(view);
+ ASSERT(complete_view.IsValid());
+ ErrorCode status = complete_view.GetStatus();
+ ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+ le_maximum_advertising_data_length_ = complete_view.GetMaximumAdvertisingDataLength();
+ }
+
+ void le_read_number_of_supported_advertising_sets_handler(CommandCompleteView view) {
+ auto complete_view = LeReadNumberOfSupportedAdvertisingSetsCompleteView::Create(view);
+ ASSERT(complete_view.IsValid());
+ ErrorCode status = complete_view.GetStatus();
+ ASSERT_LOG(status == ErrorCode::SUCCESS, "Status 0x%02hhx, %s", status, ErrorCodeText(status).c_str());
+ le_number_supported_advertising_sets_ = complete_view.GetNumberSupportedAdvertisingSets();
+ }
+
+ void le_get_vendor_capabilities_handler(CommandCompleteView view) {
+ auto complete_view = LeGetVendorCapabilitiesCompleteView::Create(view);
+
+ vendor_capabilities_.is_supported_ = 0x00;
+ vendor_capabilities_.max_advt_instances_ = 0x00;
+ vendor_capabilities_.offloaded_resolution_of_private_address_ = 0x00;
+ vendor_capabilities_.total_scan_results_storage_ = 0x00;
+ vendor_capabilities_.max_irk_list_sz_ = 0x00;
+ vendor_capabilities_.filtering_support_ = 0x00;
+ vendor_capabilities_.max_filter_ = 0x00;
+ vendor_capabilities_.activity_energy_info_support_ = 0x00;
+ vendor_capabilities_.version_supported_ = 0x00;
+ vendor_capabilities_.version_supported_ = 0x00;
+ vendor_capabilities_.total_num_of_advt_tracked_ = 0x00;
+ vendor_capabilities_.extended_scan_support_ = 0x00;
+ vendor_capabilities_.debug_logging_supported_ = 0x00;
+ vendor_capabilities_.le_address_generation_offloading_support_ = 0x00;
+ vendor_capabilities_.a2dp_source_offload_capability_mask_ = 0x00;
+ vendor_capabilities_.bluetooth_quality_report_support_ = 0x00;
+
+ if (complete_view.IsValid()) {
+ vendor_capabilities_.is_supported_ = 0x01;
+
+ // v0.55
+ BaseVendorCapabilities base_vendor_capabilities = complete_view.GetBaseVendorCapabilities();
+ vendor_capabilities_.max_advt_instances_ = base_vendor_capabilities.max_advt_instances_;
+ vendor_capabilities_.offloaded_resolution_of_private_address_ =
+ base_vendor_capabilities.offloaded_resolution_of_private_address_;
+ vendor_capabilities_.total_scan_results_storage_ = base_vendor_capabilities.total_scan_results_storage_;
+ vendor_capabilities_.max_irk_list_sz_ = base_vendor_capabilities.max_irk_list_sz_;
+ vendor_capabilities_.filtering_support_ = base_vendor_capabilities.filtering_support_;
+ vendor_capabilities_.max_filter_ = base_vendor_capabilities.max_filter_;
+ vendor_capabilities_.activity_energy_info_support_ = base_vendor_capabilities.activity_energy_info_support_;
+ if (complete_view.GetPayload().size() == 0) {
+ vendor_capabilities_.version_supported_ = 55;
+ return;
+ }
+
+ // v0.95
+ auto v95 = LeGetVendorCapabilitiesComplete095View::Create(complete_view);
+ if (!v95.IsValid()) {
+ LOG_ERROR("invalid data for hci requirements v0.95");
+ return;
+ }
+ vendor_capabilities_.version_supported_ = v95.GetVersionSupported();
+ vendor_capabilities_.total_num_of_advt_tracked_ = v95.GetTotalNumOfAdvtTracked();
+ vendor_capabilities_.extended_scan_support_ = v95.GetExtendedScanSupport();
+ vendor_capabilities_.debug_logging_supported_ = v95.GetDebugLoggingSupported();
+ if (vendor_capabilities_.version_supported_ <= 95 || complete_view.GetPayload().size() == 0) {
+ return;
+ }
+
+ // v0.96
+ auto v96 = LeGetVendorCapabilitiesComplete096View::Create(v95);
+ if (!v96.IsValid()) {
+ LOG_ERROR("invalid data for hci requirements v0.96");
+ return;
+ }
+ vendor_capabilities_.le_address_generation_offloading_support_ = v96.GetLeAddressGenerationOffloadingSupport();
+ if (vendor_capabilities_.version_supported_ <= 96 || complete_view.GetPayload().size() == 0) {
+ return;
+ }
+
+ // v0.98
+ auto v98 = LeGetVendorCapabilitiesComplete098View::Create(v96);
+ if (!v98.IsValid()) {
+ LOG_ERROR("invalid data for hci requirements v0.98");
+ return;
+ }
+ vendor_capabilities_.a2dp_source_offload_capability_mask_ = v98.GetA2dpSourceOffloadCapabilityMask();
+ vendor_capabilities_.bluetooth_quality_report_support_ = v98.GetBluetoothQualityReportSupport();
+ }
+ }
+
+ void set_event_mask(uint64_t event_mask) {
+ std::unique_ptr<SetEventMaskBuilder> packet = SetEventMaskBuilder::Create(event_mask);
+ hci_->EnqueueCommand(std::move(packet),
+ BindOnce(&Controller::impl::check_status<SetEventMaskCompleteView>, common::Unretained(this)),
+ module_.GetHandler());
+ }
+
+ void reset() {
+ std::unique_ptr<ResetBuilder> packet = ResetBuilder::Create();
+ hci_->EnqueueCommand(std::move(packet),
+ BindOnce(&Controller::impl::check_status<ResetCompleteView>, common::Unretained(this)),
+ module_.GetHandler());
+ }
+
+ void set_event_filter(std::unique_ptr<SetEventFilterBuilder> packet) {
+ hci_->EnqueueCommand(
+ std::move(packet),
+ BindOnce(&Controller::impl::check_status<SetEventFilterCompleteView>, common::Unretained(this)),
+ module_.GetHandler());
+ }
+
+ void write_local_name(std::string local_name) {
+ ASSERT(local_name.length() <= 248);
+ // Fill remaining char with 0
+ local_name.append(std::string(248 - local_name.length(), '\0'));
+ std::array<uint8_t, 248> local_name_array;
+ std::copy(std::begin(local_name), std::end(local_name), std::begin(local_name_array));
+
+ std::unique_ptr<WriteLocalNameBuilder> packet = WriteLocalNameBuilder::Create(local_name_array);
+ hci_->EnqueueCommand(
+ std::move(packet),
+ BindOnce(&Controller::impl::check_status<WriteLocalNameCompleteView>, common::Unretained(this)),
+ module_.GetHandler());
+ }
+
+ void host_buffer_size(uint16_t host_acl_data_packet_length, uint8_t host_synchronous_data_packet_length,
+ uint16_t host_total_num_acl_data_packets, uint16_t host_total_num_synchronous_data_packets) {
+ std::unique_ptr<HostBufferSizeBuilder> packet =
+ HostBufferSizeBuilder::Create(host_acl_data_packet_length, host_synchronous_data_packet_length,
+ host_total_num_acl_data_packets, host_total_num_synchronous_data_packets);
+ hci_->EnqueueCommand(
+ std::move(packet),
+ BindOnce(&Controller::impl::check_status<HostBufferSizeCompleteView>, common::Unretained(this)),
+ module_.GetHandler());
+ }
+
+ void le_set_event_mask(uint64_t le_event_mask) {
+ std::unique_ptr<LeSetEventMaskBuilder> packet = LeSetEventMaskBuilder::Create(le_event_mask);
+ hci_->EnqueueCommand(
+ std::move(packet),
+ BindOnce(&Controller::impl::check_status<LeSetEventMaskCompleteView>, common::Unretained(this)),
+ module_.GetHandler());
+ }
+
+ template <class T>
+ void check_status(CommandCompleteView view) {
+ ASSERT(view.IsValid());
+ auto status_view = T::Create(view);
+ ASSERT(status_view.IsValid());
+ ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
+ }
+
+#define OP_CODE_MAPPING(name) \
+ case OpCode::name: { \
+ uint16_t index = (uint16_t)OpCodeIndex::name; \
+ uint16_t byte_index = index / 10; \
+ uint16_t bit_index = index % 10; \
+ bool supported = local_supported_commands_[byte_index] & (1 << bit_index); \
+ if (!supported) { \
+ LOG_WARN("unsupported command opcode: 0x%04x", (uint16_t)OpCode::name); \
+ } \
+ return supported; \
+ }
+
+ bool is_supported(OpCode op_code) {
+ switch (op_code) {
+ OP_CODE_MAPPING(INQUIRY)
+ OP_CODE_MAPPING(INQUIRY_CANCEL)
+ OP_CODE_MAPPING(PERIODIC_INQUIRY_MODE)
+ OP_CODE_MAPPING(EXIT_PERIODIC_INQUIRY_MODE)
+ OP_CODE_MAPPING(CREATE_CONNECTION)
+ OP_CODE_MAPPING(DISCONNECT)
+ OP_CODE_MAPPING(CREATE_CONNECTION_CANCEL)
+ OP_CODE_MAPPING(ACCEPT_CONNECTION_REQUEST)
+ OP_CODE_MAPPING(REJECT_CONNECTION_REQUEST)
+ OP_CODE_MAPPING(LINK_KEY_REQUEST_REPLY)
+ OP_CODE_MAPPING(LINK_KEY_REQUEST_NEGATIVE_REPLY)
+ OP_CODE_MAPPING(PIN_CODE_REQUEST_REPLY)
+ OP_CODE_MAPPING(PIN_CODE_REQUEST_NEGATIVE_REPLY)
+ OP_CODE_MAPPING(CHANGE_CONNECTION_PACKET_TYPE)
+ OP_CODE_MAPPING(AUTHENTICATION_REQUESTED)
+ OP_CODE_MAPPING(SET_CONNECTION_ENCRYPTION)
+ OP_CODE_MAPPING(CHANGE_CONNECTION_LINK_KEY)
+ OP_CODE_MAPPING(MASTER_LINK_KEY)
+ OP_CODE_MAPPING(REMOTE_NAME_REQUEST)
+ OP_CODE_MAPPING(REMOTE_NAME_REQUEST_CANCEL)
+ OP_CODE_MAPPING(READ_REMOTE_SUPPORTED_FEATURES)
+ OP_CODE_MAPPING(READ_REMOTE_EXTENDED_FEATURES)
+ OP_CODE_MAPPING(READ_REMOTE_VERSION_INFORMATION)
+ OP_CODE_MAPPING(READ_CLOCK_OFFSET)
+ OP_CODE_MAPPING(READ_LMP_HANDLE)
+ OP_CODE_MAPPING(HOLD_MODE)
+ OP_CODE_MAPPING(SNIFF_MODE)
+ OP_CODE_MAPPING(EXIT_SNIFF_MODE)
+ OP_CODE_MAPPING(QOS_SETUP)
+ OP_CODE_MAPPING(ROLE_DISCOVERY)
+ OP_CODE_MAPPING(SWITCH_ROLE)
+ OP_CODE_MAPPING(READ_LINK_POLICY_SETTINGS)
+ OP_CODE_MAPPING(WRITE_LINK_POLICY_SETTINGS)
+ OP_CODE_MAPPING(READ_DEFAULT_LINK_POLICY_SETTINGS)
+ OP_CODE_MAPPING(WRITE_DEFAULT_LINK_POLICY_SETTINGS)
+ OP_CODE_MAPPING(FLOW_SPECIFICATION)
+ OP_CODE_MAPPING(SET_EVENT_MASK)
+ OP_CODE_MAPPING(RESET)
+ OP_CODE_MAPPING(SET_EVENT_FILTER)
+ OP_CODE_MAPPING(FLUSH)
+ OP_CODE_MAPPING(READ_PIN_TYPE)
+ OP_CODE_MAPPING(WRITE_PIN_TYPE)
+ OP_CODE_MAPPING(READ_STORED_LINK_KEY)
+ OP_CODE_MAPPING(WRITE_STORED_LINK_KEY)
+ OP_CODE_MAPPING(DELETE_STORED_LINK_KEY)
+ OP_CODE_MAPPING(WRITE_LOCAL_NAME)
+ OP_CODE_MAPPING(READ_LOCAL_NAME)
+ OP_CODE_MAPPING(READ_CONNECTION_ACCEPT_TIMEOUT)
+ OP_CODE_MAPPING(WRITE_CONNECTION_ACCEPT_TIMEOUT)
+ OP_CODE_MAPPING(READ_PAGE_TIMEOUT)
+ OP_CODE_MAPPING(WRITE_PAGE_TIMEOUT)
+ OP_CODE_MAPPING(READ_SCAN_ENABLE)
+ OP_CODE_MAPPING(WRITE_SCAN_ENABLE)
+ OP_CODE_MAPPING(READ_PAGE_SCAN_ACTIVITY)
+ OP_CODE_MAPPING(WRITE_PAGE_SCAN_ACTIVITY)
+ OP_CODE_MAPPING(READ_INQUIRY_SCAN_ACTIVITY)
+ OP_CODE_MAPPING(WRITE_INQUIRY_SCAN_ACTIVITY)
+ OP_CODE_MAPPING(READ_AUTHENTICATION_ENABLE)
+ OP_CODE_MAPPING(WRITE_AUTHENTICATION_ENABLE)
+ OP_CODE_MAPPING(READ_CLASS_OF_DEVICE)
+ OP_CODE_MAPPING(WRITE_CLASS_OF_DEVICE)
+ OP_CODE_MAPPING(READ_VOICE_SETTING)
+ OP_CODE_MAPPING(WRITE_VOICE_SETTING)
+ OP_CODE_MAPPING(READ_AUTOMATIC_FLUSH_TIMEOUT)
+ OP_CODE_MAPPING(WRITE_AUTOMATIC_FLUSH_TIMEOUT)
+ OP_CODE_MAPPING(READ_NUM_BROADCAST_RETRANSMITS)
+ OP_CODE_MAPPING(WRITE_NUM_BROADCAST_RETRANSMITS)
+ OP_CODE_MAPPING(READ_HOLD_MODE_ACTIVITY)
+ OP_CODE_MAPPING(WRITE_HOLD_MODE_ACTIVITY)
+ OP_CODE_MAPPING(READ_TRANSMIT_POWER_LEVEL)
+ OP_CODE_MAPPING(READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE)
+ OP_CODE_MAPPING(WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE)
+ OP_CODE_MAPPING(SET_CONTROLLER_TO_HOST_FLOW_CONTROL)
+ OP_CODE_MAPPING(HOST_BUFFER_SIZE)
+ OP_CODE_MAPPING(HOST_NUM_COMPLETED_PACKETS)
+ OP_CODE_MAPPING(READ_LINK_SUPERVISION_TIMEOUT)
+ OP_CODE_MAPPING(WRITE_LINK_SUPERVISION_TIMEOUT)
+ OP_CODE_MAPPING(READ_NUMBER_OF_SUPPORTED_IAC)
+ OP_CODE_MAPPING(READ_CURRENT_IAC_LAP)
+ OP_CODE_MAPPING(WRITE_CURRENT_IAC_LAP)
+ OP_CODE_MAPPING(SET_AFH_HOST_CHANNEL_CLASSIFICATION)
+ OP_CODE_MAPPING(READ_INQUIRY_SCAN_TYPE)
+ OP_CODE_MAPPING(WRITE_INQUIRY_SCAN_TYPE)
+ OP_CODE_MAPPING(READ_INQUIRY_MODE)
+ OP_CODE_MAPPING(WRITE_INQUIRY_MODE)
+ OP_CODE_MAPPING(READ_PAGE_SCAN_TYPE)
+ OP_CODE_MAPPING(WRITE_PAGE_SCAN_TYPE)
+ OP_CODE_MAPPING(READ_AFH_CHANNEL_ASSESSMENT_MODE)
+ OP_CODE_MAPPING(WRITE_AFH_CHANNEL_ASSESSMENT_MODE)
+ OP_CODE_MAPPING(READ_LOCAL_VERSION_INFORMATION)
+ OP_CODE_MAPPING(READ_LOCAL_SUPPORTED_FEATURES)
+ OP_CODE_MAPPING(READ_LOCAL_EXTENDED_FEATURES)
+ OP_CODE_MAPPING(READ_BUFFER_SIZE)
+ OP_CODE_MAPPING(READ_BD_ADDR)
+ OP_CODE_MAPPING(READ_FAILED_CONTACT_COUNTER)
+ OP_CODE_MAPPING(RESET_FAILED_CONTACT_COUNTER)
+ OP_CODE_MAPPING(READ_LINK_QUALITY)
+ OP_CODE_MAPPING(READ_RSSI)
+ OP_CODE_MAPPING(READ_AFH_CHANNEL_MAP)
+ OP_CODE_MAPPING(READ_CLOCK)
+ OP_CODE_MAPPING(READ_LOOPBACK_MODE)
+ OP_CODE_MAPPING(WRITE_LOOPBACK_MODE)
+ OP_CODE_MAPPING(ENABLE_DEVICE_UNDER_TEST_MODE)
+ OP_CODE_MAPPING(SETUP_SYNCHRONOUS_CONNECTION)
+ OP_CODE_MAPPING(ACCEPT_SYNCHRONOUS_CONNECTION)
+ OP_CODE_MAPPING(REJECT_SYNCHRONOUS_CONNECTION)
+ OP_CODE_MAPPING(READ_EXTENDED_INQUIRY_RESPONSE)
+ OP_CODE_MAPPING(WRITE_EXTENDED_INQUIRY_RESPONSE)
+ OP_CODE_MAPPING(REFRESH_ENCRYPTION_KEY)
+ OP_CODE_MAPPING(SNIFF_SUBRATING)
+ OP_CODE_MAPPING(READ_SIMPLE_PAIRING_MODE)
+ OP_CODE_MAPPING(WRITE_SIMPLE_PAIRING_MODE)
+ OP_CODE_MAPPING(READ_LOCAL_OOB_DATA)
+ OP_CODE_MAPPING(READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL)
+ OP_CODE_MAPPING(WRITE_INQUIRY_TRANSMIT_POWER_LEVEL)
+ OP_CODE_MAPPING(IO_CAPABILITY_REQUEST_REPLY)
+ OP_CODE_MAPPING(USER_CONFIRMATION_REQUEST_REPLY)
+ OP_CODE_MAPPING(USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY)
+ OP_CODE_MAPPING(USER_PASSKEY_REQUEST_REPLY)
+ OP_CODE_MAPPING(USER_PASSKEY_REQUEST_NEGATIVE_REPLY)
+ OP_CODE_MAPPING(REMOTE_OOB_DATA_REQUEST_REPLY)
+ OP_CODE_MAPPING(WRITE_SIMPLE_PAIRING_DEBUG_MODE)
+ OP_CODE_MAPPING(REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY)
+ OP_CODE_MAPPING(SEND_KEYPRESS_NOTIFICATION)
+ OP_CODE_MAPPING(IO_CAPABILITY_REQUEST_NEGATIVE_REPLY)
+ OP_CODE_MAPPING(READ_ENCRYPTION_KEY_SIZE)
+ OP_CODE_MAPPING(READ_DATA_BLOCK_SIZE)
+ OP_CODE_MAPPING(READ_LE_HOST_SUPPORT)
+ OP_CODE_MAPPING(WRITE_LE_HOST_SUPPORT)
+ OP_CODE_MAPPING(LE_SET_EVENT_MASK)
+ OP_CODE_MAPPING(LE_READ_BUFFER_SIZE)
+ OP_CODE_MAPPING(LE_READ_LOCAL_SUPPORTED_FEATURES)
+ OP_CODE_MAPPING(LE_SET_RANDOM_ADDRESS)
+ OP_CODE_MAPPING(LE_SET_ADVERTISING_PARAMETERS)
+ OP_CODE_MAPPING(LE_READ_ADVERTISING_CHANNEL_TX_POWER)
+ OP_CODE_MAPPING(LE_SET_ADVERTISING_DATA)
+ OP_CODE_MAPPING(LE_SET_SCAN_RESPONSE_DATA)
+ OP_CODE_MAPPING(LE_SET_ADVERTISING_ENABLE)
+ OP_CODE_MAPPING(LE_SET_SCAN_PARAMETERS)
+ OP_CODE_MAPPING(LE_SET_SCAN_ENABLE)
+ OP_CODE_MAPPING(LE_CREATE_CONNECTION)
+ OP_CODE_MAPPING(LE_CREATE_CONNECTION_CANCEL)
+ OP_CODE_MAPPING(LE_READ_WHITE_LIST_SIZE)
+ OP_CODE_MAPPING(LE_CLEAR_WHITE_LIST)
+ OP_CODE_MAPPING(LE_ADD_DEVICE_TO_WHITE_LIST)
+ OP_CODE_MAPPING(LE_REMOVE_DEVICE_FROM_WHITE_LIST)
+ OP_CODE_MAPPING(LE_CONNECTION_UPDATE)
+ OP_CODE_MAPPING(LE_SET_HOST_CHANNEL_CLASSIFICATION)
+ OP_CODE_MAPPING(LE_READ_CHANNEL_MAP)
+ OP_CODE_MAPPING(LE_READ_REMOTE_FEATURES)
+ OP_CODE_MAPPING(LE_ENCRYPT)
+ OP_CODE_MAPPING(LE_RAND)
+ OP_CODE_MAPPING(LE_START_ENCRYPTION)
+ OP_CODE_MAPPING(LE_LONG_TERM_KEY_REQUEST_REPLY)
+ OP_CODE_MAPPING(LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY)
+ OP_CODE_MAPPING(LE_READ_SUPPORTED_STATES)
+ OP_CODE_MAPPING(LE_RECEIVER_TEST)
+ OP_CODE_MAPPING(LE_TRANSMITTER_TEST)
+ OP_CODE_MAPPING(LE_TEST_END)
+ OP_CODE_MAPPING(ENHANCED_SETUP_SYNCHRONOUS_CONNECTION)
+ OP_CODE_MAPPING(ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION)
+ OP_CODE_MAPPING(READ_LOCAL_SUPPORTED_CODECS)
+ OP_CODE_MAPPING(READ_SECURE_CONNECTIONS_HOST_SUPPORT)
+ OP_CODE_MAPPING(WRITE_SECURE_CONNECTIONS_HOST_SUPPORT)
+ OP_CODE_MAPPING(READ_LOCAL_OOB_EXTENDED_DATA)
+ OP_CODE_MAPPING(WRITE_SECURE_CONNECTIONS_TEST_MODE)
+ OP_CODE_MAPPING(LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY)
+ OP_CODE_MAPPING(LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY)
+ OP_CODE_MAPPING(LE_SET_DATA_LENGTH)
+ OP_CODE_MAPPING(LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH)
+ OP_CODE_MAPPING(LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH)
+ OP_CODE_MAPPING(LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND)
+ OP_CODE_MAPPING(LE_GENERATE_DHKEY_COMMAND)
+ OP_CODE_MAPPING(LE_ADD_DEVICE_TO_RESOLVING_LIST)
+ OP_CODE_MAPPING(LE_REMOVE_DEVICE_FROM_RESOLVING_LIST)
+ OP_CODE_MAPPING(LE_CLEAR_RESOLVING_LIST)
+ OP_CODE_MAPPING(LE_READ_RESOLVING_LIST_SIZE)
+ OP_CODE_MAPPING(LE_READ_PEER_RESOLVABLE_ADDRESS)
+ OP_CODE_MAPPING(LE_READ_LOCAL_RESOLVABLE_ADDRESS)
+ OP_CODE_MAPPING(LE_SET_ADDRESS_RESOLUTION_ENABLE)
+ OP_CODE_MAPPING(LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT)
+ OP_CODE_MAPPING(LE_READ_MAXIMUM_DATA_LENGTH)
+ OP_CODE_MAPPING(LE_READ_PHY)
+ OP_CODE_MAPPING(LE_SET_DEFAULT_PHY)
+ OP_CODE_MAPPING(LE_SET_PHY)
+ OP_CODE_MAPPING(LE_ENHANCED_RECEIVER_TEST)
+ OP_CODE_MAPPING(LE_ENHANCED_TRANSMITTER_TEST)
+ OP_CODE_MAPPING(LE_SET_EXTENDED_ADVERTISING_RANDOM_ADDRESS)
+ OP_CODE_MAPPING(LE_SET_EXTENDED_ADVERTISING_PARAMETERS)
+ OP_CODE_MAPPING(LE_SET_EXTENDED_ADVERTISING_DATA)
+ OP_CODE_MAPPING(LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE)
+ OP_CODE_MAPPING(LE_SET_EXTENDED_ADVERTISING_ENABLE)
+ OP_CODE_MAPPING(LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH)
+ OP_CODE_MAPPING(LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS)
+ OP_CODE_MAPPING(LE_REMOVE_ADVERTISING_SET)
+ OP_CODE_MAPPING(LE_CLEAR_ADVERTISING_SETS)
+ OP_CODE_MAPPING(LE_SET_PERIODIC_ADVERTISING_PARAM)
+ OP_CODE_MAPPING(LE_SET_PERIODIC_ADVERTISING_DATA)
+ OP_CODE_MAPPING(LE_SET_PERIODIC_ADVERTISING_ENABLE)
+ OP_CODE_MAPPING(LE_SET_EXTENDED_SCAN_PARAMETERS)
+ OP_CODE_MAPPING(LE_SET_EXTENDED_SCAN_ENABLE)
+ OP_CODE_MAPPING(LE_EXTENDED_CREATE_CONNECTION)
+ OP_CODE_MAPPING(LE_PERIODIC_ADVERTISING_CREATE_SYNC)
+ OP_CODE_MAPPING(LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL)
+ OP_CODE_MAPPING(LE_PERIODIC_ADVERTISING_TERMINATE_SYNC)
+ OP_CODE_MAPPING(LE_ADD_DEVICE_TO_PERIODIC_ADVERTISING_LIST)
+ OP_CODE_MAPPING(LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISING_LIST)
+ OP_CODE_MAPPING(LE_CLEAR_PERIODIC_ADVERTISING_LIST)
+ OP_CODE_MAPPING(LE_READ_PERIODIC_ADVERTISING_LIST_SIZE)
+ OP_CODE_MAPPING(LE_READ_TRANSMIT_POWER)
+ OP_CODE_MAPPING(LE_READ_RF_PATH_COMPENSATION_POWER)
+ OP_CODE_MAPPING(LE_WRITE_RF_PATH_COMPENSATION_POWER)
+ OP_CODE_MAPPING(LE_SET_PRIVACY_MODE)
+ // vendor specific
+ case OpCode::LE_GET_VENDOR_CAPABILITIES:
+ return vendor_capabilities_.is_supported_ == 0x01;
+ case OpCode::LE_MULTI_ADVT:
+ return vendor_capabilities_.max_advt_instances_ != 0x00;
+ case OpCode::LE_BATCH_SCAN:
+ return vendor_capabilities_.total_scan_results_storage_ != 0x00;
+ case OpCode::LE_ADV_FILTER:
+ return vendor_capabilities_.filtering_support_ == 0x01;
+ case OpCode::LE_TRACK_ADV:
+ return vendor_capabilities_.total_num_of_advt_tracked_ > 0;
+ case OpCode::LE_ENERGY_INFO:
+ return vendor_capabilities_.activity_energy_info_support_ == 0x01;
+ case OpCode::LE_EXTENDED_SCAN_PARAMS:
+ return vendor_capabilities_.extended_scan_support_ == 0x01;
+ case OpCode::CONTROLLER_DEBUG_INFO:
+ return vendor_capabilities_.debug_logging_supported_ == 0x01;
+ case OpCode::CONTROLLER_A2DP_OPCODE:
+ return vendor_capabilities_.a2dp_source_offload_capability_mask_ != 0x00;
+ // undefined in local_supported_commands_
+ case OpCode::CREATE_NEW_UNIT_KEY:
+ case OpCode::READ_LOCAL_SUPPORTED_COMMANDS:
+ return true;
+ case OpCode::NONE:
+ return false;
+ }
+ return false;
+ }
+#undef OP_CODE_MAPPING
+
+ Controller& module_;
+
+ HciLayer* hci_;
+
+ Callback<void(uint16_t, uint16_t)> acl_credits_callback_;
+ Handler* acl_credits_handler_ = nullptr;
+ LocalVersionInformation local_version_information_;
+ std::array<uint8_t, 64> local_supported_commands_;
+ uint64_t local_supported_features_;
+ uint8_t maximum_page_number_;
+ std::vector<uint64_t> extended_lmp_features_array_;
+ uint16_t acl_buffer_length_ = 0;
+ uint16_t acl_buffers_ = 0;
+ uint8_t sco_buffer_length_ = 0;
+ uint16_t sco_buffers_ = 0;
+ Address mac_address_;
+ std::string local_name_;
+ LeBufferSize le_buffer_size_;
+ uint64_t le_local_supported_features_;
+ uint64_t le_supported_states_;
+ LeMaximumDataLength le_maximum_data_length_;
+ uint16_t le_maximum_advertising_data_length_;
+ uint16_t le_number_supported_advertising_sets_;
+ VendorCapabilities vendor_capabilities_;
+}; // namespace hci
+
+Controller::Controller() : impl_(std::make_unique<impl>(*this)) {}
+
+Controller::~Controller() = default;
+
+void Controller::RegisterCompletedAclPacketsCallback(Callback<void(uint16_t /* handle */, uint16_t /* packets */)> cb,
+ Handler* handler) {
+ impl_->RegisterCompletedAclPacketsCallback(cb, handler); // TODO hsz: why here?
+}
+
+std::string Controller::GetControllerLocalName() const {
+ return impl_->local_name_;
+}
+
+LocalVersionInformation Controller::GetControllerLocalVersionInformation() const {
+ return impl_->local_version_information_;
+}
+
+std::array<uint8_t, 64> Controller::GetControllerLocalSupportedCommands() const {
+ return impl_->local_supported_commands_;
+}
+
+uint8_t Controller::GetControllerLocalExtendedFeaturesMaxPageNumber() const {
+ return impl_->maximum_page_number_;
+}
+
+uint64_t Controller::GetControllerLocalSupportedFeatures() const {
+ return impl_->local_supported_features_;
+}
+
+uint64_t Controller::GetControllerLocalExtendedFeatures(uint8_t page_number) const {
+ if (page_number <= impl_->maximum_page_number_) {
+ return impl_->extended_lmp_features_array_[page_number];
+ }
+ return 0x00;
+}
+
+uint16_t Controller::GetControllerAclPacketLength() const {
+ return impl_->acl_buffer_length_;
+}
+
+uint16_t Controller::GetControllerNumAclPacketBuffers() const {
+ return impl_->acl_buffers_;
+}
+
+uint8_t Controller::GetControllerScoPacketLength() const {
+ return impl_->sco_buffer_length_;
+}
+
+uint16_t Controller::GetControllerNumScoPacketBuffers() const {
+ return impl_->sco_buffers_;
+}
+
+Address Controller::GetControllerMacAddress() const {
+ return impl_->mac_address_;
+}
+
+void Controller::SetEventMask(uint64_t event_mask) {
+ GetHandler()->Post(common::BindOnce(&impl::set_event_mask, common::Unretained(impl_.get()), event_mask));
+}
+
+void Controller::Reset() {
+ GetHandler()->Post(common::BindOnce(&impl::reset, common::Unretained(impl_.get())));
+}
+
+void Controller::SetEventFilterClearAll() {
+ std::unique_ptr<SetEventFilterClearAllBuilder> packet = SetEventFilterClearAllBuilder::Create();
+ GetHandler()->Post(common::BindOnce(&impl::set_event_filter, common::Unretained(impl_.get()), std::move(packet)));
+}
+
+void Controller::SetEventFilterInquiryResultAllDevices() {
+ std::unique_ptr<SetEventFilterInquiryResultAllDevicesBuilder> packet =
+ SetEventFilterInquiryResultAllDevicesBuilder::Create();
+ GetHandler()->Post(common::BindOnce(&impl::set_event_filter, common::Unretained(impl_.get()), std::move(packet)));
+}
+
+void Controller::SetEventFilterInquiryResultClassOfDevice(ClassOfDevice class_of_device,
+ ClassOfDevice class_of_device_mask) {
+ std::unique_ptr<SetEventFilterInquiryResultClassOfDeviceBuilder> packet =
+ SetEventFilterInquiryResultClassOfDeviceBuilder::Create(class_of_device, class_of_device_mask);
+ GetHandler()->Post(common::BindOnce(&impl::set_event_filter, common::Unretained(impl_.get()), std::move(packet)));
+}
+
+void Controller::SetEventFilterInquiryResultAddress(Address address) {
+ std::unique_ptr<SetEventFilterInquiryResultAddressBuilder> packet =
+ SetEventFilterInquiryResultAddressBuilder::Create(address);
+ GetHandler()->Post(common::BindOnce(&impl::set_event_filter, common::Unretained(impl_.get()), std::move(packet)));
+}
+
+void Controller::SetEventFilterConnectionSetupAllDevices(AutoAcceptFlag auto_accept_flag) {
+ std::unique_ptr<SetEventFilterConnectionSetupAllDevicesBuilder> packet =
+ SetEventFilterConnectionSetupAllDevicesBuilder::Create(auto_accept_flag);
+ GetHandler()->Post(common::BindOnce(&impl::set_event_filter, common::Unretained(impl_.get()), std::move(packet)));
+}
+
+void Controller::SetEventFilterConnectionSetupClassOfDevice(ClassOfDevice class_of_device,
+ ClassOfDevice class_of_device_mask,
+ AutoAcceptFlag auto_accept_flag) {
+ std::unique_ptr<SetEventFilterConnectionSetupClassOfDeviceBuilder> packet =
+ SetEventFilterConnectionSetupClassOfDeviceBuilder::Create(class_of_device, class_of_device_mask,
+ auto_accept_flag);
+ GetHandler()->Post(common::BindOnce(&impl::set_event_filter, common::Unretained(impl_.get()), std::move(packet)));
+}
+
+void Controller::SetEventFilterConnectionSetupAddress(Address address, AutoAcceptFlag auto_accept_flag) {
+ std::unique_ptr<SetEventFilterConnectionSetupAddressBuilder> packet =
+ SetEventFilterConnectionSetupAddressBuilder::Create(address, auto_accept_flag);
+ GetHandler()->Post(common::BindOnce(&impl::set_event_filter, common::Unretained(impl_.get()), std::move(packet)));
+}
+
+void Controller::WriteLocalName(std::string local_name) {
+ impl_->local_name_ = local_name;
+ GetHandler()->Post(common::BindOnce(&impl::write_local_name, common::Unretained(impl_.get()), local_name));
+}
+
+void Controller::HostBufferSize(uint16_t host_acl_data_packet_length, uint8_t host_synchronous_data_packet_length,
+ uint16_t host_total_num_acl_data_packets,
+ uint16_t host_total_num_synchronous_data_packets) {
+ GetHandler()->Post(common::BindOnce(&impl::host_buffer_size, common::Unretained(impl_.get()),
+ host_acl_data_packet_length, host_synchronous_data_packet_length,
+ host_total_num_acl_data_packets, host_total_num_synchronous_data_packets));
+}
+
+void Controller::LeSetEventMask(uint64_t le_event_mask) {
+ GetHandler()->Post(common::BindOnce(&impl::le_set_event_mask, common::Unretained(impl_.get()), le_event_mask));
+}
+
+LeBufferSize Controller::GetControllerLeBufferSize() const {
+ return impl_->le_buffer_size_;
+}
+
+uint64_t Controller::GetControllerLeLocalSupportedFeatures() const {
+ return impl_->le_local_supported_features_;
+}
+
+uint64_t Controller::GetControllerLeSupportedStates() const {
+ return impl_->le_supported_states_;
+}
+
+LeMaximumDataLength Controller::GetControllerLeMaximumDataLength() const {
+ return impl_->le_maximum_data_length_;
+}
+
+uint16_t Controller::GetControllerLeMaximumAdvertisingDataLength() const {
+ return impl_->le_maximum_advertising_data_length_;
+}
+
+uint16_t Controller::GetControllerLeNumberOfSupportedAdverisingSets() const {
+ return impl_->le_number_supported_advertising_sets_;
+}
+
+VendorCapabilities Controller::GetControllerVendorCapabilities() const {
+ return impl_->vendor_capabilities_;
+}
+
+bool Controller::IsSupported(bluetooth::hci::OpCode op_code) const {
+ return impl_->is_supported(op_code);
+}
+
+const ModuleFactory Controller::Factory = ModuleFactory([]() { return new Controller(); });
+
+void Controller::ListDependencies(ModuleList* list) {
+ list->add<hci::HciLayer>();
+}
+
+void Controller::Start() {
+ impl_->Start(GetDependency<hci::HciLayer>());
+}
+
+void Controller::Stop() {
+ impl_->Stop();
+}
+
+std::string Controller::ToString() const {
+ return "Controller";
+}
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/controller.h b/gd/hci/controller.h
new file mode 100644
index 0000000..251a5ab
--- /dev/null
+++ b/gd/hci/controller.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "common/callback.h"
+#include "hci/address.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+namespace hci {
+
+class Controller : public Module {
+ public:
+ Controller();
+ virtual ~Controller();
+ DISALLOW_COPY_AND_ASSIGN(Controller);
+
+ virtual void RegisterCompletedAclPacketsCallback(
+ common::Callback<void(uint16_t /* handle */, uint16_t /* num_packets */)> cb, os::Handler* handler);
+
+ virtual std::string GetControllerLocalName() const;
+
+ virtual LocalVersionInformation GetControllerLocalVersionInformation() const;
+
+ virtual std::array<uint8_t, 64> GetControllerLocalSupportedCommands() const;
+
+ virtual uint64_t GetControllerLocalSupportedFeatures() const;
+
+ virtual uint8_t GetControllerLocalExtendedFeaturesMaxPageNumber() const;
+
+ virtual uint64_t GetControllerLocalExtendedFeatures(uint8_t page_number) const;
+
+ virtual uint16_t GetControllerAclPacketLength() const;
+
+ virtual uint16_t GetControllerNumAclPacketBuffers() const;
+
+ virtual uint8_t GetControllerScoPacketLength() const;
+
+ virtual uint16_t GetControllerNumScoPacketBuffers() const;
+
+ virtual Address GetControllerMacAddress() const;
+
+ virtual void SetEventMask(uint64_t event_mask);
+
+ virtual void Reset();
+
+ virtual void SetEventFilterClearAll();
+
+ virtual void SetEventFilterInquiryResultAllDevices();
+
+ virtual void SetEventFilterInquiryResultClassOfDevice(ClassOfDevice class_of_device,
+ ClassOfDevice class_of_device_mask);
+
+ virtual void SetEventFilterInquiryResultAddress(Address address);
+
+ virtual void SetEventFilterConnectionSetupAllDevices(AutoAcceptFlag auto_accept_flag);
+
+ virtual void SetEventFilterConnectionSetupClassOfDevice(ClassOfDevice class_of_device,
+ ClassOfDevice class_of_device_mask,
+ AutoAcceptFlag auto_accept_flag);
+
+ virtual void SetEventFilterConnectionSetupAddress(Address address, AutoAcceptFlag auto_accept_flag);
+
+ virtual void WriteLocalName(std::string local_name);
+
+ virtual void HostBufferSize(uint16_t host_acl_data_packet_length, uint8_t host_synchronous_data_packet_length,
+ uint16_t host_total_num_acl_data_packets,
+ uint16_t host_total_num_synchronous_data_packets);
+
+ // LE controller commands
+ virtual void LeSetEventMask(uint64_t le_event_mask);
+
+ virtual LeBufferSize GetControllerLeBufferSize() const;
+
+ virtual uint64_t GetControllerLeLocalSupportedFeatures() const;
+
+ virtual uint64_t GetControllerLeSupportedStates() const;
+
+ virtual LeMaximumDataLength GetControllerLeMaximumDataLength() const;
+
+ virtual uint16_t GetControllerLeMaximumAdvertisingDataLength() const;
+
+ virtual uint16_t GetControllerLeNumberOfSupportedAdverisingSets() const;
+
+ virtual VendorCapabilities GetControllerVendorCapabilities() const;
+
+ virtual bool IsSupported(OpCode op_code) const;
+
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override;
+
+ void Start() override;
+
+ void Stop() override;
+
+ std::string ToString() const override;
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> impl_;
+};
+
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/controller_test.cc b/gd/hci/controller_test.cc
new file mode 100644
index 0000000..9d109f8
--- /dev/null
+++ b/gd/hci/controller_test.cc
@@ -0,0 +1,459 @@
+/*
+ * Copyright 2019 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 "hci/controller.h"
+
+#include <algorithm>
+#include <chrono>
+#include <future>
+#include <map>
+
+#include <gtest/gtest.h>
+
+#include "common/bind.h"
+#include "common/callback.h"
+#include "hci/address.h"
+#include "hci/hci_layer.h"
+#include "os/thread.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace hci {
+namespace {
+
+using common::BidiQueue;
+using common::BidiQueueEnd;
+using packet::kLittleEndian;
+using packet::PacketView;
+using packet::RawBuilder;
+
+constexpr uint16_t kHandle1 = 0x123;
+constexpr uint16_t kCredits1 = 0x78;
+constexpr uint16_t kHandle2 = 0x456;
+constexpr uint16_t kCredits2 = 0x9a;
+uint16_t feature_spec_version = 55;
+
+PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+ auto bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter i(*bytes);
+ bytes->reserve(packet->size());
+ packet->Serialize(i);
+ return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+class TestHciLayer : public HciLayer {
+ public:
+ void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+ common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) override {
+ GetHandler()->Post(common::BindOnce(&TestHciLayer::HandleCommand, common::Unretained(this), std::move(command),
+ std::move(on_complete), common::Unretained(handler)));
+ }
+
+ void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+ common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) override {
+ EXPECT_TRUE(false) << "Controller properties should not generate Command Status";
+ }
+
+ void HandleCommand(std::unique_ptr<CommandPacketBuilder> command_builder,
+ common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) {
+ auto packet_view = GetPacketView(std::move(command_builder));
+ CommandPacketView command = CommandPacketView::Create(packet_view);
+ ASSERT(command.IsValid());
+
+ uint8_t num_packets = 1;
+ std::unique_ptr<packet::BasePacketBuilder> event_builder;
+ switch (command.GetOpCode()) {
+ case (OpCode::READ_LOCAL_NAME): {
+ std::array<uint8_t, 248> local_name = {'D', 'U', 'T', '\0'};
+ event_builder = ReadLocalNameCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, local_name);
+ } break;
+ case (OpCode::READ_LOCAL_VERSION_INFORMATION): {
+ LocalVersionInformation local_version_information;
+ local_version_information.hci_version_ = HciVersion::V_5_0;
+ local_version_information.hci_revision_ = 0x1234;
+ local_version_information.lmp_version_ = LmpVersion::V_4_2;
+ local_version_information.manufacturer_name_ = 0xBAD;
+ local_version_information.lmp_subversion_ = 0x5678;
+ event_builder = ReadLocalVersionInformationCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS,
+ local_version_information);
+ } break;
+ case (OpCode::READ_LOCAL_SUPPORTED_COMMANDS): {
+ std::array<uint8_t, 64> supported_commands;
+ for (int i = 0; i < 37; i++) {
+ supported_commands[i] = 0xff;
+ }
+ for (int i = 37; i < 64; i++) {
+ supported_commands[i] = 0x00;
+ }
+ event_builder =
+ ReadLocalSupportedCommandsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, supported_commands);
+ } break;
+ case (OpCode::READ_LOCAL_SUPPORTED_FEATURES): {
+ uint64_t lmp_features = 0x012345678abcdef;
+ event_builder =
+ ReadLocalSupportedFeaturesCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, lmp_features);
+ } break;
+ case (OpCode::READ_LOCAL_EXTENDED_FEATURES): {
+ ReadLocalExtendedFeaturesView read_command = ReadLocalExtendedFeaturesView::Create(command);
+ ASSERT(read_command.IsValid());
+ uint8_t page_bumber = read_command.GetPageNumber();
+ uint64_t lmp_features = 0x012345678abcdef;
+ lmp_features += page_bumber;
+ event_builder = ReadLocalExtendedFeaturesCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, page_bumber,
+ 0x02, lmp_features);
+ } break;
+ case (OpCode::READ_BUFFER_SIZE): {
+ event_builder = ReadBufferSizeCompleteBuilder::Create(
+ num_packets, ErrorCode::SUCCESS, acl_data_packet_length, synchronous_data_packet_length,
+ total_num_acl_data_packets, total_num_synchronous_data_packets);
+ } break;
+ case (OpCode::READ_BD_ADDR): {
+ event_builder = ReadBdAddrCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, Address::kAny);
+ } break;
+ case (OpCode::LE_READ_BUFFER_SIZE): {
+ LeBufferSize le_buffer_size;
+ le_buffer_size.le_data_packet_length_ = 0x16;
+ le_buffer_size.total_num_le_packets_ = 0x08;
+ event_builder = LeReadBufferSizeCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, le_buffer_size);
+ } break;
+ case (OpCode::LE_READ_LOCAL_SUPPORTED_FEATURES): {
+ event_builder =
+ LeReadLocalSupportedFeaturesCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, 0x001f123456789abc);
+ } break;
+ case (OpCode::LE_READ_SUPPORTED_STATES): {
+ event_builder =
+ LeReadSupportedStatesCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, 0x001f123456789abe);
+ } break;
+ case (OpCode::LE_READ_MAXIMUM_DATA_LENGTH): {
+ LeMaximumDataLength le_maximum_data_length;
+ le_maximum_data_length.supported_max_tx_octets_ = 0x12;
+ le_maximum_data_length.supported_max_tx_time_ = 0x34;
+ le_maximum_data_length.supported_max_rx_octets_ = 0x56;
+ le_maximum_data_length.supported_max_rx_time_ = 0x78;
+ event_builder =
+ LeReadMaximumDataLengthCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, le_maximum_data_length);
+ } break;
+ case (OpCode::LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH): {
+ event_builder =
+ LeReadMaximumAdvertisingDataLengthCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, 0x0672);
+ } break;
+ case (OpCode::LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS): {
+ event_builder =
+ LeReadNumberOfSupportedAdvertisingSetsCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS, 0xF0);
+ } break;
+ case (OpCode::LE_GET_VENDOR_CAPABILITIES): {
+ BaseVendorCapabilities base_vendor_capabilities;
+ base_vendor_capabilities.max_advt_instances_ = 0x10;
+ base_vendor_capabilities.offloaded_resolution_of_private_address_ = 0x01;
+ base_vendor_capabilities.total_scan_results_storage_ = 0x2800;
+ base_vendor_capabilities.max_irk_list_sz_ = 0x20;
+ base_vendor_capabilities.filtering_support_ = 0x01;
+ base_vendor_capabilities.max_filter_ = 0x10;
+ base_vendor_capabilities.activity_energy_info_support_ = 0x01;
+
+ auto payload = std::make_unique<RawBuilder>();
+ if (feature_spec_version > 55) {
+ std::vector<uint8_t> payload_bytes = {0x20, 0x00, 0x01, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00};
+ payload->AddOctets2(feature_spec_version);
+ payload->AddOctets(payload_bytes);
+ }
+ event_builder = LeGetVendorCapabilitiesCompleteBuilder::Create(num_packets, ErrorCode::SUCCESS,
+ base_vendor_capabilities, std::move(payload));
+ } break;
+ case (OpCode::SET_EVENT_MASK):
+ case (OpCode::RESET):
+ case (OpCode::SET_EVENT_FILTER):
+ case (OpCode::HOST_BUFFER_SIZE):
+ case (OpCode::LE_SET_EVENT_MASK):
+ command_queue_.push(command);
+ not_empty_.notify_all();
+ return;
+ default:
+ LOG_INFO("Dropping unhandled packet");
+ return;
+ }
+ auto packet = GetPacketView(std::move(event_builder));
+ EventPacketView event = EventPacketView::Create(packet);
+ ASSERT(event.IsValid());
+ CommandCompleteView command_complete = CommandCompleteView::Create(event);
+ ASSERT(command_complete.IsValid());
+ handler->Post(common::BindOnce(std::move(on_complete), std::move(command_complete)));
+ }
+
+ void RegisterEventHandler(EventCode event_code, common::Callback<void(EventPacketView)> event_handler,
+ os::Handler* handler) override {
+ EXPECT_EQ(event_code, EventCode::NUMBER_OF_COMPLETED_PACKETS) << "Only NUMBER_OF_COMPLETED_PACKETS is needed";
+ number_of_completed_packets_callback_ = event_handler;
+ client_handler_ = handler;
+ }
+
+ void UnregisterEventHandler(EventCode event_code) override {
+ EXPECT_EQ(event_code, EventCode::NUMBER_OF_COMPLETED_PACKETS) << "Only NUMBER_OF_COMPLETED_PACKETS is needed";
+ number_of_completed_packets_callback_ = {};
+ client_handler_ = nullptr;
+ }
+
+ void IncomingCredit() {
+ std::vector<CompletedPackets> completed_packets;
+ CompletedPackets cp;
+ cp.host_num_of_completed_packets_ = kCredits1;
+ cp.connection_handle_ = kHandle1;
+ completed_packets.push_back(cp);
+ cp.host_num_of_completed_packets_ = kCredits2;
+ cp.connection_handle_ = kHandle2;
+ completed_packets.push_back(cp);
+ auto event_builder = NumberOfCompletedPacketsBuilder::Create(completed_packets);
+ auto packet = GetPacketView(std::move(event_builder));
+ EventPacketView event = EventPacketView::Create(packet);
+ ASSERT(event.IsValid());
+ client_handler_->Post(common::BindOnce(number_of_completed_packets_callback_, event));
+ }
+
+ CommandPacketView GetCommand(OpCode op_code) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ std::chrono::milliseconds time = std::chrono::milliseconds(3000);
+
+ // wait for command
+ while (command_queue_.size() == 0) {
+ if (not_empty_.wait_for(lock, time) == std::cv_status::timeout) {
+ break;
+ }
+ }
+ ASSERT(command_queue_.size() > 0);
+ CommandPacketView command = command_queue_.front();
+ EXPECT_EQ(command.GetOpCode(), op_code);
+ command_queue_.pop();
+ return command;
+ }
+
+ void ListDependencies(ModuleList* list) override {}
+ void Start() override {}
+ void Stop() override {}
+
+ constexpr static uint16_t acl_data_packet_length = 1024;
+ constexpr static uint8_t synchronous_data_packet_length = 60;
+ constexpr static uint16_t total_num_acl_data_packets = 10;
+ constexpr static uint16_t total_num_synchronous_data_packets = 12;
+
+ private:
+ common::Callback<void(EventPacketView)> number_of_completed_packets_callback_;
+ os::Handler* client_handler_;
+ std::queue<CommandPacketView> command_queue_;
+ mutable std::mutex mutex_;
+ std::condition_variable not_empty_;
+};
+
+class ControllerTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ test_hci_layer_ = new TestHciLayer;
+ fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_);
+ client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory);
+ fake_registry_.Start<Controller>(&thread_);
+ controller_ = static_cast<Controller*>(fake_registry_.GetModuleUnderTest(&Controller::Factory));
+ }
+
+ void TearDown() override {
+ fake_registry_.StopAll();
+ }
+
+ TestModuleRegistry fake_registry_;
+ TestHciLayer* test_hci_layer_ = nullptr;
+ os::Thread& thread_ = fake_registry_.GetTestThread();
+ Controller* controller_ = nullptr;
+ os::Handler* client_handler_ = nullptr;
+};
+
+TEST_F(ControllerTest, startup_teardown) {}
+
+TEST_F(ControllerTest, read_controller_info) {
+ std::promise<void> callback_completed;
+ ASSERT_EQ(controller_->GetControllerAclPacketLength(), test_hci_layer_->acl_data_packet_length);
+ ASSERT_EQ(controller_->GetControllerNumAclPacketBuffers(), test_hci_layer_->total_num_acl_data_packets);
+ ASSERT_EQ(controller_->GetControllerScoPacketLength(), test_hci_layer_->synchronous_data_packet_length);
+ ASSERT_EQ(controller_->GetControllerNumScoPacketBuffers(), test_hci_layer_->total_num_synchronous_data_packets);
+ ASSERT_EQ(controller_->GetControllerMacAddress(), Address::kAny);
+ LocalVersionInformation local_version_information = controller_->GetControllerLocalVersionInformation();
+ ASSERT_EQ(local_version_information.hci_version_, HciVersion::V_5_0);
+ ASSERT_EQ(local_version_information.hci_revision_, 0x1234);
+ ASSERT_EQ(local_version_information.lmp_version_, LmpVersion::V_4_2);
+ ASSERT_EQ(local_version_information.manufacturer_name_, 0xBAD);
+ ASSERT_EQ(local_version_information.lmp_subversion_, 0x5678);
+ std::array<uint8_t, 64> supported_commands;
+ for (int i = 0; i < 37; i++) {
+ supported_commands[i] = 0xff;
+ }
+ for (int i = 37; i < 64; i++) {
+ supported_commands[i] = 0x00;
+ }
+ ASSERT_EQ(controller_->GetControllerLocalSupportedCommands(), supported_commands);
+ ASSERT_EQ(controller_->GetControllerLocalSupportedFeatures(), 0x012345678abcdef);
+ ASSERT_EQ(controller_->GetControllerLocalExtendedFeaturesMaxPageNumber(), 0x02);
+ ASSERT_EQ(controller_->GetControllerLocalExtendedFeatures(0), 0x012345678abcdef);
+ ASSERT_EQ(controller_->GetControllerLocalExtendedFeatures(1), 0x012345678abcdf0);
+ ASSERT_EQ(controller_->GetControllerLocalExtendedFeatures(2), 0x012345678abcdf1);
+ ASSERT_EQ(controller_->GetControllerLocalExtendedFeatures(100), 0x00);
+ ASSERT_EQ(controller_->GetControllerLeBufferSize().le_data_packet_length_, 0x16);
+ ASSERT_EQ(controller_->GetControllerLeBufferSize().total_num_le_packets_, 0x08);
+ ASSERT_EQ(controller_->GetControllerLeLocalSupportedFeatures(), 0x001f123456789abc);
+ ASSERT_EQ(controller_->GetControllerLeSupportedStates(), 0x001f123456789abe);
+ ASSERT_EQ(controller_->GetControllerLeMaximumDataLength().supported_max_tx_octets_, 0x12);
+ ASSERT_EQ(controller_->GetControllerLeMaximumDataLength().supported_max_rx_octets_, 0x56);
+ ASSERT_EQ(controller_->GetControllerLeMaximumAdvertisingDataLength(), 0x0672);
+ ASSERT_EQ(controller_->GetControllerLeNumberOfSupportedAdverisingSets(), 0xF0);
+}
+
+TEST_F(ControllerTest, read_write_local_name) {
+ ASSERT_EQ(controller_->GetControllerLocalName(), "DUT");
+ controller_->WriteLocalName("New name");
+ ASSERT_EQ(controller_->GetControllerLocalName(), "New name");
+}
+
+TEST_F(ControllerTest, send_set_event_mask_command) {
+ controller_->SetEventMask(0x00001FFFFFFFFFFF);
+ auto packet = test_hci_layer_->GetCommand(OpCode::SET_EVENT_MASK);
+ auto command = SetEventMaskView::Create(packet);
+ ASSERT(command.IsValid());
+ ASSERT_EQ(command.GetEventMask(), 0x00001FFFFFFFFFFF);
+}
+
+TEST_F(ControllerTest, send_reset_command) {
+ controller_->Reset();
+ auto packet = test_hci_layer_->GetCommand(OpCode::RESET);
+ auto command = ResetView::Create(packet);
+ ASSERT(command.IsValid());
+}
+
+TEST_F(ControllerTest, send_set_event_filter_command) {
+ controller_->SetEventFilterInquiryResultAllDevices();
+ auto packet = test_hci_layer_->GetCommand(OpCode::SET_EVENT_FILTER);
+ auto set_event_filter_view1 = SetEventFilterView::Create(packet);
+ auto set_event_filter_inquiry_result_view1 = SetEventFilterInquiryResultView::Create(set_event_filter_view1);
+ auto command1 = SetEventFilterInquiryResultAllDevicesView::Create(set_event_filter_inquiry_result_view1);
+ ASSERT(command1.IsValid());
+
+ ClassOfDevice class_of_device({0xab, 0xcd, 0xef});
+ ClassOfDevice class_of_device_mask({0x12, 0x34, 0x56});
+ controller_->SetEventFilterInquiryResultClassOfDevice(class_of_device, class_of_device_mask);
+ packet = test_hci_layer_->GetCommand(OpCode::SET_EVENT_FILTER);
+ auto set_event_filter_view2 = SetEventFilterView::Create(packet);
+ auto set_event_filter_inquiry_result_view2 = SetEventFilterInquiryResultView::Create(set_event_filter_view2);
+ auto command2 = SetEventFilterInquiryResultClassOfDeviceView::Create(set_event_filter_inquiry_result_view2);
+ ASSERT(command2.IsValid());
+ ASSERT_EQ(command2.GetClassOfDevice(), class_of_device);
+
+ Address bdaddr({0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc});
+ controller_->SetEventFilterConnectionSetupAddress(bdaddr, AutoAcceptFlag::AUTO_ACCEPT_ON_ROLE_SWITCH_ENABLED);
+ packet = test_hci_layer_->GetCommand(OpCode::SET_EVENT_FILTER);
+ auto set_event_filter_view3 = SetEventFilterView::Create(packet);
+ auto set_event_filter_connection_setup_view = SetEventFilterConnectionSetupView::Create(set_event_filter_view3);
+ auto command3 = SetEventFilterConnectionSetupAddressView::Create(set_event_filter_connection_setup_view);
+ ASSERT(command3.IsValid());
+ ASSERT_EQ(command3.GetAddress(), bdaddr);
+}
+
+TEST_F(ControllerTest, send_host_buffer_size_command) {
+ controller_->HostBufferSize(0xFF00, 0xF1, 0xFF02, 0xFF03);
+ auto packet = test_hci_layer_->GetCommand(OpCode::HOST_BUFFER_SIZE);
+ auto command = HostBufferSizeView::Create(packet);
+ ASSERT(command.IsValid());
+ ASSERT_EQ(command.GetHostAclDataPacketLength(), 0xFF00);
+ ASSERT_EQ(command.GetHostSynchronousDataPacketLength(), 0xF1);
+ ASSERT_EQ(command.GetHostTotalNumAclDataPackets(), 0xFF02);
+ ASSERT_EQ(command.GetHostTotalNumSynchronousDataPackets(), 0xFF03);
+}
+
+TEST_F(ControllerTest, send_le_set_event_mask_command) {
+ controller_->LeSetEventMask(0x000000000000001F);
+ auto packet = test_hci_layer_->GetCommand(OpCode::LE_SET_EVENT_MASK);
+ auto command = LeSetEventMaskView::Create(packet);
+ ASSERT(command.IsValid());
+ ASSERT_EQ(command.GetLeEventMask(), 0x000000000000001F);
+}
+
+TEST_F(ControllerTest, is_supported_test) {
+ ASSERT_TRUE(controller_->IsSupported(OpCode::INQUIRY));
+ ASSERT_TRUE(controller_->IsSupported(OpCode::REJECT_CONNECTION_REQUEST));
+ ASSERT_TRUE(controller_->IsSupported(OpCode::ACCEPT_CONNECTION_REQUEST));
+ ASSERT_FALSE(controller_->IsSupported(OpCode::LE_REMOVE_ADVERTISING_SET));
+ ASSERT_FALSE(controller_->IsSupported(OpCode::LE_CLEAR_ADVERTISING_SETS));
+ ASSERT_FALSE(controller_->IsSupported(OpCode::LE_SET_PERIODIC_ADVERTISING_PARAM));
+}
+
+TEST_F(ControllerTest, feature_spec_version_055_test) {
+ EXPECT_EQ(controller_->GetControllerVendorCapabilities().version_supported_, 55);
+ EXPECT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT));
+ EXPECT_FALSE(controller_->IsSupported(OpCode::LE_TRACK_ADV));
+ EXPECT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO));
+ EXPECT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE));
+ feature_spec_version = 95;
+}
+
+TEST_F(ControllerTest, feature_spec_version_095_test) {
+ EXPECT_EQ(controller_->GetControllerVendorCapabilities().version_supported_, 95);
+ EXPECT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT));
+ EXPECT_TRUE(controller_->IsSupported(OpCode::LE_TRACK_ADV));
+ EXPECT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO));
+ EXPECT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE));
+ feature_spec_version = 96;
+}
+
+TEST_F(ControllerTest, feature_spec_version_096_test) {
+ EXPECT_EQ(controller_->GetControllerVendorCapabilities().version_supported_, 96);
+ EXPECT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT));
+ EXPECT_TRUE(controller_->IsSupported(OpCode::LE_TRACK_ADV));
+ EXPECT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO));
+ EXPECT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE));
+ feature_spec_version = 98;
+}
+
+TEST_F(ControllerTest, feature_spec_version_098_test) {
+ EXPECT_EQ(controller_->GetControllerVendorCapabilities().version_supported_, 98);
+ EXPECT_TRUE(controller_->IsSupported(OpCode::LE_MULTI_ADVT));
+ EXPECT_TRUE(controller_->IsSupported(OpCode::LE_TRACK_ADV));
+ EXPECT_FALSE(controller_->IsSupported(OpCode::CONTROLLER_DEBUG_INFO));
+ EXPECT_TRUE(controller_->IsSupported(OpCode::CONTROLLER_A2DP_OPCODE));
+}
+
+std::promise<void> credits1_set;
+std::promise<void> credits2_set;
+
+void CheckReceivedCredits(uint16_t handle, uint16_t credits) {
+ switch (handle) {
+ case (kHandle1):
+ ASSERT_EQ(kCredits1, credits);
+ credits1_set.set_value();
+ break;
+ case (kHandle2):
+ ASSERT_EQ(kCredits2, credits);
+ credits2_set.set_value();
+ break;
+ default:
+ ASSERT_LOG(false, "Unknown handle 0x%0hx with 0x%0hx credits", handle, credits);
+ }
+}
+
+TEST_F(ControllerTest, aclCreditCallbacksTest) {
+ controller_->RegisterCompletedAclPacketsCallback(common::Bind(&CheckReceivedCredits), client_handler_);
+
+ test_hci_layer_->IncomingCredit();
+
+ credits1_set.get_future().wait();
+ credits2_set.get_future().wait();
+}
+} // namespace
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/device.cc b/gd/hci/device.cc
new file mode 100644
index 0000000..d008dae
--- /dev/null
+++ b/gd/hci/device.cc
@@ -0,0 +1,32 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "hci/device.h"
+
+using namespace bluetooth::hci;
+
+std::string Device::generate_uid() {
+ // TODO(optedoblivion): Figure out a good way to do this for what we want
+ // to do
+ // TODO(optedoblivion): Need to make a way to override something for LE pub addr case
+ // Not sure if something like this is needed, but here is the idea (I think it came from mylesgw)
+ // CLASSIC: have all 0s in front for classic then have private address
+ // LE: have first public address in front then all 0s
+ // LE: have first public address in front then private address
+ //
+ return address_.ToString();
+}
diff --git a/gd/hci/device.h b/gd/hci/device.h
new file mode 100644
index 0000000..8324d00
--- /dev/null
+++ b/gd/hci/device.h
@@ -0,0 +1,136 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+#pragma once
+
+#include <string>
+
+#include "hci/address.h"
+#include "hci/class_of_device.h"
+
+namespace bluetooth::hci {
+
+/**
+ * Used to determine device functionality
+ */
+enum DeviceType { DUAL, CLASSIC, LE };
+
+/**
+ * Represents a physical HCI device.
+ *
+ * <p>Contains all of the metadata required to represent a phycial device.
+ *
+ * <p>Devices should only be created and modified by HCI.
+ */
+class Device {
+ public:
+ virtual ~Device() = default;
+
+ Address GetAddress() const {
+ return address_;
+ }
+
+ /**
+ * Returns 1 of 3 enum values for device's type (DUAL, CLASSIC, LE)
+ */
+ DeviceType GetDeviceType() const {
+ return device_type_;
+ }
+
+ /**
+ * Unique identifier for bluetooth devices
+ *
+ * @return string representation of the uuid
+ */
+ std::string /** use UUID when ported */ GetUuid() {
+ return uid_;
+ }
+
+ std::string GetName() {
+ return name_;
+ }
+
+ ClassOfDevice GetClassOfDevice() {
+ return class_of_device_;
+ }
+
+ bool IsBonded() {
+ return is_bonded_;
+ }
+
+ bool operator==(const Device& rhs) const {
+ return this->uid_ == rhs.uid_ && this->address_ == rhs.address_ && this->device_type_ == rhs.device_type_ &&
+ this->is_bonded_ == rhs.is_bonded_;
+ }
+
+ protected:
+ friend class DeviceDatabase;
+ friend class DualDevice;
+
+ /**
+ * @param raw_address the address of the device
+ * @param device_type specify the type of device to create
+ */
+ Device(Address address, DeviceType device_type)
+ : address_(address), device_type_(device_type), uid_(generate_uid()), name_(""), class_of_device_() {}
+
+ /**
+ * Called only by friend class DeviceDatabase
+ *
+ * @param address
+ */
+ virtual void SetAddress(Address address) {
+ address_ = address;
+ uid_ = generate_uid();
+ }
+
+ /**
+ * Set the type of the device.
+ *
+ * <p>Needed by dual mode to arbitrarily set the valure to DUAL for corresponding LE/Classic devices
+ *
+ * @param type of device
+ */
+ void SetDeviceType(DeviceType type) {
+ device_type_ = type;
+ }
+
+ void SetName(std::string& name) {
+ name_ = name;
+ }
+
+ void SetClassOfDevice(ClassOfDevice class_of_device) {
+ class_of_device_ = class_of_device;
+ }
+
+ void SetIsBonded(bool is_bonded) {
+ is_bonded_ = is_bonded;
+ }
+
+ private:
+ Address address_{Address::kEmpty};
+ DeviceType device_type_;
+ std::string uid_;
+ std::string name_;
+ ClassOfDevice class_of_device_;
+ bool is_bonded_ = false;
+
+ /* Uses specific information about the device to calculate a UID */
+ std::string generate_uid();
+};
+
+} // namespace bluetooth::hci
diff --git a/gd/hci/device_database.cc b/gd/hci/device_database.cc
new file mode 100644
index 0000000..0027074
--- /dev/null
+++ b/gd/hci/device_database.cc
@@ -0,0 +1,276 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "hci/device_database.h"
+
+#include <memory>
+#include <utility>
+
+#include "hci/classic_device.h"
+#include "hci/dual_device.h"
+#include "hci/le_device.h"
+#include "os/log.h"
+
+using namespace bluetooth::hci;
+
+std::shared_ptr<ClassicDevice> DeviceDatabase::CreateClassicDevice(Address address) {
+ ClassicDevice device(address);
+ const std::string uuid = device.GetUuid();
+ AddDeviceToMap(std::move(device));
+ return GetClassicDevice(uuid);
+}
+
+std::shared_ptr<LeDevice> DeviceDatabase::CreateLeDevice(Address address) {
+ LeDevice device(address);
+ const std::string uuid = device.GetUuid();
+ AddDeviceToMap(std::move(device));
+ return GetLeDevice(uuid);
+}
+
+std::shared_ptr<DualDevice> DeviceDatabase::CreateDualDevice(Address address) {
+ auto classic = CreateClassicDevice(address);
+ auto le = CreateLeDevice(address);
+ if (classic && le) {
+ DualDevice device(address, classic, le);
+ std::string uuid = device.GetUuid();
+ AddDeviceToMap(std::move(device));
+ return GetDualDevice(uuid);
+ }
+ LOG_WARN("Attempting to instert a DUAL device that already exists!");
+ return std::shared_ptr<DualDevice>();
+}
+
+bool DeviceDatabase::RemoveDevice(const std::shared_ptr<Device>& device) {
+ const DeviceType type = device->GetDeviceType();
+ bool success;
+ switch (type) {
+ case CLASSIC:
+ success = false;
+ {
+ std::lock_guard<std::mutex> lock(device_map_mutex_);
+ auto classic_it = classic_device_map_.find(device->GetUuid());
+ // If we have a record with the same key
+ if (classic_it != classic_device_map_.end()) {
+ classic_device_map_.erase(device->GetUuid());
+ success = true;
+ }
+ }
+ if (success) {
+ ASSERT_LOG(WriteToDisk(), "Failed to write data to disk!");
+ } else {
+ LOG_WARN("Device not in database!");
+ }
+ return success;
+ case LE:
+ success = false;
+ {
+ std::lock_guard<std::mutex> lock(device_map_mutex_);
+ auto le_it = le_device_map_.find(device->GetUuid());
+ // If we have a record with the same key
+ if (le_it != le_device_map_.end()) {
+ le_device_map_.erase(device->GetUuid());
+ success = true;
+ }
+ }
+ if (success) {
+ ASSERT_LOG(WriteToDisk(), "Failed to write data to disk!");
+ } else {
+ LOG_WARN("Device not in database!");
+ }
+ return success;
+ case DUAL:
+ std::shared_ptr<DualDevice> dual_device = nullptr;
+ {
+ std::lock_guard<std::mutex> lock(device_map_mutex_);
+ auto dual_it = dual_device_map_.find(device->GetUuid());
+ if (dual_it != dual_device_map_.end()) {
+ dual_device = GetDualDevice(device->GetUuid());
+ }
+ }
+ success = false;
+ if (dual_device != nullptr) {
+ if (RemoveDevice(dual_device->GetClassicDevice()) && RemoveDevice(dual_device->GetLeDevice())) {
+ dual_device_map_.erase(device->GetUuid());
+ success = true;
+ }
+ }
+ if (success) {
+ ASSERT_LOG(WriteToDisk(), "Failed to write data to disk!");
+ } else {
+ LOG_WARN("Device not in database!");
+ }
+ return success;
+ }
+}
+
+std::shared_ptr<ClassicDevice> DeviceDatabase::GetClassicDevice(const std::string& uuid) {
+ std::lock_guard<std::mutex> lock(device_map_mutex_);
+ auto it = classic_device_map_.find(uuid);
+ if (it != classic_device_map_.end()) {
+ return it->second;
+ }
+ LOG_WARN("Device '%s' not found!", uuid.c_str());
+ return std::shared_ptr<ClassicDevice>();
+}
+
+std::shared_ptr<LeDevice> DeviceDatabase::GetLeDevice(const std::string& uuid) {
+ std::lock_guard<std::mutex> lock(device_map_mutex_);
+ auto it = le_device_map_.find(uuid);
+ if (it != le_device_map_.end()) {
+ return it->second;
+ }
+ LOG_WARN("Device '%s' not found!", uuid.c_str());
+ return std::shared_ptr<LeDevice>();
+}
+
+std::shared_ptr<DualDevice> DeviceDatabase::GetDualDevice(const std::string& uuid) {
+ std::lock_guard<std::mutex> lock(device_map_mutex_);
+ auto it = dual_device_map_.find(uuid);
+ if (it != dual_device_map_.end()) {
+ return it->second;
+ }
+ LOG_WARN("Device '%s' not found!", uuid.c_str());
+ return std::shared_ptr<DualDevice>();
+}
+
+bool DeviceDatabase::UpdateDeviceAddress(const std::shared_ptr<Device>& device, Address new_address) {
+ // Hold onto device
+ const DeviceType type = device->GetDeviceType();
+ if (type == CLASSIC) {
+ auto classic_device = GetClassicDevice(device->GetUuid());
+ // This gets rid of the shared_ptr in the map
+ ASSERT_LOG(RemoveDevice(device), "Failed to remove the device!");
+ classic_device->SetAddress(new_address);
+ // Move the value located at the pointer
+ return AddDeviceToMap(std::move(*(classic_device.get())));
+ } else if (type == LE) {
+ auto le_device = GetLeDevice(device->GetUuid());
+ // This gets rid of the shared_ptr in the map
+ ASSERT_LOG(RemoveDevice(device), "Failed to remove the device!");
+ le_device->SetAddress(new_address);
+ // Move the value located at the pointer
+ return AddDeviceToMap(std::move(*(le_device.get())));
+ } else if (type == DUAL) {
+ auto dual_device = GetDualDevice(device->GetUuid());
+ // This gets rid of the shared_ptr in the map
+ ASSERT_LOG(RemoveDevice(device), "Failed to remove the device!");
+ dual_device->SetAddress(new_address);
+ // Move the value located at the pointer
+ return AddDeviceToMap(std::move(*(dual_device.get())));
+ }
+ LOG_ALWAYS_FATAL("Someone added a device type but didn't account for it here.");
+ return false;
+}
+
+bool DeviceDatabase::AddDeviceToMap(ClassicDevice&& device) {
+ const std::string uuid = device.GetUuid();
+ bool success = false;
+ {
+ std::lock_guard<std::mutex> lock(device_map_mutex_);
+ auto it = classic_device_map_.find(device.GetUuid());
+ // If we have a record with the same key
+ if (it != classic_device_map_.end()) {
+ // We don't want to insert and overwrite
+ return false;
+ }
+ std::shared_ptr<ClassicDevice> device_ptr = std::make_shared<ClassicDevice>(std::move(device));
+ // returning the boolean value of insert success
+ if (classic_device_map_
+ .insert(std::pair<std::string, std::shared_ptr<ClassicDevice>>(device_ptr->GetUuid(), device_ptr))
+ .second) {
+ success = true;
+ }
+ }
+ if (success) {
+ ASSERT_LOG(WriteToDisk(), "Failed to write data to disk!");
+ } else {
+ LOG_WARN("Failed to add device '%s' to map.", uuid.c_str());
+ }
+ return success;
+}
+
+bool DeviceDatabase::AddDeviceToMap(LeDevice&& device) {
+ const std::string uuid = device.GetUuid();
+ bool success = false;
+ {
+ std::lock_guard<std::mutex> lock(device_map_mutex_);
+ auto it = le_device_map_.find(device.GetUuid());
+ // If we have a record with the same key
+ if (it != le_device_map_.end()) {
+ // We don't want to insert and overwrite
+ return false;
+ }
+ std::shared_ptr<LeDevice> device_ptr = std::make_shared<LeDevice>(std::move(device));
+ // returning the boolean value of insert success
+ if (le_device_map_.insert(std::pair<std::string, std::shared_ptr<LeDevice>>(device_ptr->GetUuid(), device_ptr))
+ .second) {
+ success = true;
+ }
+ }
+ if (success) {
+ ASSERT_LOG(WriteToDisk(), "Failed to write data to disk!");
+ } else {
+ LOG_WARN("Failed to add device '%s' to map.", uuid.c_str());
+ }
+ return success;
+}
+
+bool DeviceDatabase::AddDeviceToMap(DualDevice&& device) {
+ const std::string uuid = device.GetUuid();
+ bool success = false;
+ {
+ std::lock_guard<std::mutex> lock(device_map_mutex_);
+ auto it = dual_device_map_.find(device.GetUuid());
+ // If we have a record with the same key
+ if (it != dual_device_map_.end()) {
+ // We don't want to insert and overwrite
+ return false;
+ }
+ std::shared_ptr<DualDevice> device_ptr = std::make_shared<DualDevice>(std::move(device));
+ // returning the boolean value of insert success
+ if (dual_device_map_.insert(std::pair<std::string, std::shared_ptr<DualDevice>>(device_ptr->GetUuid(), device_ptr))
+ .second) {
+ success = true;
+ }
+ }
+ if (success) {
+ ASSERT_LOG(WriteToDisk(), "Failed to write data to disk!");
+ } else {
+ LOG_WARN("Failed to add device '%s' to map.", uuid.c_str());
+ }
+ return success;
+}
+
+bool DeviceDatabase::WriteToDisk() {
+ // TODO(optedoblivion): Implement
+ // TODO(optedoblivion): FIX ME!
+ // If synchronous stack dies before async write, we can miss adding device
+ // post(WriteToDisk());
+ // Current Solution: Synchronous disk I/O...
+ std::lock_guard<std::mutex> lock(device_map_mutex_);
+ // Collect information to sync to database
+ // Create SQL query for insert/update
+ // submit SQL
+ return true;
+}
+
+bool DeviceDatabase::ReadFromDisk() {
+ // TODO(optedoblivion): Implement
+ // Current Solution: Synchronous disk I/O...
+ std::lock_guard<std::mutex> lock(device_map_mutex_);
+ return true;
+}
diff --git a/gd/hci/device_database.h b/gd/hci/device_database.h
new file mode 100644
index 0000000..88434a4
--- /dev/null
+++ b/gd/hci/device_database.h
@@ -0,0 +1,149 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+#pragma once
+
+#include <map>
+#include <mutex>
+
+#include "hci/classic_device.h"
+#include "hci/device.h"
+#include "hci/dual_device.h"
+#include "hci/le_device.h"
+#include "os/log.h"
+
+namespace bluetooth::hci {
+
+/**
+ * Stores all of the paired or connected devices in the database.
+ *
+ * <p>If a device is stored here it is actively being used by the stack.
+ *
+ * <p>This database is not meant for scan results.
+ */
+class DeviceDatabase {
+ public:
+ DeviceDatabase() : classic_device_map_(), le_device_map_(), dual_device_map_() {
+ if (!ReadFromDisk()) {
+ LOG_WARN("First boot or missing data!");
+ }
+ }
+
+ /**
+ * Adds a device to the internal memory map and triggers a WriteToDisk.
+ *
+ * @param address private address for device
+ * @return weak pointer to the device or empty pointer if device already exists
+ */
+ std::shared_ptr<ClassicDevice> CreateClassicDevice(Address address);
+
+ /**
+ * Adds a device to the internal memory map and triggers a WriteToDisk.
+ *
+ * @param address private address for device
+ * @return weak pointer to the device or empty pointer if device already exists
+ */
+ std::shared_ptr<LeDevice> CreateLeDevice(Address address);
+
+ /**
+ * Adds a device to the internal memory map and triggers a WriteToDisk.
+ *
+ * @param address private address for device
+ * @return weak pointer to the device or empty pointer if device already exists
+ */
+ std::shared_ptr<DualDevice> CreateDualDevice(Address address);
+
+ /**
+ * Fetches a Classic Device matching the given uuid.
+ *
+ * @param uuid generated uuid from a Device
+ * @return a weak reference to the matching Device or empty shared_ptr (nullptr)
+ */
+ std::shared_ptr<ClassicDevice> GetClassicDevice(const std::string& uuid);
+
+ /**
+ * Fetches a Le Device matching the given uuid.
+ *
+ * @param uuid generated uuid from a Device
+ * @return a weak reference to the matching Device or empty shared_ptr (nullptr)
+ */
+ std::shared_ptr<LeDevice> GetLeDevice(const std::string& uuid);
+
+ /**
+ * Fetches a Dual Device matching the given uuid.
+ *
+ * @param uuid generated uuid from a Device
+ * @return a weak reference to the matching Device or empty shared_ptr (nullptr)
+ */
+ std::shared_ptr<DualDevice> GetDualDevice(const std::string& uuid);
+
+ /**
+ * Removes a device from the internal database.
+ *
+ * @param device weak pointer to device to remove from the database
+ * @return <code>true</code> if the device is removed
+ */
+ bool RemoveDevice(const std::shared_ptr<Device>& device);
+
+ /**
+ * Changes an address for a device.
+ *
+ * Also fixes the key mapping for the device.
+ *
+ * @param new_address this will replace the existing address
+ * @return <code>true</code> if updated
+ */
+ bool UpdateDeviceAddress(const std::shared_ptr<Device>& device, Address new_address);
+
+ // TODO(optedoblivion): Make interfaces for device modification
+ // We want to keep the device modification encapsulated to the DeviceDatabase.
+ // Pass around shared_ptr to device, device metadata only accessible via Getters.
+ // Choices:
+ // a) Have Getters/Setters on device object
+ // b) Have Getters/Setters on device database accepting a device object
+ // c) Have Getters on device object and Setters on device database accepting a device object
+ // I chose to go with option c for now as I think it is the best option.
+
+ /**
+ * Fetches a list of classic devices.
+ *
+ * @return vector of weak pointers to classic devices
+ */
+ std::vector<std::shared_ptr<Device>> GetClassicDevices();
+
+ /**
+ * Fetches a list of le devices
+ *
+ * @return vector of weak pointers to le devices
+ */
+ std::vector<std::shared_ptr<Device>> GetLeDevices();
+
+ private:
+ std::mutex device_map_mutex_;
+ std::map<std::string, std::shared_ptr<ClassicDevice>> classic_device_map_;
+ std::map<std::string, std::shared_ptr<LeDevice>> le_device_map_;
+ std::map<std::string, std::shared_ptr<DualDevice>> dual_device_map_;
+
+ bool AddDeviceToMap(ClassicDevice&& device);
+ bool AddDeviceToMap(LeDevice&& device);
+ bool AddDeviceToMap(DualDevice&& device);
+
+ bool WriteToDisk();
+ bool ReadFromDisk();
+};
+
+} // namespace bluetooth::hci
diff --git a/gd/hci/device_database_test.cc b/gd/hci/device_database_test.cc
new file mode 100644
index 0000000..330571d
--- /dev/null
+++ b/gd/hci/device_database_test.cc
@@ -0,0 +1,134 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "device_database.h"
+#include "classic_device.h"
+
+#include <gtest/gtest.h>
+
+using namespace bluetooth::hci;
+
+namespace bluetooth::hci {
+namespace {
+
+Address address({0x01, 0x02, 0x03, 0x04, 0x05, 0x06});
+std::string address_str = "06:05:04:03:02:01";
+class DeviceDatabaseTest : public ::testing::Test {
+ protected:
+ DeviceDatabaseTest() = default;
+
+ void SetUp() override {}
+
+ void TearDown() override {}
+
+ DeviceDatabase device_database_;
+};
+
+TEST_F(DeviceDatabaseTest, create_classic_device) {
+ auto classic_device = device_database_.CreateClassicDevice(address);
+ ASSERT_TRUE(classic_device);
+ ASSERT_EQ(CLASSIC, classic_device->GetDeviceType());
+ ASSERT_EQ(address_str, classic_device->GetUuid());
+}
+
+TEST_F(DeviceDatabaseTest, create_le_device) {
+ auto le_device = device_database_.CreateLeDevice(address);
+ ASSERT_TRUE(le_device);
+ ASSERT_EQ(LE, le_device->GetDeviceType());
+ ASSERT_EQ(address_str, le_device->GetUuid());
+}
+
+TEST_F(DeviceDatabaseTest, create_dual_device) {
+ auto dual_device = device_database_.CreateDualDevice(address);
+ ASSERT_TRUE(dual_device);
+ ASSERT_EQ(DUAL, dual_device->GetDeviceType());
+ ASSERT_EQ(DUAL, dual_device->GetClassicDevice()->GetDeviceType());
+ ASSERT_EQ(DUAL, dual_device->GetLeDevice()->GetDeviceType());
+ ASSERT_EQ(address_str, dual_device->GetUuid());
+}
+
+// Shouldn't fail when creating twice. Should just get back a s_ptr the same device
+TEST_F(DeviceDatabaseTest, create_classic_device_twice) {
+ auto classic_device = device_database_.CreateClassicDevice(address);
+ ASSERT_TRUE(classic_device);
+ ASSERT_EQ(CLASSIC, classic_device->GetDeviceType());
+ ASSERT_EQ(address_str, classic_device->GetUuid());
+ ASSERT_TRUE(device_database_.CreateClassicDevice(address));
+}
+
+TEST_F(DeviceDatabaseTest, create_le_device_twice) {
+ auto le_device = device_database_.CreateLeDevice(address);
+ ASSERT_TRUE(le_device);
+ ASSERT_EQ(LE, le_device->GetDeviceType());
+ ASSERT_EQ(address_str, le_device->GetUuid());
+ ASSERT_TRUE(device_database_.CreateLeDevice(address));
+}
+
+TEST_F(DeviceDatabaseTest, create_dual_device_twice) {
+ auto dual_device = device_database_.CreateDualDevice(address);
+ ASSERT_TRUE(dual_device);
+
+ // Dual
+ ASSERT_EQ(DUAL, dual_device->GetDeviceType());
+ ASSERT_EQ(address_str, dual_device->GetUuid());
+
+ // Classic
+ ASSERT_EQ(DUAL, dual_device->GetClassicDevice()->GetDeviceType());
+ ASSERT_EQ(address_str, dual_device->GetClassicDevice()->GetUuid());
+
+ // LE
+ ASSERT_EQ(DUAL, dual_device->GetLeDevice()->GetDeviceType());
+ ASSERT_EQ(address_str, dual_device->GetLeDevice()->GetUuid());
+
+ ASSERT_TRUE(device_database_.CreateDualDevice(address));
+}
+
+TEST_F(DeviceDatabaseTest, remove_device) {
+ std::shared_ptr<Device> created_device = device_database_.CreateClassicDevice(address);
+ ASSERT_TRUE(created_device);
+ ASSERT_TRUE(device_database_.RemoveDevice(created_device));
+ ASSERT_TRUE(device_database_.CreateClassicDevice(address));
+}
+
+TEST_F(DeviceDatabaseTest, remove_device_twice) {
+ std::shared_ptr<Device> created_device = device_database_.CreateClassicDevice(address);
+ ASSERT_TRUE(device_database_.RemoveDevice(created_device));
+ ASSERT_FALSE(device_database_.RemoveDevice(created_device));
+}
+
+TEST_F(DeviceDatabaseTest, get_nonexistent_device) {
+ std::shared_ptr<Device> device_ptr = device_database_.GetClassicDevice(address_str);
+ ASSERT_FALSE(device_ptr);
+}
+
+TEST_F(DeviceDatabaseTest, address_modification_check) {
+ std::shared_ptr<Device> created_device = device_database_.CreateClassicDevice(address);
+ std::shared_ptr<Device> gotten_device = device_database_.GetClassicDevice(address.ToString());
+ ASSERT_TRUE(created_device);
+ ASSERT_TRUE(gotten_device);
+ ASSERT_EQ(address_str, created_device->GetAddress().ToString());
+ ASSERT_EQ(address_str, gotten_device->GetAddress().ToString());
+ device_database_.UpdateDeviceAddress(created_device, Address({0x01, 0x01, 0x01, 0x01, 0x01, 0x01}));
+ ASSERT_EQ("01:01:01:01:01:01", created_device->GetAddress().ToString());
+ ASSERT_EQ("01:01:01:01:01:01", gotten_device->GetAddress().ToString());
+ std::shared_ptr<Device> gotten_modified_device = device_database_.GetClassicDevice("01:01:01:01:01:01");
+ ASSERT_TRUE(gotten_modified_device);
+ ASSERT_TRUE(device_database_.RemoveDevice(gotten_modified_device));
+ ASSERT_FALSE(device_database_.GetClassicDevice("01:01:01:01:01:01"));
+}
+} // namespace
+} // namespace bluetooth::hci
diff --git a/gd/hci/device_test.cc b/gd/hci/device_test.cc
new file mode 100644
index 0000000..1b4fafc
--- /dev/null
+++ b/gd/hci/device_test.cc
@@ -0,0 +1,101 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "device.h"
+#include "classic_device.h"
+
+#include <gtest/gtest.h>
+
+using namespace bluetooth::hci;
+
+static const char* test_addr_str = "bc:9a:78:56:34:12";
+static const uint8_t test_addr[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc};
+static const Address address(test_addr);
+
+namespace bluetooth::hci {
+namespace {
+class TestableDevice : public Device {
+ public:
+ explicit TestableDevice(Address a) : Device(a, CLASSIC) {}
+
+ void SetTheAddress() {
+ Address a({0x01, 0x02, 0x03, 0x04, 0x05, 0x06});
+ this->SetAddress(a);
+ }
+ void SetTheClassOfDevice() {
+ ClassOfDevice class_of_device({0x01, 0x02, 0x03});
+ this->SetClassOfDevice(class_of_device);
+ }
+ void SetTheName() {
+ std::string name = "Some Name";
+ this->SetName(name);
+ }
+ void SetTheIsBonded() {
+ this->SetIsBonded(true);
+ }
+};
+class DeviceTest : public ::testing::Test {
+ public:
+ DeviceTest() : device_(Address(test_addr)) {}
+
+ protected:
+ void SetUp() override {}
+
+ void TearDown() override {}
+ TestableDevice device_;
+};
+
+TEST_F(DeviceTest, initial_integrity) {
+ ASSERT_STREQ(test_addr_str, device_.GetAddress().ToString().c_str());
+ ASSERT_STREQ(test_addr_str, device_.GetUuid().c_str());
+ ASSERT_EQ(DeviceType::CLASSIC, device_.GetDeviceType());
+ ASSERT_EQ("", device_.GetName());
+}
+
+TEST_F(DeviceTest, set_get_class_of_device) {
+ ClassOfDevice class_of_device({0x01, 0x02, 0x03});
+ ASSERT_NE(class_of_device, device_.GetClassOfDevice());
+ device_.SetTheClassOfDevice();
+ ASSERT_EQ(class_of_device, device_.GetClassOfDevice());
+}
+
+TEST_F(DeviceTest, set_get_name) {
+ std::string name = "Some Name";
+ ASSERT_EQ("", device_.GetName());
+ device_.SetTheName();
+ ASSERT_EQ(name, device_.GetName());
+}
+
+TEST_F(DeviceTest, operator_iseq) {
+ TestableDevice d(address);
+ EXPECT_EQ(device_, d);
+}
+
+TEST_F(DeviceTest, set_address) {
+ ASSERT_EQ(test_addr_str, device_.GetAddress().ToString());
+ device_.SetTheAddress();
+ ASSERT_EQ("06:05:04:03:02:01", device_.GetAddress().ToString());
+}
+
+TEST_F(DeviceTest, set_bonded) {
+ ASSERT_FALSE(device_.IsBonded());
+ device_.SetTheIsBonded();
+ ASSERT_TRUE(device_.IsBonded());
+}
+
+} // namespace
+} // namespace bluetooth::hci
diff --git a/gd/hci/dual_device.h b/gd/hci/dual_device.h
new file mode 100644
index 0000000..8d08019
--- /dev/null
+++ b/gd/hci/dual_device.h
@@ -0,0 +1,60 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+#pragma once
+
+#include "hci/classic_device.h"
+#include "hci/device.h"
+#include "hci/le_device.h"
+
+namespace bluetooth::hci {
+
+/**
+ * A device representing a DUAL device.
+ *
+ * <p>This can be a DUAL only.
+ */
+class DualDevice : public Device {
+ public:
+ std::shared_ptr<Device> GetClassicDevice() {
+ return classic_device_;
+ }
+
+ std::shared_ptr<Device> GetLeDevice() {
+ return le_device_;
+ }
+
+ protected:
+ friend class DeviceDatabase;
+ DualDevice(Address address, std::shared_ptr<ClassicDevice> classic_device, std::shared_ptr<LeDevice> le_device)
+ : Device(address, DUAL), classic_device_(std::move(classic_device)), le_device_(std::move(le_device)) {
+ classic_device_->SetDeviceType(DUAL);
+ le_device_->SetDeviceType(DUAL);
+ }
+
+ void SetAddress(Address address) override {
+ Device::SetAddress(address);
+ GetClassicDevice()->SetAddress(address);
+ GetLeDevice()->SetAddress(address);
+ }
+
+ private:
+ std::shared_ptr<ClassicDevice> classic_device_;
+ std::shared_ptr<LeDevice> le_device_;
+};
+
+} // namespace bluetooth::hci
diff --git a/gd/hci/dual_device_test.cc b/gd/hci/dual_device_test.cc
new file mode 100644
index 0000000..1c4c2b0
--- /dev/null
+++ b/gd/hci/dual_device_test.cc
@@ -0,0 +1,81 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "dual_device.h"
+#include "device.h"
+
+#include <gtest/gtest.h>
+
+using namespace bluetooth::hci;
+
+static const char* test_addr_str = "bc:9a:78:56:34:12";
+static const uint8_t test_addr[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc};
+static const Address address(test_addr);
+
+namespace bluetooth::hci {
+namespace {
+class TestableClassicDevice : public ClassicDevice {
+ public:
+ explicit TestableClassicDevice(Address a) : ClassicDevice(a) {}
+};
+class TestableLeDevice : public LeDevice {
+ public:
+ explicit TestableLeDevice(Address a) : LeDevice(a) {}
+};
+class TestableDevice : public DualDevice {
+ public:
+ TestableDevice(Address a, std::shared_ptr<TestableClassicDevice>& classic_device,
+ std::shared_ptr<TestableLeDevice>& le_device)
+ : DualDevice(a, classic_device, le_device) {}
+
+ void SetTheAddress() {
+ Address a({0x01, 0x02, 0x03, 0x04, 0x05, 0x06});
+ this->SetAddress(a);
+ }
+};
+std::shared_ptr<TestableClassicDevice> classic_device = std::make_shared<TestableClassicDevice>(address);
+std::shared_ptr<TestableLeDevice> le_device = std::make_shared<TestableLeDevice>(address);
+class DualDeviceTest : public ::testing::Test {
+ public:
+ DualDeviceTest() : device_(Address(test_addr), classic_device, le_device) {}
+
+ protected:
+ void SetUp() override {}
+
+ void TearDown() override {}
+ TestableDevice device_;
+};
+
+TEST_F(DualDeviceTest, initial_integrity) {
+ Address a = device_.GetAddress();
+ ASSERT_EQ(test_addr_str, a.ToString());
+
+ ASSERT_EQ(DUAL, device_.GetClassicDevice()->GetDeviceType());
+ ASSERT_EQ(a.ToString(), device_.GetClassicDevice()->GetAddress().ToString());
+
+ ASSERT_EQ(DUAL, device_.GetLeDevice()->GetDeviceType());
+ ASSERT_EQ(a.ToString(), device_.GetLeDevice()->GetAddress().ToString());
+
+ device_.SetTheAddress();
+
+ ASSERT_EQ("06:05:04:03:02:01", device_.GetAddress().ToString());
+ ASSERT_EQ("06:05:04:03:02:01", device_.GetClassicDevice()->GetAddress().ToString());
+ ASSERT_EQ("06:05:04:03:02:01", device_.GetLeDevice()->GetAddress().ToString());
+}
+
+} // namespace
+} // namespace bluetooth::hci
diff --git a/gd/hci/facade.cc b/gd/hci/facade.cc
new file mode 100644
index 0000000..3aebcbb
--- /dev/null
+++ b/gd/hci/facade.cc
@@ -0,0 +1,796 @@
+/*
+ * Copyright 2019 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 "hci/facade.h"
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+
+#include "common/bind.h"
+#include "common/blocking_queue.h"
+#include "grpc/grpc_event_stream.h"
+#include "hci/acl_manager.h"
+#include "hci/classic_security_manager.h"
+#include "hci/controller.h"
+#include "hci/facade.grpc.pb.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "packet/raw_builder.h"
+
+using ::grpc::ServerAsyncResponseWriter;
+using ::grpc::ServerAsyncWriter;
+using ::grpc::ServerContext;
+
+using ::bluetooth::facade::EventStreamRequest;
+using ::bluetooth::packet::RawBuilder;
+
+namespace bluetooth {
+namespace hci {
+
+class AclManagerFacadeService : public AclManagerFacade::Service,
+ public ::bluetooth::hci::ConnectionCallbacks,
+ public ::bluetooth::hci::ConnectionManagementCallbacks,
+ public ::bluetooth::hci::AclManagerCallbacks {
+ public:
+ AclManagerFacadeService(AclManager* acl_manager, Controller* controller, HciLayer* hci_layer,
+ ::bluetooth::os::Handler* facade_handler)
+ : acl_manager_(acl_manager), controller_(controller), hci_layer_(hci_layer), facade_handler_(facade_handler) {
+ acl_manager_->RegisterCallbacks(this, facade_handler_);
+ acl_manager_->RegisterAclManagerCallbacks(this, facade_handler_);
+ }
+
+ using EventStream = ::bluetooth::grpc::GrpcEventStream<AclData, AclPacketView>;
+
+ ::grpc::Status SetPageScanMode(::grpc::ServerContext* context, const ::bluetooth::hci::PageScanMode* request,
+ ::google::protobuf::Empty* response) override {
+ ScanEnable scan_enable = request->enabled() ? ScanEnable::PAGE_SCAN_ONLY : ScanEnable::NO_SCANS;
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ hci_layer_->EnqueueCommand(
+ WriteScanEnableBuilder::Create(scan_enable),
+ common::BindOnce([](std::promise<void> promise, CommandCompleteView) { promise.set_value(); },
+ std::move(promise)),
+ facade_handler_);
+ future.wait();
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status Connect(::grpc::ServerContext* context, const facade::BluetoothAddress* remote,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ Address peer;
+ ASSERT(Address::FromString(remote->address(), peer));
+ acl_manager_->CreateConnection(peer);
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status Disconnect(::grpc::ServerContext* context, const facade::BluetoothAddress* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ Address peer;
+ Address::FromString(request->address(), peer);
+ auto connection = acl_connections_.find(request->address());
+ if (connection == acl_connections_.end()) {
+ LOG_ERROR("Invalid address");
+ return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid address");
+ } else {
+ connection->second->Disconnect(DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION);
+ return ::grpc::Status::OK;
+ }
+ }
+
+ ::grpc::Status AuthenticationRequested(::grpc::ServerContext* context, const facade::BluetoothAddress* request,
+ ::google::protobuf::Empty* response) override {
+ Address peer;
+ Address::FromString(request->address(), peer);
+ auto connection = acl_connections_.find(request->address());
+ if (connection == acl_connections_.end()) {
+ LOG_ERROR("Invalid address");
+ return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid address");
+ } else {
+ connection->second->AuthenticationRequested();
+ return ::grpc::Status::OK;
+ }
+ };
+
+ ::grpc::Status SendAclData(::grpc::ServerContext* context, const AclData* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ acl_connections_[request->remote().address()]->GetAclQueueEnd()->RegisterEnqueue(
+ facade_handler_, common::Bind(&AclManagerFacadeService::enqueue_packet, common::Unretained(this),
+ common::Unretained(request), common::Passed(std::move(promise))));
+ future.wait();
+ return ::grpc::Status::OK;
+ }
+
+ std::unique_ptr<BasePacketBuilder> enqueue_packet(const AclData* request, std::promise<void> promise) {
+ acl_connections_[request->remote().address()]->GetAclQueueEnd()->UnregisterEnqueue();
+ std::string req_string = request->payload();
+ std::unique_ptr<RawBuilder> packet = std::make_unique<RawBuilder>();
+ packet->AddOctets(std::vector<uint8_t>(req_string.begin(), req_string.end()));
+ promise.set_value();
+ return packet;
+ }
+
+ ::grpc::Status FetchAclData(::grpc::ServerContext* context, const facade::EventStreamRequest* request,
+ ::grpc::ServerWriter<AclData>* writer) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ return acl_stream_.HandleRequest(context, request, writer);
+ }
+
+ ::grpc::Status TestInternalHciCommands(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+ ::google::protobuf::Empty* response) {
+ LocalVersionInformation local_version_information = controller_->GetControllerLocalVersionInformation();
+ LOG_DEBUG("local name : %s", controller_->GetControllerLocalName().c_str());
+ controller_->WriteLocalName("Device Under Test");
+ LOG_DEBUG("new local name : %s", controller_->GetControllerLocalName().c_str());
+ LOG_DEBUG("manufacturer name : %d", local_version_information.manufacturer_name_);
+ LOG_DEBUG("hci version : %x", (uint16_t)local_version_information.hci_version_);
+ LOG_DEBUG("lmp version : %x", (uint16_t)local_version_information.lmp_version_);
+ LOG_DEBUG("supported commands : %x", controller_->GetControllerLocalSupportedCommands()[0]);
+ LOG_DEBUG("local extended features :");
+
+ controller_->SetEventMask(0x00001FFFFFFFFFFF);
+ controller_->SetEventFilterInquiryResultAllDevices();
+ ClassOfDevice class_of_device({0xab, 0xcd, 0xef});
+ ClassOfDevice class_of_device_mask({0x12, 0x34, 0x56});
+ controller_->SetEventFilterInquiryResultClassOfDevice(class_of_device, class_of_device_mask);
+ Address bdaddr({0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc});
+ controller_->SetEventFilterInquiryResultAddress(bdaddr);
+ controller_->SetEventFilterConnectionSetupAllDevices(AutoAcceptFlag::AUTO_ACCEPT_OFF);
+ controller_->SetEventFilterConnectionSetupClassOfDevice(class_of_device, class_of_device_mask,
+ AutoAcceptFlag::AUTO_ACCEPT_ON_ROLE_SWITCH_DISABLED);
+ controller_->SetEventFilterConnectionSetupAddress(bdaddr, AutoAcceptFlag::AUTO_ACCEPT_ON_ROLE_SWITCH_ENABLED);
+ controller_->SetEventFilterClearAll();
+ controller_->HostBufferSize(0xFF00, 0xF1, 0xFF02, 0xFF03);
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status TestInternalHciLeCommands(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+ ::google::protobuf::Empty* response) {
+ LOG_DEBUG("le data packet length : %d", controller_->GetControllerLeBufferSize().le_data_packet_length_);
+ LOG_DEBUG("total num le packets : %d", controller_->GetControllerLeBufferSize().total_num_le_packets_);
+ LOG_DEBUG("le supported max tx octets : %d",
+ controller_->GetControllerLeMaximumDataLength().supported_max_tx_octets_);
+ LOG_DEBUG("le supported max tx times : %d", controller_->GetControllerLeMaximumDataLength().supported_max_tx_time_);
+ LOG_DEBUG("le supported max rx octets : %d",
+ controller_->GetControllerLeMaximumDataLength().supported_max_rx_octets_);
+ LOG_DEBUG("le supported max rx times : %d", controller_->GetControllerLeMaximumDataLength().supported_max_rx_time_);
+ LOG_DEBUG("le maximum advertising data length %d", controller_->GetControllerLeMaximumAdvertisingDataLength());
+ LOG_DEBUG("le number of supported advertising sets %d",
+ controller_->GetControllerLeNumberOfSupportedAdverisingSets());
+
+ controller_->LeSetEventMask(0x000000000000001F);
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status TestClassicConnectionManagementCommands(::grpc::ServerContext* context,
+ const facade::BluetoothAddress* request,
+ ::google::protobuf::Empty* response) {
+ Address peer;
+ Address::FromString(request->address(), peer);
+ auto connection = acl_connections_.find(request->address());
+ if (connection == acl_connections_.end()) {
+ LOG_ERROR("Invalid address");
+ return ::grpc::Status(::grpc::StatusCode::INVALID_ARGUMENT, "Invalid address");
+ } else {
+ // TODO add individual grpc command if necessary
+ connection->second->RoleDiscovery();
+ connection->second->WriteLinkPolicySettings(0x07);
+ connection->second->ReadLinkPolicySettings();
+ connection->second->SniffSubrating(0x1234, 0x1234, 0x1234);
+ connection->second->WriteAutomaticFlushTimeout(0x07FF);
+ connection->second->ReadAutomaticFlushTimeout();
+ connection->second->ReadTransmitPowerLevel(TransmitPowerLevelType::CURRENT);
+ connection->second->ReadTransmitPowerLevel(TransmitPowerLevelType::MAXIMUM);
+ connection->second->WriteLinkSupervisionTimeout(0x5678);
+ connection->second->ReadLinkSupervisionTimeout();
+ connection->second->ReadFailedContactCounter();
+ connection->second->ResetFailedContactCounter();
+ connection->second->ReadLinkQuality();
+ connection->second->ReadAfhChannelMap();
+ connection->second->ReadRssi();
+ connection->second->ReadClock(WhichClock::LOCAL);
+ connection->second->ReadClock(WhichClock::PICONET);
+
+ connection->second->ChangeConnectionPacketType(0xEE1C);
+ connection->second->SetConnectionEncryption(Enable::ENABLED);
+ connection->second->ChangeConnectionLinkKey();
+ connection->second->ReadClockOffset();
+ connection->second->HoldMode(0x0500, 0x0020);
+ connection->second->SniffMode(0x0500, 0x0020, 0x0040, 0x0014);
+ connection->second->ExitSniffMode();
+ connection->second->QosSetup(ServiceType::BEST_EFFORT, 0x1234, 0x1233, 0x1232, 0x1231);
+ connection->second->FlowSpecification(FlowDirection::OUTGOING_FLOW, ServiceType::BEST_EFFORT, 0x1234, 0x1233,
+ 0x1232, 0x1231);
+ connection->second->Flush();
+
+ acl_manager_->MasterLinkKey(KeyFlag::TEMPORARY);
+ acl_manager_->SwitchRole(peer, Role::MASTER);
+ acl_manager_->WriteDefaultLinkPolicySettings(0x07);
+ acl_manager_->ReadDefaultLinkPolicySettings();
+ return ::grpc::Status::OK;
+ }
+ }
+
+ void on_incoming_acl(std::string address) {
+ auto connection = acl_connections_.find(address);
+ if (connection == acl_connections_.end()) {
+ LOG_ERROR("Invalid address");
+ return;
+ }
+
+ auto packet = connection->second->GetAclQueueEnd()->TryDequeue();
+ auto acl_packet = AclPacketView::Create(*packet);
+ AclData acl_data;
+ acl_data.mutable_remote()->set_address(address);
+ std::string data = std::string(acl_packet.begin(), acl_packet.end());
+ acl_data.set_payload(data);
+ acl_stream_.OnIncomingEvent(acl_data);
+ }
+
+ void OnConnectSuccess(std::unique_ptr<::bluetooth::hci::AclConnection> connection) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ auto addr = connection->GetAddress();
+ std::shared_ptr<::bluetooth::hci::AclConnection> shared_connection = std::move(connection);
+ acl_connections_.emplace(addr.ToString(), shared_connection);
+ shared_connection->RegisterDisconnectCallback(
+ common::BindOnce(&AclManagerFacadeService::on_disconnect, common::Unretained(this), addr.ToString()),
+ facade_handler_);
+ shared_connection->RegisterCallbacks(this, facade_handler_);
+ connection_complete_stream_.OnIncomingEvent(shared_connection);
+ }
+
+ void OnMasterLinkKeyComplete(uint16_t connection_handle, KeyFlag key_flag) override {
+ LOG_DEBUG("OnMasterLinkKeyComplete connection_handle:%d", connection_handle);
+ }
+
+ void OnRoleChange(Address bd_addr, Role new_role) override {
+ LOG_DEBUG("OnRoleChange bd_addr:%s, new_role:%d", bd_addr.ToString().c_str(), (uint8_t)new_role);
+ }
+
+ void OnReadDefaultLinkPolicySettingsComplete(uint16_t default_link_policy_settings) override {
+ LOG_DEBUG("OnReadDefaultLinkPolicySettingsComplete default_link_policy_settings:%d", default_link_policy_settings);
+ }
+
+ void on_disconnect(std::string address, ErrorCode code) {
+ acl_connections_.erase(address);
+ DisconnectionEvent event;
+ event.mutable_remote()->set_address(address);
+ event.set_reason(static_cast<uint32_t>(code));
+ disconnection_stream_.OnIncomingEvent(event);
+ }
+
+ ::grpc::Status FetchConnectionComplete(::grpc::ServerContext* context, const EventStreamRequest* request,
+ ::grpc::ServerWriter<ConnectionEvent>* writer) override {
+ return connection_complete_stream_.HandleRequest(context, request, writer);
+ };
+
+ void OnConnectFail(Address address, ::bluetooth::hci::ErrorCode reason) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ ConnectionFailedEvent event;
+ event.mutable_remote()->set_address(address.ToString());
+ event.set_reason(static_cast<uint32_t>(reason));
+ connection_failed_stream_.OnIncomingEvent(event);
+ }
+
+ void OnConnectionPacketTypeChanged(uint16_t packet_type) override {
+ LOG_DEBUG("OnConnectionPacketTypeChanged packet_type:%d", packet_type);
+ }
+
+ void OnAuthenticationComplete() override {
+ LOG_DEBUG("OnAuthenticationComplete");
+ }
+
+ void OnEncryptionChange(EncryptionEnabled enabled) override {
+ LOG_DEBUG("OnConnectionPacketTypeChanged enabled:%d", (uint8_t)enabled);
+ }
+
+ void OnChangeConnectionLinkKeyComplete() override {
+ LOG_DEBUG("OnChangeConnectionLinkKeyComplete");
+ };
+
+ void OnReadClockOffsetComplete(uint16_t clock_offset) override {
+ LOG_DEBUG("OnReadClockOffsetComplete clock_offset:%d", clock_offset);
+ };
+
+ void OnModeChange(Mode current_mode, uint16_t interval) override {
+ LOG_DEBUG("OnModeChange Mode:%d, interval:%d", (uint8_t)current_mode, interval);
+ };
+
+ void OnQosSetupComplete(ServiceType service_type, uint32_t token_rate, uint32_t peak_bandwidth, uint32_t latency,
+ uint32_t delay_variation) override {
+ LOG_DEBUG("OnQosSetupComplete service_type:%d, token_rate:%d, peak_bandwidth:%d, latency:%d, delay_variation:%d",
+ (uint8_t)service_type, token_rate, peak_bandwidth, latency, delay_variation);
+ }
+
+ void OnFlowSpecificationComplete(FlowDirection flow_direction, ServiceType service_type, uint32_t token_rate,
+ uint32_t token_bucket_size, uint32_t peak_bandwidth,
+ uint32_t access_latency) override {
+ LOG_DEBUG(
+ "OnFlowSpecificationComplete flow_direction:%d. service_type:%d, token_rate:%d, token_bucket_size:%d, "
+ "peak_bandwidth:%d, access_latency:%d",
+ (uint8_t)flow_direction, (uint8_t)service_type, token_rate, token_bucket_size, peak_bandwidth, access_latency);
+ }
+
+ void OnFlushOccurred() override {
+ LOG_DEBUG("OnFlushOccurred");
+ }
+
+ void OnRoleDiscoveryComplete(Role current_role) override {
+ LOG_DEBUG("OnRoleDiscoveryComplete current_role:%d", (uint8_t)current_role);
+ }
+
+ void OnReadLinkPolicySettingsComplete(uint16_t link_policy_settings) override {
+ LOG_DEBUG("OnReadLinkPolicySettingsComplete link_policy_settings:%d", link_policy_settings);
+ }
+
+ void OnReadAutomaticFlushTimeoutComplete(uint16_t flush_timeout) override {
+ LOG_DEBUG("OnReadAutomaticFlushTimeoutComplete flush_timeout:%d", flush_timeout);
+ }
+
+ void OnReadTransmitPowerLevelComplete(uint8_t transmit_power_level) override {
+ LOG_DEBUG("OnReadTransmitPowerLevelComplete transmit_power_level:%d", transmit_power_level);
+ }
+
+ void OnReadLinkSupervisionTimeoutComplete(uint16_t link_supervision_timeout) override {
+ LOG_DEBUG("OnReadLinkSupervisionTimeoutComplete link_supervision_timeout:%d", link_supervision_timeout);
+ }
+
+ void OnReadFailedContactCounterComplete(uint16_t failed_contact_counter) override {
+ LOG_DEBUG("OnReadFailedContactCounterComplete failed_contact_counter:%d", failed_contact_counter);
+ }
+
+ void OnReadLinkQualityComplete(uint8_t link_quality) override {
+ LOG_DEBUG("OnReadLinkQualityComplete link_quality:%d", link_quality);
+ }
+
+ void OnReadAfhChannelMapComplete(AfhMode afh_mode, std::array<uint8_t, 10> afh_channel_map) {
+ LOG_DEBUG("OnReadAfhChannelMapComplete afh_mode:%d", (uint8_t)afh_mode);
+ }
+
+ void OnReadRssiComplete(uint8_t rssi) override {
+ LOG_DEBUG("OnReadRssiComplete rssi:%d", rssi);
+ }
+
+ void OnReadClockComplete(uint32_t clock, uint16_t accuracy) override {
+ LOG_DEBUG("OnReadClockComplete clock:%d, accuracy:%d", clock, accuracy);
+ }
+
+ ::grpc::Status FetchConnectionFailed(::grpc::ServerContext* context, const EventStreamRequest* request,
+ ::grpc::ServerWriter<ConnectionFailedEvent>* writer) override {
+ return connection_failed_stream_.HandleRequest(context, request, writer);
+ };
+
+ ::grpc::Status FetchDisconnection(::grpc::ServerContext* context,
+ const ::bluetooth::facade::EventStreamRequest* request,
+ ::grpc::ServerWriter<DisconnectionEvent>* writer) override {
+ return disconnection_stream_.HandleRequest(context, request, writer);
+ }
+
+ private:
+ AclManager* acl_manager_;
+ Controller* controller_;
+ HciLayer* hci_layer_;
+ mutable std::mutex mutex_;
+ ::bluetooth::os::Handler* facade_handler_;
+
+ class ConnectionCompleteStreamCallback
+ : public ::bluetooth::grpc::GrpcEventStreamCallback<ConnectionEvent, std::shared_ptr<AclConnection>> {
+ public:
+ void OnWriteResponse(ConnectionEvent* response, const std::shared_ptr<AclConnection>& connection) override {
+ response->mutable_remote()->set_address(connection->GetAddress().ToString());
+ response->set_connection_handle(connection->GetHandle());
+ }
+ } connection_complete_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<ConnectionEvent, std::shared_ptr<AclConnection>> connection_complete_stream_{
+ &connection_complete_stream_callback_};
+
+ class ConnectionFailedStreamCallback
+ : public ::bluetooth::grpc::GrpcEventStreamCallback<ConnectionFailedEvent, ConnectionFailedEvent> {
+ public:
+ void OnWriteResponse(ConnectionFailedEvent* response, const ConnectionFailedEvent& event) override {
+ response->CopyFrom(event);
+ }
+ } connection_failed_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<ConnectionFailedEvent, ConnectionFailedEvent> connection_failed_stream_{
+ &connection_failed_stream_callback_};
+
+ class DisconnectionStreamCallback
+ : public ::bluetooth::grpc::GrpcEventStreamCallback<DisconnectionEvent, DisconnectionEvent> {
+ public:
+ void OnWriteResponse(DisconnectionEvent* response, const DisconnectionEvent& event) override {
+ response->CopyFrom(event);
+ }
+ } disconnection_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<DisconnectionEvent, DisconnectionEvent> disconnection_stream_{
+ &disconnection_stream_callback_};
+
+ class AclStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<AclData, AclData> {
+ public:
+ AclStreamCallback(AclManagerFacadeService* service) : service_(service) {}
+
+ ~AclStreamCallback() {
+ if (subscribed_) {
+ for (const auto& connection : service_->acl_connections_) {
+ connection.second->GetAclQueueEnd()->UnregisterDequeue();
+ }
+ subscribed_ = false;
+ }
+ }
+
+ void OnSubscribe() override {
+ if (subscribed_) {
+ LOG_WARN("Already subscribed");
+ return;
+ }
+ for (const auto& connection : service_->acl_connections_) {
+ auto remote_address = connection.second->GetAddress().ToString();
+ connection.second->GetAclQueueEnd()->RegisterDequeue(
+ service_->facade_handler_,
+ common::Bind(&AclManagerFacadeService::on_incoming_acl, common::Unretained(service_), remote_address));
+ }
+ subscribed_ = true;
+ }
+
+ void OnUnsubscribe() override {
+ if (!subscribed_) {
+ LOG_WARN("Not subscribed");
+ return;
+ }
+ for (const auto& connection : service_->acl_connections_) {
+ connection.second->GetAclQueueEnd()->UnregisterDequeue();
+ }
+ subscribed_ = false;
+ }
+
+ void OnWriteResponse(AclData* response, const AclData& event) override {
+ response->CopyFrom(event);
+ }
+
+ private:
+ AclManagerFacadeService* service_;
+ bool subscribed_ = false;
+ } acl_stream_callback_{this};
+ ::bluetooth::grpc::GrpcEventStream<AclData, AclData> acl_stream_{&acl_stream_callback_};
+
+ std::map<std::string, std::shared_ptr<AclConnection>> acl_connections_;
+};
+
+void AclManagerFacadeModule::ListDependencies(ModuleList* list) {
+ ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
+ list->add<AclManager>();
+ list->add<Controller>();
+ list->add<HciLayer>();
+}
+
+void AclManagerFacadeModule::Start() {
+ ::bluetooth::grpc::GrpcFacadeModule::Start();
+ service_ = new AclManagerFacadeService(GetDependency<AclManager>(), GetDependency<Controller>(),
+ GetDependency<HciLayer>(), GetHandler());
+}
+
+void AclManagerFacadeModule::Stop() {
+ delete service_;
+ ::bluetooth::grpc::GrpcFacadeModule::Stop();
+}
+
+::grpc::Service* AclManagerFacadeModule::GetService() const {
+ return service_;
+}
+
+const ModuleFactory AclManagerFacadeModule::Factory =
+ ::bluetooth::ModuleFactory([]() { return new AclManagerFacadeModule(); });
+
+class ClassicSecurityManagerFacadeService : public ClassicSecurityManagerFacade::Service,
+ public ::bluetooth::hci::ClassicSecurityCommandCallbacks {
+ public:
+ ClassicSecurityManagerFacadeService(ClassicSecurityManager* classic_security_manager, Controller* controller,
+ HciLayer* hci_layer, ::bluetooth::os::Handler* facade_handler)
+ : classic_security_manager_(classic_security_manager), facade_handler_(facade_handler) {
+ classic_security_manager_->RegisterCallbacks(this, facade_handler_);
+ }
+
+ ::grpc::Status LinkKeyRequestReply(::grpc::ServerContext* context,
+ const ::bluetooth::hci::LinkKeyRequestReplyMessage* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ Address peer;
+ common::LinkKey link_key;
+ ASSERT(Address::FromString(request->remote().address(), peer));
+ ASSERT(common::LinkKey::FromString(request->link_key(), link_key));
+ classic_security_manager_->LinkKeyRequestReply(peer, link_key);
+ return ::grpc::Status::OK;
+ };
+
+ ::grpc::Status LinkKeyRequestNegativeReply(::grpc::ServerContext* context,
+ const ::bluetooth::facade::BluetoothAddress* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ Address peer;
+ ASSERT(Address::FromString(request->address(), peer));
+ classic_security_manager_->LinkKeyRequestNegativeReply(peer);
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status PinCodeRequestReply(::grpc::ServerContext* context,
+ const ::bluetooth::hci::PinCodeRequestReplyMessage* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ Address peer;
+ ASSERT(Address::FromString(request->remote().address(), peer));
+ uint8_t len = request->len();
+ std::string pin_code = request->pin_code();
+ classic_security_manager_->PinCodeRequestReply(peer, len, pin_code);
+ return ::grpc::Status::OK;
+ };
+
+ ::grpc::Status PinCodeRequestNegativeReply(::grpc::ServerContext* context,
+ const ::bluetooth::facade::BluetoothAddress* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ Address peer;
+ ASSERT(Address::FromString(request->address(), peer));
+ classic_security_manager_->PinCodeRequestNegativeReply(peer);
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status IoCapabilityRequestReply(::grpc::ServerContext* context,
+ const ::bluetooth::hci::IoCapabilityRequestReplyMessage* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ Address peer;
+ ASSERT(Address::FromString(request->remote().address(), peer));
+ IoCapability io_capability = (IoCapability)request->io_capability();
+ OobDataPresent oob_present = (OobDataPresent)request->oob_present();
+ AuthenticationRequirements authentication_requirements =
+ (AuthenticationRequirements)request->authentication_requirements();
+ classic_security_manager_->IoCapabilityRequestReply(peer, io_capability, oob_present, authentication_requirements);
+ return ::grpc::Status::OK;
+ };
+
+ ::grpc::Status IoCapabilityRequestNegativeReply(
+ ::grpc::ServerContext* context, const ::bluetooth::hci::IoCapabilityRequestNegativeReplyMessage* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ Address peer;
+ ASSERT(Address::FromString(request->remote().address(), peer));
+ ErrorCode reason = (ErrorCode)request->reason();
+ classic_security_manager_->IoCapabilityRequestNegativeReply(peer, reason);
+ return ::grpc::Status::OK;
+ };
+
+ ::grpc::Status UserConfirmationRequestReply(::grpc::ServerContext* context,
+ const ::bluetooth::facade::BluetoothAddress* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ Address peer;
+ ASSERT(Address::FromString(request->address(), peer));
+ classic_security_manager_->UserConfirmationRequestReply(peer);
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status UserConfirmationRequestNegativeReply(::grpc::ServerContext* context,
+ const ::bluetooth::facade::BluetoothAddress* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ Address peer;
+ ASSERT(Address::FromString(request->address(), peer));
+ classic_security_manager_->UserConfirmationRequestNegativeReply(peer);
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status UserPasskeyRequestReply(::grpc::ServerContext* context,
+ const ::bluetooth::hci::UserPasskeyRequestReplyMessage* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ Address peer;
+ ASSERT(Address::FromString(request->remote().address(), peer));
+ uint32_t passkey = request->passkey();
+ classic_security_manager_->UserPasskeyRequestReply(peer, passkey);
+ return ::grpc::Status::OK;
+ };
+
+ ::grpc::Status UserPasskeyRequestNegativeReply(::grpc::ServerContext* context,
+ const ::bluetooth::facade::BluetoothAddress* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ Address peer;
+ ASSERT(Address::FromString(request->address(), peer));
+ classic_security_manager_->UserPasskeyRequestNegativeReply(peer);
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status RemoteOobDataRequestReply(::grpc::ServerContext* context,
+ const ::bluetooth::hci::RemoteOobDataRequestReplyMessage* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ Address peer;
+ ASSERT(Address::FromString(request->remote().address(), peer));
+ std::string c_string = request->c();
+ std::string r_string = request->r();
+ std::array<uint8_t, 16> c;
+ std::array<uint8_t, 16> r;
+ std::copy(std::begin(c_string), std::end(c_string), std::begin(c));
+ std::copy(std::begin(r_string), std::end(r_string), std::begin(r));
+ classic_security_manager_->RemoteOobDataRequestReply(peer, c, r);
+ return ::grpc::Status::OK;
+ };
+
+ ::grpc::Status RemoteOobDataRequestNegativeReply(::grpc::ServerContext* context,
+ const ::bluetooth::facade::BluetoothAddress* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ Address peer;
+ ASSERT(Address::FromString(request->address(), peer));
+ classic_security_manager_->RemoteOobDataRequestNegativeReply(peer);
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status ReadStoredLinkKey(::grpc::ServerContext* context,
+ const ::bluetooth::hci::ReadStoredLinkKeyMessage* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ Address peer;
+ ASSERT(Address::FromString(request->remote().address(), peer));
+ ReadStoredLinkKeyReadAllFlag read_all_flag = (ReadStoredLinkKeyReadAllFlag)request->read_all_flag();
+ classic_security_manager_->ReadStoredLinkKey(peer, read_all_flag);
+ return ::grpc::Status::OK;
+ };
+
+ ::grpc::Status WriteStoredLinkKey(::grpc::ServerContext* context,
+ const ::bluetooth::hci::WriteStoredLinkKeyMessage* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ uint8_t num_keys_to_write = request->num_keys_to_write();
+ std::vector<KeyAndAddress> keys;
+ for (size_t i = 0; i < num_keys_to_write; i++) {
+ KeyAndAddress key;
+ common::LinkKey link_key;
+ ASSERT(Address::FromString(request->remote().address(), key.address_));
+ ASSERT(common::LinkKey::FromString(request->link_keys(), link_key));
+ std::copy(std::begin(link_key.link_key), std::end(link_key.link_key), std::begin(key.link_key_));
+ keys.push_back(key);
+ }
+
+ classic_security_manager_->WriteStoredLinkKey(keys);
+ return ::grpc::Status::OK;
+ };
+
+ ::grpc::Status DeleteStoredLinkKey(::grpc::ServerContext* context,
+ const ::bluetooth::hci::DeleteStoredLinkKeyMessage* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ Address peer;
+ ASSERT(Address::FromString(request->remote().address(), peer));
+ DeleteStoredLinkKeyDeleteAllFlag delete_all_flag = (DeleteStoredLinkKeyDeleteAllFlag)request->delete_all_flag();
+ classic_security_manager_->DeleteStoredLinkKey(peer, delete_all_flag);
+ return ::grpc::Status::OK;
+ };
+
+ ::grpc::Status RefreshEncryptionKey(::grpc::ServerContext* context,
+ const ::bluetooth::hci::RefreshEncryptionKeyMessage* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ classic_security_manager_->RefreshEncryptionKey(request->connection_handle());
+ return ::grpc::Status::OK;
+ };
+
+ ::grpc::Status ReadSimplePairingMode(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ classic_security_manager_->ReadSimplePairingMode();
+ return ::grpc::Status::OK;
+ };
+
+ ::grpc::Status WriteSimplePairingMode(::grpc::ServerContext* context,
+ const ::bluetooth::hci::WriteSimplePairingModeMessage* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ Enable simple_pairing_mode = (Enable)request->simple_pairing_mode();
+ classic_security_manager_->WriteSimplePairingMode(simple_pairing_mode);
+ return ::grpc::Status::OK;
+ };
+
+ ::grpc::Status ReadLocalOobData(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ classic_security_manager_->ReadLocalOobData();
+ return ::grpc::Status::OK;
+ };
+
+ ::grpc::Status SendKeypressNotification(::grpc::ServerContext* context,
+ const ::bluetooth::hci::SendKeypressNotificationMessage* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ Address peer;
+ ASSERT(Address::FromString(request->remote().address(), peer));
+ KeypressNotificationType notification_type = (KeypressNotificationType)request->notification_type();
+ classic_security_manager_->SendKeypressNotification(peer, notification_type);
+ return ::grpc::Status::OK;
+ };
+
+ ::grpc::Status ReadLocalOobExtendedData(::grpc::ServerContext* context, const ::google::protobuf::Empty* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ classic_security_manager_->ReadLocalOobExtendedData();
+ return ::grpc::Status::OK;
+ };
+
+ ::grpc::Status ReadEncryptionKeySize(::grpc::ServerContext* context,
+ const ::bluetooth::hci::ReadEncryptionKeySizeMessage* request,
+ ::google::protobuf::Empty* response) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ classic_security_manager_->ReadEncryptionKeySize(request->connection_handle());
+ return ::grpc::Status::OK;
+ };
+
+ ::grpc::Status FetchCommandCompleteEvent(::grpc::ServerContext* context, const EventStreamRequest* request,
+ ::grpc::ServerWriter<CommandCompleteEvent>* writer) override {
+ return command_complete_stream_.HandleRequest(context, request, writer);
+ };
+
+ void OnCommandComplete(CommandCompleteView status) override {
+ std::unique_lock<std::mutex> lock(mutex_);
+ command_complete_stream_.OnIncomingEvent(status);
+ }
+
+ private:
+ ClassicSecurityManager* classic_security_manager_;
+ mutable std::mutex mutex_;
+ ::bluetooth::os::Handler* facade_handler_;
+
+ class CommandCompleteStreamCallback
+ : public ::bluetooth::grpc::GrpcEventStreamCallback<CommandCompleteEvent, CommandCompleteView> {
+ public:
+ void OnWriteResponse(CommandCompleteEvent* response, CommandCompleteView const& status) override {
+ response->set_command_opcode((uint32_t)status.GetCommandOpCode());
+ }
+ } command_complete_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<CommandCompleteEvent, CommandCompleteView> command_complete_stream_{
+ &command_complete_stream_callback_};
+};
+
+void ClassicSecurityManagerFacadeModule::ListDependencies(ModuleList* list) {
+ ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
+ list->add<ClassicSecurityManager>();
+ list->add<Controller>();
+ list->add<HciLayer>();
+}
+
+void ClassicSecurityManagerFacadeModule::Start() {
+ ::bluetooth::grpc::GrpcFacadeModule::Start();
+ service_ = new ClassicSecurityManagerFacadeService(
+ GetDependency<ClassicSecurityManager>(), GetDependency<Controller>(), GetDependency<HciLayer>(), GetHandler());
+}
+
+void ClassicSecurityManagerFacadeModule::Stop() {
+ delete service_;
+ ::bluetooth::grpc::GrpcFacadeModule::Stop();
+}
+
+::grpc::Service* ClassicSecurityManagerFacadeModule::GetService() const {
+ return service_;
+}
+
+const ModuleFactory ClassicSecurityManagerFacadeModule::Factory =
+ ::bluetooth::ModuleFactory([]() { return new ClassicSecurityManagerFacadeModule(); });
+
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/facade.h b/gd/hci/facade.h
new file mode 100644
index 0000000..b38286d
--- /dev/null
+++ b/gd/hci/facade.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <grpc++/grpc++.h>
+
+#include "grpc/grpc_module.h"
+#include "hci/acl_manager.h"
+
+namespace bluetooth {
+namespace hci {
+
+class AclManagerFacadeService;
+
+class AclManagerFacadeModule : public ::bluetooth::grpc::GrpcFacadeModule {
+ public:
+ static const ModuleFactory Factory;
+
+ void ListDependencies(ModuleList* list) override;
+ void Start() override;
+ void Stop() override;
+ ::grpc::Service* GetService() const override;
+
+ private:
+ AclManagerFacadeService* service_;
+};
+
+class ClassicSecurityManagerFacadeService;
+
+class ClassicSecurityManagerFacadeModule : public ::bluetooth::grpc::GrpcFacadeModule {
+ public:
+ static const ModuleFactory Factory;
+
+ void ListDependencies(ModuleList* list) override;
+ void Start() override;
+ void Stop() override;
+ ::grpc::Service* GetService() const override;
+
+ private:
+ ClassicSecurityManagerFacadeService* service_;
+};
+
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/facade.proto b/gd/hci/facade.proto
new file mode 100644
index 0000000..b9899e6
--- /dev/null
+++ b/gd/hci/facade.proto
@@ -0,0 +1,158 @@
+syntax = "proto3";
+
+package bluetooth.hci;
+
+import "google/protobuf/empty.proto";
+import "facade/common.proto";
+
+service AclManagerFacade {
+ rpc SetPageScanMode(PageScanMode) returns (google.protobuf.Empty) {}
+ rpc Connect(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
+ rpc Disconnect(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
+ rpc AuthenticationRequested(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
+ rpc FetchConnectionComplete(facade.EventStreamRequest) returns (stream ConnectionEvent) {}
+ rpc FetchDisconnection(facade.EventStreamRequest) returns (stream DisconnectionEvent) {}
+ rpc FetchConnectionFailed(facade.EventStreamRequest) returns (stream ConnectionFailedEvent) {}
+ rpc SendAclData(AclData) returns (google.protobuf.Empty) {}
+ rpc FetchAclData(facade.EventStreamRequest) returns (stream AclData) {}
+ rpc TestInternalHciCommands(google.protobuf.Empty) returns (google.protobuf.Empty) {}
+ rpc TestInternalHciLeCommands(google.protobuf.Empty) returns (google.protobuf.Empty) {}
+ rpc TestClassicConnectionManagementCommands(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
+}
+
+message PageScanMode {
+ bool enabled = 1;
+}
+
+message ConnectionEvent {
+ facade.BluetoothAddress remote = 1;
+ uint32 connection_handle = 2;
+}
+
+message DisconnectionEvent {
+ facade.BluetoothAddress remote = 1;
+ uint32 reason = 2;
+}
+
+message ConnectionFailedEvent {
+ facade.BluetoothAddress remote = 1;
+ uint32 reason = 2;
+}
+
+message AclData {
+ facade.BluetoothAddress remote = 1;
+ bytes payload = 2;
+}
+
+service ClassicPairingFacade {
+ rpc SetPairingMode(PairingMode) returns (google.protobuf.Empty) {}
+ rpc DeletePairing(DeletePairingRequest) returns (google.protobuf.Empty) {}
+}
+
+message PairingMode {
+ bool enabled = 1;
+}
+
+message DeletePairingRequest {
+ bool deleteAll = 1;
+ facade.BluetoothAddress remote = 2;
+}
+
+service ClassicSecurityManagerFacade {
+ rpc LinkKeyRequestReply(LinkKeyRequestReplyMessage) returns (google.protobuf.Empty) {}
+ rpc LinkKeyRequestNegativeReply(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
+ rpc PinCodeRequestReply(PinCodeRequestReplyMessage) returns (google.protobuf.Empty) {}
+ rpc PinCodeRequestNegativeReply(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
+ rpc IoCapabilityRequestReply(IoCapabilityRequestReplyMessage) returns (google.protobuf.Empty) {}
+ rpc IoCapabilityRequestNegativeReply(IoCapabilityRequestNegativeReplyMessage) returns (google.protobuf.Empty) {}
+ rpc UserConfirmationRequestReply(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
+ rpc UserConfirmationRequestNegativeReply(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
+ rpc UserPasskeyRequestReply(UserPasskeyRequestReplyMessage) returns (google.protobuf.Empty) {}
+ rpc UserPasskeyRequestNegativeReply(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
+ rpc RemoteOobDataRequestReply(RemoteOobDataRequestReplyMessage) returns (google.protobuf.Empty) {}
+ rpc RemoteOobDataRequestNegativeReply(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
+ rpc ReadStoredLinkKey(ReadStoredLinkKeyMessage) returns (google.protobuf.Empty) {}
+ rpc WriteStoredLinkKey(WriteStoredLinkKeyMessage) returns (google.protobuf.Empty) {}
+ rpc DeleteStoredLinkKey(DeleteStoredLinkKeyMessage) returns (google.protobuf.Empty) {}
+ rpc RefreshEncryptionKey(RefreshEncryptionKeyMessage) returns (google.protobuf.Empty) {}
+ rpc ReadSimplePairingMode(google.protobuf.Empty) returns (google.protobuf.Empty) {}
+ rpc WriteSimplePairingMode(WriteSimplePairingModeMessage) returns (google.protobuf.Empty) {}
+ rpc ReadLocalOobData(google.protobuf.Empty) returns (google.protobuf.Empty) {}
+ rpc SendKeypressNotification(SendKeypressNotificationMessage) returns (google.protobuf.Empty) {}
+ rpc ReadLocalOobExtendedData(google.protobuf.Empty) returns (google.protobuf.Empty) {}
+ rpc ReadEncryptionKeySize(ReadEncryptionKeySizeMessage) returns (google.protobuf.Empty) {}
+
+ rpc FetchCommandCompleteEvent(facade.EventStreamRequest) returns (stream CommandCompleteEvent) {}
+}
+
+
+message CommandCompleteEvent {
+ uint32 command_opcode = 1;
+}
+
+message LinkKeyRequestReplyMessage {
+ facade.BluetoothAddress remote = 1;
+ bytes link_key = 2;
+}
+
+message PinCodeRequestReplyMessage {
+ facade.BluetoothAddress remote = 1;
+ uint32 len = 2;
+ bytes pin_code = 3;
+}
+
+message IoCapabilityRequestReplyMessage {
+ facade.BluetoothAddress remote = 1;
+ uint32 io_capability = 2;
+ uint32 oob_present = 3;
+ uint32 authentication_requirements = 4;
+}
+
+message IoCapabilityRequestNegativeReplyMessage {
+ facade.BluetoothAddress remote = 1;
+ uint32 reason = 2;
+}
+
+message UserPasskeyRequestReplyMessage {
+ facade.BluetoothAddress remote = 1;
+ uint32 passkey = 2;
+}
+
+message RemoteOobDataRequestReplyMessage {
+ facade.BluetoothAddress remote = 1;
+ bytes c = 2;
+ bytes r = 3;
+}
+
+message ReadStoredLinkKeyMessage {
+ facade.BluetoothAddress remote = 1;
+ uint32 read_all_flag = 2;
+}
+
+message WriteStoredLinkKeyMessage {
+ uint32 num_keys_to_write = 1;
+ facade.BluetoothAddress remote = 2;
+ bytes link_keys = 3;
+}
+
+message DeleteStoredLinkKeyMessage {
+ facade.BluetoothAddress remote = 1;
+ uint32 delete_all_flag = 2;
+}
+
+message RefreshEncryptionKeyMessage {
+ uint32 connection_handle = 1;
+}
+
+message WriteSimplePairingModeMessage {
+ uint32 simple_pairing_mode = 1;
+}
+
+message SendKeypressNotificationMessage {
+ facade.BluetoothAddress remote = 1;
+ uint32 notification_type = 2;
+}
+
+message ReadEncryptionKeySizeMessage {
+ uint32 connection_handle = 1;
+}
\ No newline at end of file
diff --git a/gd/hci/hci_layer.cc b/gd/hci/hci_layer.cc
new file mode 100644
index 0000000..5d903de
--- /dev/null
+++ b/gd/hci/hci_layer.cc
@@ -0,0 +1,529 @@
+/*
+ * Copyright 2019 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 "hci/hci_layer.h"
+
+#include "common/bind.h"
+#include "common/callback.h"
+#include "os/alarm.h"
+#include "os/queue.h"
+#include "packet/packet_builder.h"
+
+namespace {
+using bluetooth::common::Bind;
+using bluetooth::common::BindOnce;
+using bluetooth::common::Callback;
+using bluetooth::common::Closure;
+using bluetooth::common::OnceCallback;
+using bluetooth::common::OnceClosure;
+using bluetooth::hci::CommandCompleteView;
+using bluetooth::hci::CommandPacketBuilder;
+using bluetooth::hci::CommandStatusView;
+using bluetooth::hci::EventPacketView;
+using bluetooth::hci::LeMetaEventView;
+using bluetooth::os::Handler;
+
+class EventHandler {
+ public:
+ EventHandler() : event_handler(), handler(nullptr) {}
+ EventHandler(Callback<void(EventPacketView)> on_event, Handler* on_event_handler)
+ : event_handler(std::move(on_event)), handler(on_event_handler) {}
+ Callback<void(EventPacketView)> event_handler;
+ Handler* handler;
+};
+
+class SubeventHandler {
+ public:
+ SubeventHandler() : subevent_handler(), handler(nullptr) {}
+ SubeventHandler(Callback<void(LeMetaEventView)> on_event, Handler* on_event_handler)
+ : subevent_handler(std::move(on_event)), handler(on_event_handler) {}
+ Callback<void(LeMetaEventView)> subevent_handler;
+ Handler* handler;
+};
+
+class CommandQueueEntry {
+ public:
+ CommandQueueEntry(std::unique_ptr<CommandPacketBuilder> command_packet,
+ OnceCallback<void(CommandCompleteView)> on_complete_function, Handler* handler)
+ : command(std::move(command_packet)), waiting_for_status_(false), on_complete(std::move(on_complete_function)),
+ caller_handler(handler) {}
+
+ CommandQueueEntry(std::unique_ptr<CommandPacketBuilder> command_packet,
+ OnceCallback<void(CommandStatusView)> on_status_function, Handler* handler)
+ : command(std::move(command_packet)), waiting_for_status_(true), on_status(std::move(on_status_function)),
+ caller_handler(handler) {}
+
+ std::unique_ptr<CommandPacketBuilder> command;
+ bool waiting_for_status_;
+ OnceCallback<void(CommandStatusView)> on_status;
+ OnceCallback<void(CommandCompleteView)> on_complete;
+ Handler* caller_handler;
+};
+} // namespace
+
+namespace bluetooth {
+namespace hci {
+
+using common::BidiQueue;
+using common::BidiQueueEnd;
+using os::Alarm;
+using os::Handler;
+
+namespace {
+using hci::OpCode;
+using hci::ResetCompleteView;
+
+void fail_if_reset_complete_not_success(CommandCompleteView complete) {
+ auto reset_complete = ResetCompleteView::Create(complete);
+ ASSERT(reset_complete.IsValid());
+ ASSERT(reset_complete.GetStatus() == ErrorCode::SUCCESS);
+}
+
+void on_hci_timeout(OpCode op_code) {
+ ASSERT_LOG(false, "Timed out waiting for 0x%02hx (%s)", op_code, OpCodeText(op_code).c_str());
+}
+} // namespace
+
+class SecurityInterfaceImpl : public SecurityInterface {
+ public:
+ SecurityInterfaceImpl(HciLayer& hci) : hci_(hci) {}
+ virtual ~SecurityInterfaceImpl() = default;
+
+ virtual void EnqueueCommand(std::unique_ptr<SecurityCommandBuilder> command,
+ common::OnceCallback<void(CommandCompleteView)> on_complete,
+ os::Handler* handler) override {
+ hci_.EnqueueCommand(std::move(command), std::move(on_complete), handler);
+ }
+
+ virtual void EnqueueCommand(std::unique_ptr<SecurityCommandBuilder> command,
+ common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) override {
+ hci_.EnqueueCommand(std::move(command), std::move(on_status), handler);
+ }
+ HciLayer& hci_;
+};
+
+class LeSecurityInterfaceImpl : public LeSecurityInterface {
+ public:
+ LeSecurityInterfaceImpl(HciLayer& hci) : hci_(hci) {}
+ virtual ~LeSecurityInterfaceImpl() = default;
+
+ virtual void EnqueueCommand(std::unique_ptr<LeSecurityCommandBuilder> command,
+ common::OnceCallback<void(CommandCompleteView)> on_complete,
+ os::Handler* handler) override {
+ hci_.EnqueueCommand(std::move(command), std::move(on_complete), handler);
+ }
+
+ virtual void EnqueueCommand(std::unique_ptr<LeSecurityCommandBuilder> command,
+ common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) override {
+ hci_.EnqueueCommand(std::move(command), std::move(on_status), handler);
+ }
+ HciLayer& hci_;
+};
+
+class LeAdvertisingInterfaceImpl : public LeAdvertisingInterface {
+ public:
+ LeAdvertisingInterfaceImpl(HciLayer& hci) : hci_(hci) {}
+ virtual ~LeAdvertisingInterfaceImpl() = default;
+
+ virtual void EnqueueCommand(std::unique_ptr<LeAdvertisingCommandBuilder> command,
+ common::OnceCallback<void(CommandCompleteView)> on_complete,
+ os::Handler* handler) override {
+ hci_.EnqueueCommand(std::move(command), std::move(on_complete), handler);
+ }
+
+ virtual void EnqueueCommand(std::unique_ptr<LeAdvertisingCommandBuilder> command,
+ common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) override {
+ hci_.EnqueueCommand(std::move(command), std::move(on_status), handler);
+ }
+ HciLayer& hci_;
+};
+
+class LeScanningInterfaceImpl : public LeScanningInterface {
+ public:
+ LeScanningInterfaceImpl(HciLayer& hci) : hci_(hci) {}
+ virtual ~LeScanningInterfaceImpl() = default;
+
+ virtual void EnqueueCommand(std::unique_ptr<LeScanningCommandBuilder> command,
+ common::OnceCallback<void(CommandCompleteView)> on_complete,
+ os::Handler* handler) override {
+ hci_.EnqueueCommand(std::move(command), std::move(on_complete), handler);
+ }
+
+ virtual void EnqueueCommand(std::unique_ptr<LeScanningCommandBuilder> command,
+ common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) override {
+ hci_.EnqueueCommand(std::move(command), std::move(on_status), handler);
+ }
+ HciLayer& hci_;
+};
+
+struct HciLayer::impl : public hal::HciHalCallbacks {
+ impl(HciLayer& module) : hal_(nullptr), module_(module) {}
+
+ ~impl() {}
+
+ void Start(hal::HciHal* hal) {
+ hal_ = hal;
+ hci_timeout_alarm_ = new Alarm(module_.GetHandler());
+
+ auto queue_end = acl_queue_.GetDownEnd();
+ Handler* handler = module_.GetHandler();
+ queue_end->RegisterDequeue(handler, Bind(&impl::dequeue_and_send_acl, common::Unretained(this)));
+ RegisterEventHandler(EventCode::COMMAND_COMPLETE, Bind(&impl::command_complete_callback, common::Unretained(this)),
+ handler);
+ RegisterEventHandler(EventCode::COMMAND_STATUS, Bind(&impl::command_status_callback, common::Unretained(this)),
+ handler);
+ RegisterEventHandler(EventCode::LE_META_EVENT, Bind(&impl::le_meta_event_callback, common::Unretained(this)),
+ handler);
+ // TODO find the right place
+ RegisterEventHandler(EventCode::PAGE_SCAN_REPETITION_MODE_CHANGE, Bind(&impl::drop, common::Unretained(this)),
+ handler);
+ RegisterEventHandler(EventCode::MAX_SLOTS_CHANGE, Bind(&impl::drop, common::Unretained(this)), handler);
+ RegisterEventHandler(EventCode::VENDOR_SPECIFIC, Bind(&impl::drop, common::Unretained(this)), handler);
+
+ EnqueueCommand(ResetBuilder::Create(), BindOnce(&fail_if_reset_complete_not_success), handler);
+ hal_->registerIncomingPacketCallback(this);
+ }
+
+ void drop(EventPacketView) {}
+
+ void dequeue_and_send_acl() {
+ auto packet = acl_queue_.GetDownEnd()->TryDequeue();
+ send_acl(std::move(packet));
+ }
+
+ void Stop() {
+ hal_->unregisterIncomingPacketCallback();
+ acl_queue_.GetDownEnd()->UnregisterDequeue();
+ incoming_acl_packet_buffer_.Clear();
+ delete hci_timeout_alarm_;
+ command_queue_.clear();
+ hal_ = nullptr;
+ }
+
+ void send_acl(std::unique_ptr<hci::BasePacketBuilder> packet) {
+ std::vector<uint8_t> bytes;
+ BitInserter bi(bytes);
+ packet->Serialize(bi);
+ hal_->sendAclData(bytes);
+ }
+
+ void send_sco(std::unique_ptr<hci::BasePacketBuilder> packet) {
+ std::vector<uint8_t> bytes;
+ BitInserter bi(bytes);
+ packet->Serialize(bi);
+ hal_->sendScoData(bytes);
+ }
+
+ void command_status_callback(EventPacketView event) {
+ CommandStatusView status_view = CommandStatusView::Create(event);
+ ASSERT(status_view.IsValid());
+ command_credits_ = status_view.GetNumHciCommandPackets();
+ OpCode op_code = status_view.GetCommandOpCode();
+ if (op_code == OpCode::NONE) {
+ send_next_command();
+ return;
+ }
+ ASSERT_LOG(!command_queue_.empty(), "Unexpected status event with OpCode 0x%02hx (%s)", op_code,
+ OpCodeText(op_code).c_str());
+ ASSERT_LOG(waiting_command_ == op_code, "Waiting for 0x%02hx (%s), got 0x%02hx (%s)", waiting_command_,
+ OpCodeText(waiting_command_).c_str(), op_code, OpCodeText(op_code).c_str());
+ ASSERT_LOG(command_queue_.front().waiting_for_status_,
+ "Waiting for command complete 0x%02hx (%s), got command status for 0x%02hx (%s)", waiting_command_,
+ OpCodeText(waiting_command_).c_str(), op_code, OpCodeText(op_code).c_str());
+ auto caller_handler = command_queue_.front().caller_handler;
+ caller_handler->Post(BindOnce(std::move(command_queue_.front().on_status), std::move(status_view)));
+ command_queue_.pop_front();
+ waiting_command_ = OpCode::NONE;
+ hci_timeout_alarm_->Cancel();
+ send_next_command();
+ }
+
+ void command_complete_callback(EventPacketView event) {
+ CommandCompleteView complete_view = CommandCompleteView::Create(event);
+ ASSERT(complete_view.IsValid());
+ command_credits_ = complete_view.GetNumHciCommandPackets();
+ OpCode op_code = complete_view.GetCommandOpCode();
+ if (op_code == OpCode::NONE) {
+ send_next_command();
+ return;
+ }
+ ASSERT_LOG(command_queue_.size() > 0, "Unexpected command complete with OpCode 0x%02hx (%s)", op_code,
+ OpCodeText(op_code).c_str());
+ ASSERT_LOG(waiting_command_ == op_code, "Waiting for 0x%02hx (%s), got 0x%02hx (%s)", waiting_command_,
+ OpCodeText(waiting_command_).c_str(), op_code, OpCodeText(op_code).c_str());
+ ASSERT_LOG(!command_queue_.front().waiting_for_status_,
+ "Waiting for command status 0x%02hx (%s), got command complete for 0x%02hx (%s)", waiting_command_,
+ OpCodeText(waiting_command_).c_str(), op_code, OpCodeText(op_code).c_str());
+ auto caller_handler = command_queue_.front().caller_handler;
+ caller_handler->Post(BindOnce(std::move(command_queue_.front().on_complete), complete_view));
+ command_queue_.pop_front();
+ waiting_command_ = OpCode::NONE;
+ hci_timeout_alarm_->Cancel();
+ send_next_command();
+ }
+
+ void le_meta_event_callback(EventPacketView event) {
+ LeMetaEventView meta_event_view = LeMetaEventView::Create(event);
+ ASSERT(meta_event_view.IsValid());
+ SubeventCode subevent_code = meta_event_view.GetSubeventCode();
+ ASSERT_LOG(subevent_handlers_.find(subevent_code) != subevent_handlers_.end(),
+ "Unhandled le event of type 0x%02hhx (%s)", subevent_code, SubeventCodeText(subevent_code).c_str());
+ auto& registered_handler = subevent_handlers_[subevent_code].subevent_handler;
+ subevent_handlers_[subevent_code].handler->Post(BindOnce(registered_handler, meta_event_view));
+ }
+
+ void hciEventReceived(hal::HciPacket event_bytes) override {
+ auto packet = packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(event_bytes));
+ EventPacketView event = EventPacketView::Create(packet);
+ ASSERT(event.IsValid());
+ module_.GetHandler()->Post(
+ BindOnce(&HciLayer::impl::hci_event_received_handler, common::Unretained(this), std::move(event)));
+ }
+
+ void hci_event_received_handler(EventPacketView event) {
+ EventCode event_code = event.GetEventCode();
+ ASSERT_LOG(event_handlers_.find(event_code) != event_handlers_.end(), "Unhandled event of type 0x%02hhx (%s)",
+ event_code, EventCodeText(event_code).c_str());
+ auto& registered_handler = event_handlers_[event_code].event_handler;
+ event_handlers_[event_code].handler->Post(BindOnce(registered_handler, std::move(event)));
+ }
+
+ void aclDataReceived(hal::HciPacket data_bytes) override {
+ auto packet =
+ packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(std::move(data_bytes)));
+ AclPacketView acl = AclPacketView::Create(packet);
+ incoming_acl_packet_buffer_.Enqueue(std::make_unique<AclPacketView>(acl), module_.GetHandler());
+ }
+
+ void scoDataReceived(hal::HciPacket data_bytes) override {
+ auto packet = packet::PacketView<packet::kLittleEndian>(std::make_shared<std::vector<uint8_t>>(data_bytes));
+ ScoPacketView sco = ScoPacketView::Create(packet);
+ }
+
+ void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+ OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) {
+ module_.GetHandler()->Post(common::BindOnce(&impl::handle_enqueue_command_with_complete, common::Unretained(this),
+ std::move(command), std::move(on_complete),
+ common::Unretained(handler)));
+ }
+
+ void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command, OnceCallback<void(CommandStatusView)> on_status,
+ os::Handler* handler) {
+ module_.GetHandler()->Post(common::BindOnce(&impl::handle_enqueue_command_with_status, common::Unretained(this),
+ std::move(command), std::move(on_status), common::Unretained(handler)));
+ }
+
+ void handle_enqueue_command_with_complete(std::unique_ptr<CommandPacketBuilder> command,
+ OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) {
+ command_queue_.emplace_back(std::move(command), std::move(on_complete), handler);
+
+ send_next_command();
+ }
+
+ void handle_enqueue_command_with_status(std::unique_ptr<CommandPacketBuilder> command,
+ OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) {
+ command_queue_.emplace_back(std::move(command), std::move(on_status), handler);
+
+ send_next_command();
+ }
+
+ void send_next_command() {
+ if (command_credits_ == 0) {
+ return;
+ }
+ if (waiting_command_ != OpCode::NONE) {
+ return;
+ }
+ if (command_queue_.size() == 0) {
+ return;
+ }
+ std::shared_ptr<std::vector<uint8_t>> bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter bi(*bytes);
+ command_queue_.front().command->Serialize(bi);
+ hal_->sendHciCommand(*bytes);
+ auto cmd_view = CommandPacketView::Create(bytes);
+ ASSERT(cmd_view.IsValid());
+ OpCode op_code = cmd_view.GetOpCode();
+ waiting_command_ = op_code;
+ command_credits_ = 0; // Only allow one outstanding command
+ hci_timeout_alarm_->Schedule(BindOnce(&on_hci_timeout, op_code), kHciTimeoutMs);
+ }
+
+ BidiQueueEnd<AclPacketBuilder, AclPacketView>* GetAclQueueEnd() {
+ return acl_queue_.GetUpEnd();
+ }
+
+ void RegisterEventHandler(EventCode event_code, Callback<void(EventPacketView)> event_handler, os::Handler* handler) {
+ module_.GetHandler()->Post(common::BindOnce(&impl::handle_register_event_handler, common::Unretained(this),
+ event_code, event_handler, common::Unretained(handler)));
+ }
+
+ void handle_register_event_handler(EventCode event_code, Callback<void(EventPacketView)> event_handler,
+ os::Handler* handler) {
+ ASSERT_LOG(event_handlers_.count(event_code) == 0, "Can not register a second handler for event_code %02hhx (%s)",
+ event_code, EventCodeText(event_code).c_str());
+ EventHandler to_save(event_handler, handler);
+ event_handlers_[event_code] = to_save;
+ }
+
+ void UnregisterEventHandler(EventCode event_code) {
+ module_.GetHandler()->Post(
+ common::BindOnce(&impl::handle_unregister_event_handler, common::Unretained(this), event_code));
+ }
+
+ void handle_unregister_event_handler(EventCode event_code) {
+ event_handlers_.erase(event_code);
+ }
+
+ void RegisterLeEventHandler(SubeventCode subevent_code, Callback<void(LeMetaEventView)> event_handler,
+ os::Handler* handler) {
+ module_.GetHandler()->Post(common::BindOnce(&impl::handle_register_le_event_handler, common::Unretained(this),
+ subevent_code, event_handler, common::Unretained(handler)));
+ }
+
+ void handle_register_le_event_handler(SubeventCode subevent_code, Callback<void(LeMetaEventView)> subevent_handler,
+ os::Handler* handler) {
+ ASSERT_LOG(subevent_handlers_.count(subevent_code) == 0,
+ "Can not register a second handler for subevent_code %02hhx (%s)", subevent_code,
+ SubeventCodeText(subevent_code).c_str());
+ SubeventHandler to_save(subevent_handler, handler);
+ subevent_handlers_[subevent_code] = to_save;
+ }
+
+ void UnregisterLeEventHandler(SubeventCode subevent_code) {
+ module_.GetHandler()->Post(
+ common::BindOnce(&impl::handle_unregister_le_event_handler, common::Unretained(this), subevent_code));
+ }
+
+ void handle_unregister_le_event_handler(SubeventCode subevent_code) {
+ subevent_handlers_.erase(subevent_code);
+ }
+
+ // The HAL
+ hal::HciHal* hal_;
+
+ // A reference to the HciLayer module
+ HciLayer& module_;
+
+ // Interfaces
+ SecurityInterfaceImpl security_interface{module_};
+ LeSecurityInterfaceImpl le_security_interface{module_};
+ LeAdvertisingInterfaceImpl le_advertising_interface{module_};
+ LeScanningInterfaceImpl le_scanning_interface{module_};
+
+ // Command Handling
+ std::list<CommandQueueEntry> command_queue_;
+
+ std::map<EventCode, EventHandler> event_handlers_;
+ std::map<SubeventCode, SubeventHandler> subevent_handlers_;
+ OpCode waiting_command_{OpCode::NONE};
+ uint8_t command_credits_{1}; // Send reset first
+ Alarm* hci_timeout_alarm_{nullptr};
+
+ // Acl packets
+ BidiQueue<AclPacketView, AclPacketBuilder> acl_queue_{3 /* TODO: Set queue depth */};
+ os::EnqueueBuffer<AclPacketView> incoming_acl_packet_buffer_{acl_queue_.GetDownEnd()};
+};
+
+HciLayer::HciLayer() : impl_(std::make_unique<impl>(*this)) {}
+
+HciLayer::~HciLayer() {
+ impl_.reset();
+}
+
+void HciLayer::EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+ common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) {
+ impl_->EnqueueCommand(std::move(command), std::move(on_complete), handler);
+}
+
+void HciLayer::EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+ common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) {
+ impl_->EnqueueCommand(std::move(command), std::move(on_status), handler);
+}
+
+common::BidiQueueEnd<AclPacketBuilder, AclPacketView>* HciLayer::GetAclQueueEnd() {
+ return impl_->GetAclQueueEnd();
+}
+
+void HciLayer::RegisterEventHandler(EventCode event_code, common::Callback<void(EventPacketView)> event_handler,
+ os::Handler* handler) {
+ impl_->RegisterEventHandler(event_code, std::move(event_handler), handler);
+}
+
+void HciLayer::UnregisterEventHandler(EventCode event_code) {
+ impl_->UnregisterEventHandler(event_code);
+}
+
+void HciLayer::RegisterLeEventHandler(SubeventCode subevent_code, common::Callback<void(LeMetaEventView)> event_handler,
+ os::Handler* handler) {
+ impl_->RegisterLeEventHandler(subevent_code, std::move(event_handler), handler);
+}
+
+void HciLayer::UnregisterLeEventHandler(SubeventCode subevent_code) {
+ impl_->UnregisterLeEventHandler(subevent_code);
+}
+
+SecurityInterface* HciLayer::GetSecurityInterface(common::Callback<void(EventPacketView)> event_handler,
+ os::Handler* handler) {
+ for (const auto event : SecurityInterface::SecurityEvents) {
+ RegisterEventHandler(event, event_handler, handler);
+ }
+ return &impl_->security_interface;
+}
+
+LeSecurityInterface* HciLayer::GetLeSecurityInterface(common::Callback<void(LeMetaEventView)> event_handler,
+ os::Handler* handler) {
+ for (const auto subevent : LeSecurityInterface::LeSecurityEvents) {
+ RegisterLeEventHandler(subevent, event_handler, handler);
+ }
+ return &impl_->le_security_interface;
+}
+
+LeAdvertisingInterface* HciLayer::GetLeAdvertisingInterface(common::Callback<void(LeMetaEventView)> event_handler,
+ os::Handler* handler) {
+ for (const auto subevent : LeAdvertisingInterface::LeAdvertisingEvents) {
+ RegisterLeEventHandler(subevent, event_handler, handler);
+ }
+ return &impl_->le_advertising_interface;
+}
+
+LeScanningInterface* HciLayer::GetLeScanningInterface(common::Callback<void(LeMetaEventView)> event_handler,
+ os::Handler* handler) {
+ for (const auto subevent : LeScanningInterface::LeScanningEvents) {
+ RegisterLeEventHandler(subevent, event_handler, handler);
+ }
+ return &impl_->le_scanning_interface;
+}
+
+const ModuleFactory HciLayer::Factory = ModuleFactory([]() { return new HciLayer(); });
+
+void HciLayer::ListDependencies(ModuleList* list) {
+ list->add<hal::HciHal>();
+}
+
+void HciLayer::Start() {
+ impl_->Start(GetDependency<hal::HciHal>());
+}
+
+void HciLayer::Stop() {
+ impl_->Stop();
+}
+
+std::string HciLayer::ToString() const {
+ return "Hci Layer";
+}
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/hci_layer.h b/gd/hci/hci_layer.h
new file mode 100644
index 0000000..3e299d4
--- /dev/null
+++ b/gd/hci/hci_layer.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <chrono>
+#include <map>
+
+#include "address.h"
+#include "class_of_device.h"
+#include "common/bidi_queue.h"
+#include "common/callback.h"
+#include "hal/hci_hal.h"
+#include "hci/hci_packets.h"
+#include "hci/le_advertising_interface.h"
+#include "hci/le_scanning_interface.h"
+#include "hci/le_security_interface.h"
+#include "hci/security_interface.h"
+#include "module.h"
+#include "os/utils.h"
+
+namespace bluetooth {
+namespace hci {
+
+class HciLayer : public Module {
+ public:
+ HciLayer();
+ virtual ~HciLayer();
+ DISALLOW_COPY_AND_ASSIGN(HciLayer);
+
+ virtual void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+ common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler);
+
+ virtual void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+ common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler);
+
+ virtual common::BidiQueueEnd<AclPacketBuilder, AclPacketView>* GetAclQueueEnd();
+
+ virtual void RegisterEventHandler(EventCode event_code, common::Callback<void(EventPacketView)> event_handler,
+ os::Handler* handler);
+
+ virtual void UnregisterEventHandler(EventCode event_code);
+
+ virtual void RegisterLeEventHandler(SubeventCode subevent_code, common::Callback<void(LeMetaEventView)> event_handler,
+ os::Handler* handler);
+
+ virtual void UnregisterLeEventHandler(SubeventCode subevent_code);
+
+ SecurityInterface* GetSecurityInterface(common::Callback<void(EventPacketView)> event_handler, os::Handler* handler);
+
+ LeSecurityInterface* GetLeSecurityInterface(common::Callback<void(LeMetaEventView)> event_handler,
+ os::Handler* handler);
+
+ LeAdvertisingInterface* GetLeAdvertisingInterface(common::Callback<void(LeMetaEventView)> event_handler,
+ os::Handler* handler);
+
+ LeScanningInterface* GetLeScanningInterface(common::Callback<void(LeMetaEventView)> event_handler,
+ os::Handler* handler);
+
+ static const ModuleFactory Factory;
+
+ void ListDependencies(ModuleList* list) override;
+
+ void Start() override;
+
+ void Stop() override;
+
+ std::string ToString() const override;
+ static constexpr std::chrono::milliseconds kHciTimeoutMs = std::chrono::milliseconds(2000);
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> impl_;
+};
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/hci_layer_test.cc b/gd/hci/hci_layer_test.cc
new file mode 100644
index 0000000..d796488
--- /dev/null
+++ b/gd/hci/hci_layer_test.cc
@@ -0,0 +1,729 @@
+/*
+ * Copyright 2019 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 "hci/hci_layer.h"
+
+#include <gtest/gtest.h>
+#include <list>
+#include <memory>
+
+#include "hal/hci_hal.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "os/log.h"
+#include "os/thread.h"
+#include "packet/bit_inserter.h"
+#include "packet/raw_builder.h"
+
+using bluetooth::os::Thread;
+using bluetooth::packet::BitInserter;
+using bluetooth::packet::RawBuilder;
+using std::vector;
+
+namespace {
+vector<uint8_t> information_request = {
+ 0xfe, 0x2e, 0x0a, 0x00, 0x06, 0x00, 0x01, 0x00, 0x0a, 0x02, 0x02, 0x00, 0x02, 0x00,
+};
+// 0x00, 0x01, 0x02, 0x03, ...
+vector<uint8_t> counting_bytes;
+// 0xFF, 0xFE, 0xFD, 0xFC, ...
+vector<uint8_t> counting_down_bytes;
+const size_t count_size = 0x8;
+
+} // namespace
+
+namespace bluetooth {
+namespace hci {
+
+constexpr std::chrono::milliseconds kTimeout = HciLayer::kHciTimeoutMs / 2;
+constexpr std::chrono::milliseconds kAclTimeout = std::chrono::milliseconds(1000);
+
+class TestHciHal : public hal::HciHal {
+ public:
+ TestHciHal() : hal::HciHal() {}
+
+ ~TestHciHal() {
+ ASSERT_LOG(callbacks == nullptr, "unregisterIncomingPacketCallback() must be called");
+ }
+
+ void registerIncomingPacketCallback(hal::HciHalCallbacks* callback) override {
+ callbacks = callback;
+ }
+
+ void unregisterIncomingPacketCallback() override {
+ callbacks = nullptr;
+ }
+
+ void sendHciCommand(hal::HciPacket command) override {
+ outgoing_commands_.push_back(std::move(command));
+ if (sent_command_promise_ != nullptr) {
+ auto promise = std::move(sent_command_promise_);
+ sent_command_promise_.reset();
+ promise->set_value();
+ }
+ }
+
+ void sendAclData(hal::HciPacket data) override {
+ outgoing_acl_.push_front(std::move(data));
+ if (sent_acl_promise_ != nullptr) {
+ auto promise = std::move(sent_acl_promise_);
+ sent_acl_promise_.reset();
+ promise->set_value();
+ }
+ }
+
+ void sendScoData(hal::HciPacket data) override {
+ outgoing_sco_.push_front(std::move(data));
+ }
+
+ hal::HciHalCallbacks* callbacks = nullptr;
+
+ PacketView<kLittleEndian> GetPacketView(hal::HciPacket data) {
+ auto shared = std::make_shared<std::vector<uint8_t>>(data);
+ return PacketView<kLittleEndian>(shared);
+ }
+
+ size_t GetNumSentCommands() {
+ return outgoing_commands_.size();
+ }
+
+ std::future<void> GetSentCommandFuture() {
+ ASSERT_LOG(sent_command_promise_ == nullptr, "Promises promises ... Only one at a time");
+ sent_command_promise_ = std::make_unique<std::promise<void>>();
+ return sent_command_promise_->get_future();
+ }
+
+ CommandPacketView GetSentCommand() {
+ auto packetview = GetPacketView(std::move(outgoing_commands_.front()));
+ outgoing_commands_.pop_front();
+ return CommandPacketView::Create(packetview);
+ }
+
+ std::future<void> GetSentAclFuture() {
+ ASSERT_LOG(sent_acl_promise_ == nullptr, "Promises promises ... Only one at a time");
+ sent_acl_promise_ = std::make_unique<std::promise<void>>();
+ return sent_acl_promise_->get_future();
+ }
+
+ PacketView<kLittleEndian> GetSentAcl() {
+ auto packetview = GetPacketView(std::move(outgoing_acl_.front()));
+ outgoing_acl_.pop_front();
+ return packetview;
+ }
+
+ void Start() {}
+
+ void Stop() {}
+
+ void ListDependencies(ModuleList*) {}
+
+ static const ModuleFactory Factory;
+
+ private:
+ std::list<hal::HciPacket> outgoing_commands_;
+ std::list<hal::HciPacket> outgoing_acl_;
+ std::list<hal::HciPacket> outgoing_sco_;
+ std::unique_ptr<std::promise<void>> sent_command_promise_;
+ std::unique_ptr<std::promise<void>> sent_acl_promise_;
+};
+
+const ModuleFactory TestHciHal::Factory = ModuleFactory([]() { return new TestHciHal(); });
+
+class DependsOnHci : public Module {
+ public:
+ DependsOnHci() : Module() {}
+
+ void SendHciCommandExpectingStatus(std::unique_ptr<CommandPacketBuilder> command) {
+ hci_->EnqueueCommand(std::move(command),
+ common::Bind(&DependsOnHci::handle_event<CommandStatusView>, common::Unretained(this)),
+ GetHandler());
+ }
+
+ void SendHciCommandExpectingComplete(std::unique_ptr<CommandPacketBuilder> command) {
+ hci_->EnqueueCommand(std::move(command),
+ common::Bind(&DependsOnHci::handle_event<CommandCompleteView>, common::Unretained(this)),
+ GetHandler());
+ }
+
+ void SendSecurityCommandExpectingComplete(std::unique_ptr<SecurityCommandBuilder> command) {
+ if (security_interface_ == nullptr) {
+ security_interface_ = hci_->GetSecurityInterface(
+ common::Bind(&DependsOnHci::handle_event<EventPacketView>, common::Unretained(this)), GetHandler());
+ }
+ hci_->EnqueueCommand(std::move(command),
+ common::Bind(&DependsOnHci::handle_event<CommandCompleteView>, common::Unretained(this)),
+ GetHandler());
+ }
+
+ void SendLeSecurityCommandExpectingComplete(std::unique_ptr<LeSecurityCommandBuilder> command) {
+ if (le_security_interface_ == nullptr) {
+ le_security_interface_ = hci_->GetLeSecurityInterface(
+ common::Bind(&DependsOnHci::handle_event<LeMetaEventView>, common::Unretained(this)), GetHandler());
+ }
+ hci_->EnqueueCommand(std::move(command),
+ common::Bind(&DependsOnHci::handle_event<CommandCompleteView>, common::Unretained(this)),
+ GetHandler());
+ }
+
+ void SendAclData(std::unique_ptr<AclPacketBuilder> acl) {
+ outgoing_acl_.push(std::move(acl));
+ auto queue_end = hci_->GetAclQueueEnd();
+ queue_end->RegisterEnqueue(GetHandler(), common::Bind(&DependsOnHci::handle_enqueue, common::Unretained(this)));
+ }
+
+ std::future<void> GetReceivedEventFuture() {
+ ASSERT_LOG(event_promise_ == nullptr, "Promises promises ... Only one at a time");
+ event_promise_ = std::make_unique<std::promise<void>>();
+ return event_promise_->get_future();
+ }
+
+ EventPacketView GetReceivedEvent() {
+ EventPacketView packetview = incoming_events_.front();
+ incoming_events_.pop_front();
+ return packetview;
+ }
+
+ std::future<void> GetReceivedAclFuture() {
+ ASSERT_LOG(acl_promise_ == nullptr, "Promises promises ... Only one at a time");
+ acl_promise_ = std::make_unique<std::promise<void>>();
+ return acl_promise_->get_future();
+ }
+
+ size_t GetNumReceivedAclPackets() {
+ return incoming_acl_packets_.size();
+ }
+
+ AclPacketView GetReceivedAcl() {
+ AclPacketView packetview = incoming_acl_packets_.front();
+ incoming_acl_packets_.pop_front();
+ return packetview;
+ }
+
+ void Start() {
+ hci_ = GetDependency<HciLayer>();
+ hci_->RegisterEventHandler(EventCode::CONNECTION_COMPLETE,
+ common::Bind(&DependsOnHci::handle_event<EventPacketView>, common::Unretained(this)),
+ GetHandler());
+ hci_->RegisterLeEventHandler(SubeventCode::CONNECTION_COMPLETE,
+ common::Bind(&DependsOnHci::handle_event<LeMetaEventView>, common::Unretained(this)),
+ GetHandler());
+ hci_->GetAclQueueEnd()->RegisterDequeue(GetHandler(),
+ common::Bind(&DependsOnHci::handle_acl, common::Unretained(this)));
+ }
+
+ void Stop() {
+ hci_->GetAclQueueEnd()->UnregisterDequeue();
+ }
+
+ void ListDependencies(ModuleList* list) {
+ list->add<HciLayer>();
+ }
+
+ static const ModuleFactory Factory;
+
+ private:
+ HciLayer* hci_ = nullptr;
+ const SecurityInterface* security_interface_;
+ const LeSecurityInterface* le_security_interface_;
+ std::list<EventPacketView> incoming_events_;
+ std::list<AclPacketView> incoming_acl_packets_;
+ std::unique_ptr<std::promise<void>> event_promise_;
+ std::unique_ptr<std::promise<void>> acl_promise_;
+
+ void handle_acl() {
+ auto acl_ptr = hci_->GetAclQueueEnd()->TryDequeue();
+ incoming_acl_packets_.push_back(*acl_ptr);
+ if (acl_promise_ != nullptr) {
+ auto promise = std::move(acl_promise_);
+ acl_promise_.reset();
+ promise->set_value();
+ }
+ }
+
+ template <typename T>
+ void handle_event(T event) {
+ incoming_events_.push_back(event);
+ if (event_promise_ != nullptr) {
+ auto promise = std::move(event_promise_);
+ event_promise_.reset();
+ promise->set_value();
+ }
+ }
+
+ std::queue<std::unique_ptr<AclPacketBuilder>> outgoing_acl_;
+
+ std::unique_ptr<AclPacketBuilder> handle_enqueue() {
+ hci_->GetAclQueueEnd()->UnregisterEnqueue();
+ auto acl = std::move(outgoing_acl_.front());
+ outgoing_acl_.pop();
+ return acl;
+ }
+};
+
+const ModuleFactory DependsOnHci::Factory = ModuleFactory([]() { return new DependsOnHci(); });
+
+class HciTest : public ::testing::Test {
+ public:
+ void SetUp() override {
+ counting_bytes.reserve(count_size);
+ counting_down_bytes.reserve(count_size);
+ for (size_t i = 0; i < count_size; i++) {
+ counting_bytes.push_back(i);
+ counting_down_bytes.push_back(~i);
+ }
+ hal = new TestHciHal();
+
+ auto command_future = hal->GetSentCommandFuture();
+
+ fake_registry_.InjectTestModule(&hal::HciHal::Factory, hal);
+ fake_registry_.Start<DependsOnHci>(&fake_registry_.GetTestThread());
+ hci = static_cast<HciLayer*>(fake_registry_.GetModuleUnderTest(&HciLayer::Factory));
+ upper = static_cast<DependsOnHci*>(fake_registry_.GetModuleUnderTest(&DependsOnHci::Factory));
+ ASSERT(fake_registry_.IsStarted<HciLayer>());
+
+ auto reset_sent_status = command_future.wait_for(kTimeout);
+ ASSERT_EQ(reset_sent_status, std::future_status::ready);
+
+ // Verify that reset was received
+ ASSERT_EQ(1, hal->GetNumSentCommands());
+
+ auto sent_command = hal->GetSentCommand();
+ auto reset_view = ResetView::Create(CommandPacketView::Create(sent_command));
+ ASSERT_TRUE(reset_view.IsValid());
+
+ // Verify that only one was sent
+ ASSERT_EQ(0, hal->GetNumSentCommands());
+
+ // Send the response event
+ uint8_t num_packets = 1;
+ ErrorCode error_code = ErrorCode::SUCCESS;
+ hal->callbacks->hciEventReceived(GetPacketBytes(ResetCompleteBuilder::Create(num_packets, error_code)));
+ }
+
+ void TearDown() override {
+ fake_registry_.StopAll();
+ }
+
+ std::vector<uint8_t> GetPacketBytes(std::unique_ptr<packet::BasePacketBuilder> packet) {
+ std::vector<uint8_t> bytes;
+ BitInserter i(bytes);
+ bytes.reserve(packet->size());
+ packet->Serialize(i);
+ return bytes;
+ }
+
+ DependsOnHci* upper = nullptr;
+ TestHciHal* hal = nullptr;
+ HciLayer* hci = nullptr;
+ TestModuleRegistry fake_registry_;
+};
+
+TEST_F(HciTest, initAndClose) {}
+
+TEST_F(HciTest, leMetaEvent) {
+ auto event_future = upper->GetReceivedEventFuture();
+
+ // Send an LE event
+ ErrorCode status = ErrorCode::SUCCESS;
+ uint16_t handle = 0x123;
+ Role role = Role::MASTER;
+ AddressType peer_address_type = AddressType::PUBLIC_DEVICE_ADDRESS;
+ Address peer_address = Address::kAny;
+ uint16_t conn_interval = 0x0ABC;
+ uint16_t conn_latency = 0x0123;
+ uint16_t supervision_timeout = 0x0B05;
+ MasterClockAccuracy master_clock_accuracy = MasterClockAccuracy::PPM_50;
+ hal->callbacks->hciEventReceived(GetPacketBytes(
+ LeConnectionCompleteBuilder::Create(status, handle, role, peer_address_type, peer_address, conn_interval,
+ conn_latency, supervision_timeout, master_clock_accuracy)));
+
+ // Wait for the event
+ auto event_status = event_future.wait_for(kTimeout);
+ ASSERT_EQ(event_status, std::future_status::ready);
+
+ auto event = upper->GetReceivedEvent();
+ ASSERT(LeConnectionCompleteView::Create(LeMetaEventView::Create(EventPacketView::Create(event))).IsValid());
+}
+
+TEST_F(HciTest, noOpCredits) {
+ ASSERT_EQ(0, hal->GetNumSentCommands());
+
+ // Send 0 credits
+ uint8_t num_packets = 0;
+ hal->callbacks->hciEventReceived(GetPacketBytes(NoCommandCompleteBuilder::Create(num_packets)));
+
+ auto command_future = hal->GetSentCommandFuture();
+ upper->SendHciCommandExpectingComplete(ReadLocalVersionInformationBuilder::Create());
+
+ // Verify that nothing was sent
+ ASSERT_EQ(0, hal->GetNumSentCommands());
+
+ num_packets = 1;
+ hal->callbacks->hciEventReceived(GetPacketBytes(NoCommandCompleteBuilder::Create(num_packets)));
+
+ auto command_sent_status = command_future.wait_for(kTimeout);
+ ASSERT_EQ(command_sent_status, std::future_status::ready);
+
+ // Verify that one was sent
+ ASSERT_EQ(1, hal->GetNumSentCommands());
+
+ auto event_future = upper->GetReceivedEventFuture();
+
+ // Send the response event
+ ErrorCode error_code = ErrorCode::SUCCESS;
+ LocalVersionInformation local_version_information;
+ local_version_information.hci_version_ = HciVersion::V_5_0;
+ local_version_information.hci_revision_ = 0x1234;
+ local_version_information.lmp_version_ = LmpVersion::V_4_2;
+ local_version_information.manufacturer_name_ = 0xBAD;
+ local_version_information.lmp_subversion_ = 0x5678;
+ hal->callbacks->hciEventReceived(GetPacketBytes(
+ ReadLocalVersionInformationCompleteBuilder::Create(num_packets, error_code, local_version_information)));
+
+ // Wait for the event
+ auto event_status = event_future.wait_for(kTimeout);
+ ASSERT_EQ(event_status, std::future_status::ready);
+
+ auto event = upper->GetReceivedEvent();
+ ASSERT(ReadLocalVersionInformationCompleteView::Create(CommandCompleteView::Create(EventPacketView::Create(event)))
+ .IsValid());
+}
+
+TEST_F(HciTest, creditsTest) {
+ ASSERT_EQ(0, hal->GetNumSentCommands());
+
+ auto command_future = hal->GetSentCommandFuture();
+
+ // Send all three commands
+ upper->SendHciCommandExpectingComplete(ReadLocalVersionInformationBuilder::Create());
+ upper->SendHciCommandExpectingComplete(ReadLocalSupportedCommandsBuilder::Create());
+ upper->SendHciCommandExpectingComplete(ReadLocalSupportedFeaturesBuilder::Create());
+
+ auto command_sent_status = command_future.wait_for(kTimeout);
+ ASSERT_EQ(command_sent_status, std::future_status::ready);
+
+ // Verify that the first one is sent
+ ASSERT_EQ(1, hal->GetNumSentCommands());
+
+ auto sent_command = hal->GetSentCommand();
+ auto version_view = ReadLocalVersionInformationView::Create(CommandPacketView::Create(sent_command));
+ ASSERT_TRUE(version_view.IsValid());
+
+ // Verify that only one was sent
+ ASSERT_EQ(0, hal->GetNumSentCommands());
+
+ // Get a new future
+ auto event_future = upper->GetReceivedEventFuture();
+
+ // Send the response event
+ uint8_t num_packets = 1;
+ ErrorCode error_code = ErrorCode::SUCCESS;
+ LocalVersionInformation local_version_information;
+ local_version_information.hci_version_ = HciVersion::V_5_0;
+ local_version_information.hci_revision_ = 0x1234;
+ local_version_information.lmp_version_ = LmpVersion::V_4_2;
+ local_version_information.manufacturer_name_ = 0xBAD;
+ local_version_information.lmp_subversion_ = 0x5678;
+ hal->callbacks->hciEventReceived(GetPacketBytes(
+ ReadLocalVersionInformationCompleteBuilder::Create(num_packets, error_code, local_version_information)));
+
+ // Wait for the event
+ auto event_status = event_future.wait_for(kTimeout);
+ ASSERT_EQ(event_status, std::future_status::ready);
+
+ auto event = upper->GetReceivedEvent();
+ ASSERT(ReadLocalVersionInformationCompleteView::Create(CommandCompleteView::Create(EventPacketView::Create(event)))
+ .IsValid());
+
+ // Verify that the second one is sent
+ command_sent_status = command_future.wait_for(kTimeout);
+ ASSERT_EQ(command_sent_status, std::future_status::ready);
+ ASSERT_EQ(1, hal->GetNumSentCommands());
+
+ sent_command = hal->GetSentCommand();
+ auto supported_commands_view = ReadLocalSupportedCommandsView::Create(CommandPacketView::Create(sent_command));
+ ASSERT_TRUE(supported_commands_view.IsValid());
+
+ // Verify that only one was sent
+ ASSERT_EQ(0, hal->GetNumSentCommands());
+ event_future = upper->GetReceivedEventFuture();
+ command_future = hal->GetSentCommandFuture();
+
+ // Send the response event
+ std::array<uint8_t, 64> supported_commands;
+ for (uint8_t i = 0; i < 64; i++) {
+ supported_commands[i] = i;
+ }
+ hal->callbacks->hciEventReceived(
+ GetPacketBytes(ReadLocalSupportedCommandsCompleteBuilder::Create(num_packets, error_code, supported_commands)));
+ // Wait for the event
+ event_status = event_future.wait_for(kTimeout);
+ ASSERT_EQ(event_status, std::future_status::ready);
+
+ event = upper->GetReceivedEvent();
+ ASSERT(ReadLocalSupportedCommandsCompleteView::Create(CommandCompleteView::Create(EventPacketView::Create(event)))
+ .IsValid());
+ // Verify that the third one is sent
+ command_sent_status = command_future.wait_for(kTimeout);
+ ASSERT_EQ(command_sent_status, std::future_status::ready);
+ ASSERT_EQ(1, hal->GetNumSentCommands());
+
+ sent_command = hal->GetSentCommand();
+ auto supported_features_view = ReadLocalSupportedFeaturesView::Create(CommandPacketView::Create(sent_command));
+ ASSERT_TRUE(supported_features_view.IsValid());
+
+ // Verify that only one was sent
+ ASSERT_EQ(0, hal->GetNumSentCommands());
+ event_future = upper->GetReceivedEventFuture();
+
+ // Send the response event
+ uint64_t lmp_features = 0x012345678abcdef;
+ hal->callbacks->hciEventReceived(
+ GetPacketBytes(ReadLocalSupportedFeaturesCompleteBuilder::Create(num_packets, error_code, lmp_features)));
+
+ // Wait for the event
+ event_status = event_future.wait_for(kTimeout);
+ ASSERT_EQ(event_status, std::future_status::ready);
+ event = upper->GetReceivedEvent();
+ ASSERT(ReadLocalSupportedFeaturesCompleteView::Create(CommandCompleteView::Create(EventPacketView::Create(event)))
+ .IsValid());
+}
+
+TEST_F(HciTest, leSecurityInterfaceTest) {
+ // Send LeRand to the controller
+ auto command_future = hal->GetSentCommandFuture();
+ upper->SendLeSecurityCommandExpectingComplete(LeRandBuilder::Create());
+
+ auto command_sent_status = command_future.wait_for(kTimeout);
+ ASSERT_EQ(command_sent_status, std::future_status::ready);
+
+ // Check the command
+ auto sent_command = hal->GetSentCommand();
+ ASSERT_LT(0, sent_command.size());
+ LeRandView view = LeRandView::Create(LeSecurityCommandView::Create(CommandPacketView::Create(sent_command)));
+ ASSERT_TRUE(view.IsValid());
+
+ // Send a Command Complete to the host
+ auto event_future = upper->GetReceivedEventFuture();
+ uint8_t num_packets = 1;
+ ErrorCode status = ErrorCode::SUCCESS;
+ uint64_t rand = 0x0123456789abcdef;
+ hal->callbacks->hciEventReceived(GetPacketBytes(LeRandCompleteBuilder::Create(num_packets, status, rand)));
+
+ // Verify the event
+ auto event_status = event_future.wait_for(kTimeout);
+ ASSERT_EQ(event_status, std::future_status::ready);
+ auto event = upper->GetReceivedEvent();
+ ASSERT_TRUE(event.IsValid());
+ ASSERT_EQ(EventCode::COMMAND_COMPLETE, event.GetEventCode());
+ ASSERT_TRUE(LeRandCompleteView::Create(CommandCompleteView::Create(event)).IsValid());
+}
+
+TEST_F(HciTest, securityInterfacesTest) {
+ // Send WriteSimplePairingMode to the controller
+ auto command_future = hal->GetSentCommandFuture();
+ Enable enable = Enable::ENABLED;
+ upper->SendSecurityCommandExpectingComplete(WriteSimplePairingModeBuilder::Create(enable));
+
+ auto command_sent_status = command_future.wait_for(kTimeout);
+ ASSERT_EQ(command_sent_status, std::future_status::ready);
+
+ // Check the command
+ auto sent_command = hal->GetSentCommand();
+ ASSERT_LT(0, sent_command.size());
+ auto view = WriteSimplePairingModeView::Create(SecurityCommandView::Create(CommandPacketView::Create(sent_command)));
+ ASSERT_TRUE(view.IsValid());
+
+ // Send a Command Complete to the host
+ auto event_future = upper->GetReceivedEventFuture();
+ uint8_t num_packets = 1;
+ ErrorCode status = ErrorCode::SUCCESS;
+ hal->callbacks->hciEventReceived(GetPacketBytes(WriteSimplePairingModeCompleteBuilder::Create(num_packets, status)));
+
+ // Verify the event
+ auto event_status = event_future.wait_for(kTimeout);
+ ASSERT_EQ(event_status, std::future_status::ready);
+ auto event = upper->GetReceivedEvent();
+ ASSERT_TRUE(event.IsValid());
+ ASSERT_EQ(EventCode::COMMAND_COMPLETE, event.GetEventCode());
+ ASSERT_TRUE(WriteSimplePairingModeCompleteView::Create(CommandCompleteView::Create(event)).IsValid());
+}
+
+TEST_F(HciTest, createConnectionTest) {
+ // Send CreateConnection to the controller
+ auto command_future = hal->GetSentCommandFuture();
+ Address bd_addr;
+ ASSERT_TRUE(Address::FromString("A1:A2:A3:A4:A5:A6", bd_addr));
+ uint16_t packet_type = 0x1234;
+ PageScanRepetitionMode page_scan_repetition_mode = PageScanRepetitionMode::R0;
+ uint16_t clock_offset = 0x3456;
+ ClockOffsetValid clock_offset_valid = ClockOffsetValid::VALID;
+ CreateConnectionRoleSwitch allow_role_switch = CreateConnectionRoleSwitch::ALLOW_ROLE_SWITCH;
+ upper->SendHciCommandExpectingStatus(CreateConnectionBuilder::Create(
+ bd_addr, packet_type, page_scan_repetition_mode, clock_offset, clock_offset_valid, allow_role_switch));
+
+ auto command_sent_status = command_future.wait_for(kTimeout);
+ ASSERT_EQ(command_sent_status, std::future_status::ready);
+
+ // Check the command
+ auto sent_command = hal->GetSentCommand();
+ ASSERT_LT(0, sent_command.size());
+ CreateConnectionView view =
+ CreateConnectionView::Create(ConnectionManagementCommandView::Create(CommandPacketView::Create(sent_command)));
+ ASSERT_TRUE(view.IsValid());
+ ASSERT_EQ(bd_addr, view.GetBdAddr());
+ ASSERT_EQ(packet_type, view.GetPacketType());
+ ASSERT_EQ(page_scan_repetition_mode, view.GetPageScanRepetitionMode());
+ ASSERT_EQ(clock_offset, view.GetClockOffset());
+ ASSERT_EQ(clock_offset_valid, view.GetClockOffsetValid());
+ ASSERT_EQ(allow_role_switch, view.GetAllowRoleSwitch());
+
+ // Send a Command Status to the host
+ auto event_future = upper->GetReceivedEventFuture();
+ ErrorCode status = ErrorCode::SUCCESS;
+ uint16_t handle = 0x123;
+ LinkType link_type = LinkType::ACL;
+ Enable encryption_enabled = Enable::DISABLED;
+ hal->callbacks->hciEventReceived(GetPacketBytes(CreateConnectionStatusBuilder::Create(ErrorCode::SUCCESS, 1)));
+
+ // Verify the event
+ auto event_status = event_future.wait_for(kTimeout);
+ ASSERT_EQ(event_status, std::future_status::ready);
+ auto event = upper->GetReceivedEvent();
+ ASSERT_TRUE(event.IsValid());
+ ASSERT_EQ(EventCode::COMMAND_STATUS, event.GetEventCode());
+
+ // Send a ConnectionComplete to the host
+ event_future = upper->GetReceivedEventFuture();
+ hal->callbacks->hciEventReceived(
+ GetPacketBytes(ConnectionCompleteBuilder::Create(status, handle, bd_addr, link_type, encryption_enabled)));
+
+ // Verify the event
+ event_status = event_future.wait_for(kTimeout);
+ ASSERT_EQ(event_status, std::future_status::ready);
+ event = upper->GetReceivedEvent();
+ ASSERT_TRUE(event.IsValid());
+ ASSERT_EQ(EventCode::CONNECTION_COMPLETE, event.GetEventCode());
+ ConnectionCompleteView connection_complete_view = ConnectionCompleteView::Create(event);
+ ASSERT_TRUE(connection_complete_view.IsValid());
+ ASSERT_EQ(status, connection_complete_view.GetStatus());
+ ASSERT_EQ(handle, connection_complete_view.GetConnectionHandle());
+ ASSERT_EQ(link_type, connection_complete_view.GetLinkType());
+ ASSERT_EQ(encryption_enabled, connection_complete_view.GetEncryptionEnabled());
+
+ // Send an ACL packet from the remote
+ PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
+ BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
+ auto acl_payload = std::make_unique<RawBuilder>();
+ acl_payload->AddAddress(bd_addr);
+ acl_payload->AddOctets2(handle);
+ auto incoming_acl_future = upper->GetReceivedAclFuture();
+ hal->callbacks->aclDataReceived(
+ GetPacketBytes(AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(acl_payload))));
+
+ // Verify the ACL packet
+ auto incoming_acl_status = incoming_acl_future.wait_for(kAclTimeout);
+ ASSERT_EQ(incoming_acl_status, std::future_status::ready);
+ auto acl_view = upper->GetReceivedAcl();
+ ASSERT_TRUE(acl_view.IsValid());
+ ASSERT_EQ(sizeof(bd_addr) + sizeof(handle), acl_view.GetPayload().size());
+ auto itr = acl_view.GetPayload().begin();
+ ASSERT_EQ(bd_addr, itr.extract<Address>());
+ ASSERT_EQ(handle, itr.extract<uint16_t>());
+
+ // Send an ACL packet from DependsOnHci
+ PacketBoundaryFlag packet_boundary_flag2 = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
+ BroadcastFlag broadcast_flag2 = BroadcastFlag::POINT_TO_POINT;
+ auto acl_payload2 = std::make_unique<RawBuilder>();
+ acl_payload2->AddOctets2(handle);
+ acl_payload2->AddAddress(bd_addr);
+ auto sent_acl_future = hal->GetSentAclFuture();
+ upper->SendAclData(AclPacketBuilder::Create(handle, packet_boundary_flag2, broadcast_flag2, std::move(acl_payload2)));
+
+ // Verify the ACL packet
+ auto sent_acl_status = sent_acl_future.wait_for(kAclTimeout);
+ ASSERT_EQ(sent_acl_status, std::future_status::ready);
+ auto sent_acl = hal->GetSentAcl();
+ ASSERT_LT(0, sent_acl.size());
+ AclPacketView sent_acl_view = AclPacketView::Create(sent_acl);
+ ASSERT_TRUE(sent_acl_view.IsValid());
+ ASSERT_EQ(sizeof(bd_addr) + sizeof(handle), sent_acl_view.GetPayload().size());
+ auto sent_itr = sent_acl_view.GetPayload().begin();
+ ASSERT_EQ(handle, sent_itr.extract<uint16_t>());
+ ASSERT_EQ(bd_addr, sent_itr.extract<Address>());
+}
+
+TEST_F(HciTest, receiveMultipleAclPackets) {
+ Address bd_addr;
+ ASSERT_TRUE(Address::FromString("A1:A2:A3:A4:A5:A6", bd_addr));
+ uint16_t handle = 0x0001;
+ uint16_t num_packets = 100;
+ PacketBoundaryFlag packet_boundary_flag = PacketBoundaryFlag::FIRST_AUTOMATICALLY_FLUSHABLE;
+ BroadcastFlag broadcast_flag = BroadcastFlag::POINT_TO_POINT;
+ for (uint16_t i = 0; i < num_packets; i++) {
+ auto acl_payload = std::make_unique<RawBuilder>();
+ acl_payload->AddAddress(bd_addr);
+ acl_payload->AddOctets2(handle);
+ acl_payload->AddOctets2(i);
+ hal->callbacks->aclDataReceived(
+ GetPacketBytes(AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(acl_payload))));
+ }
+ auto incoming_acl_future = upper->GetReceivedAclFuture();
+ uint16_t received_packets = 0;
+ while (received_packets < num_packets - 1) {
+ auto incoming_acl_status = incoming_acl_future.wait_for(kAclTimeout);
+ // Get the next future.
+ incoming_acl_future = upper->GetReceivedAclFuture();
+ ASSERT_EQ(incoming_acl_status, std::future_status::ready);
+ size_t num_packets = upper->GetNumReceivedAclPackets();
+ for (size_t i = 0; i < num_packets; i++) {
+ auto acl_view = upper->GetReceivedAcl();
+ ASSERT_TRUE(acl_view.IsValid());
+ ASSERT_EQ(sizeof(bd_addr) + sizeof(handle) + sizeof(received_packets), acl_view.GetPayload().size());
+ auto itr = acl_view.GetPayload().begin();
+ ASSERT_EQ(bd_addr, itr.extract<Address>());
+ ASSERT_EQ(handle, itr.extract<uint16_t>());
+ ASSERT_EQ(received_packets, itr.extract<uint16_t>());
+ received_packets += 1;
+ }
+ }
+
+ // Check to see if this future was already fulfilled.
+ auto acl_race_status = incoming_acl_future.wait_for(std::chrono::milliseconds(1));
+ if (acl_race_status == std::future_status::ready) {
+ // Get the next future.
+ incoming_acl_future = upper->GetReceivedAclFuture();
+ }
+
+ // One last packet to make sure they were all sent. Already got the future.
+ auto acl_payload = std::make_unique<RawBuilder>();
+ acl_payload->AddAddress(bd_addr);
+ acl_payload->AddOctets2(handle);
+ acl_payload->AddOctets2(num_packets);
+ hal->callbacks->aclDataReceived(
+ GetPacketBytes(AclPacketBuilder::Create(handle, packet_boundary_flag, broadcast_flag, std::move(acl_payload))));
+ auto incoming_acl_status = incoming_acl_future.wait_for(kAclTimeout);
+ ASSERT_EQ(incoming_acl_status, std::future_status::ready);
+ auto acl_view = upper->GetReceivedAcl();
+ ASSERT_TRUE(acl_view.IsValid());
+ ASSERT_EQ(sizeof(bd_addr) + sizeof(handle) + sizeof(received_packets), acl_view.GetPayload().size());
+ auto itr = acl_view.GetPayload().begin();
+ ASSERT_EQ(bd_addr, itr.extract<Address>());
+ ASSERT_EQ(handle, itr.extract<uint16_t>());
+ ASSERT_EQ(received_packets, itr.extract<uint16_t>());
+}
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/hci_packets.pdl b/gd/hci/hci_packets.pdl
new file mode 100644
index 0000000..e3ee19e
--- /dev/null
+++ b/gd/hci/hci_packets.pdl
@@ -0,0 +1,3667 @@
+little_endian_packets
+
+custom_field Address : 48 "hci/"
+custom_field ClassOfDevice : 24 "hci/"
+
+enum Enable : 8 {
+ DISABLED = 0x00,
+ ENABLED = 0x01,
+}
+
+// https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile
+enum GapDataType : 8 {
+ INVALID = 0x00,
+ FLAGS = 0x01,
+ INCOMPLETE_LIST_16_BIT_UUIDS = 0x02,
+ COMPLETE_LIST_16_BIT_UUIDS = 0x03,
+ INCOMPLETE_LIST_32_BIT_UUIDS = 0x04,
+ COMPLETE_LIST_32_BIT_UUIDS = 0x05,
+ INCOMPLETE_LIST_128_BIT_UUIDS = 0x06,
+ COMPLETE_LIST_128_BIT_UUIDS = 0x07,
+ SHORTENED_LOCAL_NAME = 0x08,
+ COMPLETE_LOCAL_NAME = 0x09,
+ TX_POWER_LEVEL = 0x0A,
+ CLASS_OF_DEVICE = 0x0D,
+}
+
+struct GapData {
+ _size_(data) : 8, // Including one byte for data_type
+ data_type : GapDataType,
+ data : 8[+1*8],
+}
+
+// HCI ACL Packets
+
+enum PacketBoundaryFlag : 2 {
+ FIRST_NON_AUTOMATICALLY_FLUSHABLE = 0,
+ CONTINUING_FRAGMENT = 1,
+ FIRST_AUTOMATICALLY_FLUSHABLE = 2,
+}
+
+enum BroadcastFlag : 2 {
+ POINT_TO_POINT = 0,
+ ACTIVE_SLAVE_BROADCAST = 1,
+}
+
+packet AclPacket {
+ handle : 12,
+ packet_boundary_flag : PacketBoundaryFlag,
+ broadcast_flag : BroadcastFlag,
+ _size_(_payload_) : 16,
+ _payload_,
+}
+
+// HCI SCO Packets
+
+enum PacketStatusFlag : 2 {
+ CORRECTLY_RECEIVED = 0,
+ POSSIBLY_INCOMPLETE = 1,
+ NO_DATA = 2,
+ PARTIALLY_LOST = 3,
+}
+
+packet ScoPacket {
+ handle : 12,
+ packet_status_flag : PacketStatusFlag,
+ _reserved_ : 2, // BroadcastFlag
+ _size_(data) : 8,
+ data : 8[],
+}
+
+// HCI Command Packets
+
+enum OpCode : 16 {
+ NONE = 0x0000,
+
+ // LINK_CONTROL
+ INQUIRY = 0x0401,
+ INQUIRY_CANCEL = 0x0402,
+ PERIODIC_INQUIRY_MODE = 0x0403,
+ EXIT_PERIODIC_INQUIRY_MODE = 0x0404,
+ CREATE_CONNECTION = 0x0405,
+ DISCONNECT = 0x0406,
+ CREATE_CONNECTION_CANCEL = 0x0408,
+ ACCEPT_CONNECTION_REQUEST = 0x0409,
+ REJECT_CONNECTION_REQUEST = 0x040A,
+ LINK_KEY_REQUEST_REPLY = 0x040B,
+ LINK_KEY_REQUEST_NEGATIVE_REPLY = 0x040C,
+ PIN_CODE_REQUEST_REPLY = 0x040D,
+ PIN_CODE_REQUEST_NEGATIVE_REPLY = 0x040E,
+ CHANGE_CONNECTION_PACKET_TYPE = 0x040F,
+ AUTHENTICATION_REQUESTED = 0x0411,
+ SET_CONNECTION_ENCRYPTION = 0x0413,
+ CHANGE_CONNECTION_LINK_KEY = 0x0415,
+ MASTER_LINK_KEY = 0x0417,
+ REMOTE_NAME_REQUEST = 0x0419,
+ REMOTE_NAME_REQUEST_CANCEL = 0x041A,
+ READ_REMOTE_SUPPORTED_FEATURES = 0x041B,
+ READ_REMOTE_EXTENDED_FEATURES = 0x041C,
+ READ_REMOTE_VERSION_INFORMATION = 0x041D,
+ READ_CLOCK_OFFSET = 0x041F,
+ READ_LMP_HANDLE = 0x0420,
+ SETUP_SYNCHRONOUS_CONNECTION = 0x0428,
+ ACCEPT_SYNCHRONOUS_CONNECTION = 0x0429,
+ REJECT_SYNCHRONOUS_CONNECTION = 0x042A,
+ IO_CAPABILITY_REQUEST_REPLY = 0x042B,
+ USER_CONFIRMATION_REQUEST_REPLY = 0x042C,
+ USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY = 0x042D,
+ USER_PASSKEY_REQUEST_REPLY = 0x042E,
+ USER_PASSKEY_REQUEST_NEGATIVE_REPLY = 0x042F,
+ REMOTE_OOB_DATA_REQUEST_REPLY = 0x0430,
+ REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY = 0x0433,
+ IO_CAPABILITY_REQUEST_NEGATIVE_REPLY = 0x0434,
+ ENHANCED_SETUP_SYNCHRONOUS_CONNECTION = 0x043D,
+ ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION = 0x043E,
+
+ // LINK_POLICY
+ HOLD_MODE = 0x0801,
+ SNIFF_MODE = 0x0803,
+ EXIT_SNIFF_MODE = 0x0804,
+ QOS_SETUP = 0x0807,
+ ROLE_DISCOVERY = 0x0809,
+ SWITCH_ROLE = 0x080B,
+ READ_LINK_POLICY_SETTINGS = 0x080C,
+ WRITE_LINK_POLICY_SETTINGS = 0x080D,
+ READ_DEFAULT_LINK_POLICY_SETTINGS = 0x080E,
+ WRITE_DEFAULT_LINK_POLICY_SETTINGS = 0x080F,
+ FLOW_SPECIFICATION = 0x0810,
+ SNIFF_SUBRATING = 0x0811,
+
+ // CONTROLLER_AND_BASEBAND
+ SET_EVENT_MASK = 0x0C01,
+ RESET = 0x0C03,
+ SET_EVENT_FILTER = 0x0C05,
+ FLUSH = 0x0C08,
+ READ_PIN_TYPE = 0x0C09,
+ WRITE_PIN_TYPE = 0x0C0A,
+ CREATE_NEW_UNIT_KEY = 0x0C0B,
+ READ_STORED_LINK_KEY = 0x0C0D,
+ WRITE_STORED_LINK_KEY = 0x0C11,
+ DELETE_STORED_LINK_KEY = 0x0C12,
+ WRITE_LOCAL_NAME = 0x0C13,
+ READ_LOCAL_NAME = 0x0C14,
+ READ_CONNECTION_ACCEPT_TIMEOUT = 0x0C15,
+ WRITE_CONNECTION_ACCEPT_TIMEOUT = 0x0C16,
+ READ_PAGE_TIMEOUT = 0x0C17,
+ WRITE_PAGE_TIMEOUT = 0x0C18,
+ READ_SCAN_ENABLE = 0x0C19,
+ WRITE_SCAN_ENABLE = 0x0C1A,
+ READ_PAGE_SCAN_ACTIVITY = 0x0C1B,
+ WRITE_PAGE_SCAN_ACTIVITY = 0x0C1C,
+ READ_INQUIRY_SCAN_ACTIVITY = 0x0C1D,
+ WRITE_INQUIRY_SCAN_ACTIVITY = 0x0C1E,
+ READ_AUTHENTICATION_ENABLE = 0x0C1F,
+ WRITE_AUTHENTICATION_ENABLE = 0x0C20,
+ READ_CLASS_OF_DEVICE = 0x0C23,
+ WRITE_CLASS_OF_DEVICE = 0x0C24,
+ READ_VOICE_SETTING = 0x0C25,
+ WRITE_VOICE_SETTING = 0x0C26,
+ READ_AUTOMATIC_FLUSH_TIMEOUT = 0x0C27,
+ WRITE_AUTOMATIC_FLUSH_TIMEOUT = 0x0C28,
+ READ_NUM_BROADCAST_RETRANSMITS = 0x0C29,
+ WRITE_NUM_BROADCAST_RETRANSMITS = 0x0C2A,
+ READ_HOLD_MODE_ACTIVITY = 0x0C2B,
+ WRITE_HOLD_MODE_ACTIVITY = 0x0C2C,
+ READ_TRANSMIT_POWER_LEVEL = 0x0C2D,
+ READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE = 0x0C2E,
+ WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE = 0x0C2F,
+ SET_CONTROLLER_TO_HOST_FLOW_CONTROL = 0x0C31,
+ HOST_BUFFER_SIZE = 0x0C33,
+ HOST_NUM_COMPLETED_PACKETS = 0x0C35,
+ READ_LINK_SUPERVISION_TIMEOUT = 0x0C36,
+ WRITE_LINK_SUPERVISION_TIMEOUT = 0x0C37,
+ READ_NUMBER_OF_SUPPORTED_IAC = 0x0C38,
+ READ_CURRENT_IAC_LAP = 0x0C39,
+ WRITE_CURRENT_IAC_LAP = 0x0C3A,
+ SET_AFH_HOST_CHANNEL_CLASSIFICATION = 0x0C3F,
+ READ_INQUIRY_SCAN_TYPE = 0x0C42,
+ WRITE_INQUIRY_SCAN_TYPE = 0x0C43,
+ READ_INQUIRY_MODE = 0x0C44,
+ WRITE_INQUIRY_MODE = 0x0C45,
+ READ_PAGE_SCAN_TYPE = 0x0C46,
+ WRITE_PAGE_SCAN_TYPE = 0x0C47,
+ READ_AFH_CHANNEL_ASSESSMENT_MODE = 0x0C48,
+ WRITE_AFH_CHANNEL_ASSESSMENT_MODE = 0x0C49,
+ READ_EXTENDED_INQUIRY_RESPONSE = 0x0C51,
+ WRITE_EXTENDED_INQUIRY_RESPONSE = 0x0C52,
+ REFRESH_ENCRYPTION_KEY = 0x0C53,
+ READ_SIMPLE_PAIRING_MODE = 0x0C55,
+ WRITE_SIMPLE_PAIRING_MODE = 0x0C56,
+ READ_LOCAL_OOB_DATA = 0x0C57,
+ READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL = 0x0C58,
+ WRITE_INQUIRY_TRANSMIT_POWER_LEVEL = 0x0C59,
+ SEND_KEYPRESS_NOTIFICATION = 0x0C60,
+
+ READ_LE_HOST_SUPPORT = 0x0C6C,
+ WRITE_LE_HOST_SUPPORT = 0x0C6D,
+
+ READ_SECURE_CONNECTIONS_HOST_SUPPORT = 0x0C79,
+ WRITE_SECURE_CONNECTIONS_HOST_SUPPORT = 0x0C7A,
+ READ_LOCAL_OOB_EXTENDED_DATA = 0x0C7D,
+
+ // INFORMATIONAL_PARAMETERS
+ READ_LOCAL_VERSION_INFORMATION = 0x1001,
+ READ_LOCAL_SUPPORTED_COMMANDS = 0x1002,
+ READ_LOCAL_SUPPORTED_FEATURES = 0x1003,
+ READ_LOCAL_EXTENDED_FEATURES = 0x1004,
+ READ_BUFFER_SIZE = 0x1005,
+ READ_BD_ADDR = 0x1009,
+ READ_DATA_BLOCK_SIZE = 0x100A,
+ READ_LOCAL_SUPPORTED_CODECS = 0x100B,
+
+ // STATUS_PARAMETERS
+ READ_FAILED_CONTACT_COUNTER = 0x1401,
+ RESET_FAILED_CONTACT_COUNTER = 0x1402,
+ READ_LINK_QUALITY = 0x1403,
+ READ_RSSI = 0x1405,
+ READ_AFH_CHANNEL_MAP = 0x1406,
+ READ_CLOCK = 0x1407,
+ READ_ENCRYPTION_KEY_SIZE = 0x1408,
+
+ // TESTING
+ READ_LOOPBACK_MODE = 0x1801,
+ WRITE_LOOPBACK_MODE = 0x1802,
+ ENABLE_DEVICE_UNDER_TEST_MODE = 0x1803,
+ WRITE_SIMPLE_PAIRING_DEBUG_MODE = 0x1804,
+ WRITE_SECURE_CONNECTIONS_TEST_MODE = 0x180A,
+
+ // LE_CONTROLLER
+ LE_SET_EVENT_MASK = 0x2001,
+ LE_READ_BUFFER_SIZE = 0x2002,
+ LE_READ_LOCAL_SUPPORTED_FEATURES = 0x2003,
+ LE_SET_RANDOM_ADDRESS = 0x2005,
+ LE_SET_ADVERTISING_PARAMETERS = 0x2006,
+ LE_READ_ADVERTISING_CHANNEL_TX_POWER = 0x2007,
+ LE_SET_ADVERTISING_DATA = 0x2008,
+ LE_SET_SCAN_RESPONSE_DATA = 0x2009,
+ LE_SET_ADVERTISING_ENABLE = 0x200A,
+ LE_SET_SCAN_PARAMETERS = 0x200B,
+ LE_SET_SCAN_ENABLE = 0x200C,
+ LE_CREATE_CONNECTION = 0x200D,
+ LE_CREATE_CONNECTION_CANCEL = 0x200E,
+ LE_READ_WHITE_LIST_SIZE = 0x200F,
+ LE_CLEAR_WHITE_LIST = 0x2010,
+ LE_ADD_DEVICE_TO_WHITE_LIST = 0x2011,
+ LE_REMOVE_DEVICE_FROM_WHITE_LIST = 0x2012,
+ LE_CONNECTION_UPDATE = 0x2013,
+ LE_SET_HOST_CHANNEL_CLASSIFICATION = 0x2014,
+ LE_READ_CHANNEL_MAP = 0x2015,
+ LE_READ_REMOTE_FEATURES = 0x2016,
+ LE_ENCRYPT = 0x2017,
+ LE_RAND = 0x2018,
+ LE_START_ENCRYPTION = 0x2019,
+ LE_LONG_TERM_KEY_REQUEST_REPLY = 0x201A,
+ LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY = 0x201B,
+ LE_READ_SUPPORTED_STATES = 0x201C,
+ LE_RECEIVER_TEST = 0x201D,
+ LE_TRANSMITTER_TEST = 0x201E,
+ LE_TEST_END = 0x201F,
+ LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY = 0x2020,
+ LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY = 0x2021,
+
+ LE_SET_DATA_LENGTH = 0x2022,
+ LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH = 0x2023,
+ LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH = 0x2024,
+ LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND = 0x2025,
+ LE_GENERATE_DHKEY_COMMAND = 0x2026,
+ LE_ADD_DEVICE_TO_RESOLVING_LIST = 0x2027,
+ LE_REMOVE_DEVICE_FROM_RESOLVING_LIST = 0x2028,
+ LE_CLEAR_RESOLVING_LIST = 0x2029,
+ LE_READ_RESOLVING_LIST_SIZE = 0x202A,
+ LE_READ_PEER_RESOLVABLE_ADDRESS = 0x202B,
+ LE_READ_LOCAL_RESOLVABLE_ADDRESS = 0x202C,
+ LE_SET_ADDRESS_RESOLUTION_ENABLE = 0x202D,
+ LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT = 0x202E,
+ LE_READ_MAXIMUM_DATA_LENGTH = 0x202F,
+ LE_READ_PHY = 0x2030,
+ LE_SET_DEFAULT_PHY = 0x2031,
+ LE_SET_PHY = 0x2032,
+ LE_ENHANCED_RECEIVER_TEST = 0x2033,
+ LE_ENHANCED_TRANSMITTER_TEST = 0x2034,
+ LE_SET_EXTENDED_ADVERTISING_RANDOM_ADDRESS = 0x2035,
+ LE_SET_EXTENDED_ADVERTISING_PARAMETERS = 0x2036,
+ LE_SET_EXTENDED_ADVERTISING_DATA = 0x2037,
+ LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE = 0x2038,
+ LE_SET_EXTENDED_ADVERTISING_ENABLE = 0x2039,
+ LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH = 0x203A,
+ LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS = 0x203B,
+ LE_REMOVE_ADVERTISING_SET = 0x203C,
+ LE_CLEAR_ADVERTISING_SETS = 0x203D,
+ LE_SET_PERIODIC_ADVERTISING_PARAM = 0x203E,
+ LE_SET_PERIODIC_ADVERTISING_DATA = 0x203F,
+ LE_SET_PERIODIC_ADVERTISING_ENABLE = 0x2040,
+ LE_SET_EXTENDED_SCAN_PARAMETERS = 0x2041,
+ LE_SET_EXTENDED_SCAN_ENABLE = 0x2042,
+ LE_EXTENDED_CREATE_CONNECTION = 0x2043,
+ LE_PERIODIC_ADVERTISING_CREATE_SYNC = 0x2044,
+ LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL = 0x2045,
+ LE_PERIODIC_ADVERTISING_TERMINATE_SYNC = 0x2046,
+ LE_ADD_DEVICE_TO_PERIODIC_ADVERTISING_LIST = 0x2047,
+ LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISING_LIST = 0x2048,
+ LE_CLEAR_PERIODIC_ADVERTISING_LIST = 0x2049,
+ LE_READ_PERIODIC_ADVERTISING_LIST_SIZE = 0x204A,
+ LE_READ_TRANSMIT_POWER = 0x204B,
+ LE_READ_RF_PATH_COMPENSATION_POWER = 0x204C,
+ LE_WRITE_RF_PATH_COMPENSATION_POWER = 0x204D,
+ LE_SET_PRIVACY_MODE = 0x204E,
+
+ // VENDOR_SPECIFIC
+ LE_GET_VENDOR_CAPABILITIES = 0xFD53,
+ LE_MULTI_ADVT = 0xFD54,
+ LE_BATCH_SCAN = 0xFD56,
+ LE_ADV_FILTER = 0xFD57,
+ LE_TRACK_ADV = 0xFD58,
+ LE_ENERGY_INFO = 0xFD59,
+ LE_EXTENDED_SCAN_PARAMS = 0xFD5A,
+ CONTROLLER_DEBUG_INFO = 0xFD5B,
+ CONTROLLER_A2DP_OPCODE = 0xFD5D,
+}
+
+// For mapping Local Supported Commands command
+// Value = Octet * 10 + bit
+enum OpCodeIndex : 16 {
+ INQUIRY = 0,
+ INQUIRY_CANCEL = 1,
+ PERIODIC_INQUIRY_MODE = 2,
+ EXIT_PERIODIC_INQUIRY_MODE = 3,
+ CREATE_CONNECTION = 4,
+ DISCONNECT = 5,
+ CREATE_CONNECTION_CANCEL = 7,
+ ACCEPT_CONNECTION_REQUEST = 10,
+ REJECT_CONNECTION_REQUEST = 11,
+ LINK_KEY_REQUEST_REPLY = 12,
+ LINK_KEY_REQUEST_NEGATIVE_REPLY = 13,
+ PIN_CODE_REQUEST_REPLY = 14,
+ PIN_CODE_REQUEST_NEGATIVE_REPLY = 15,
+ CHANGE_CONNECTION_PACKET_TYPE = 16,
+ AUTHENTICATION_REQUESTED = 17,
+ SET_CONNECTION_ENCRYPTION = 20,
+ CHANGE_CONNECTION_LINK_KEY = 21,
+ MASTER_LINK_KEY = 22,
+ REMOTE_NAME_REQUEST = 23,
+ REMOTE_NAME_REQUEST_CANCEL = 24,
+ READ_REMOTE_SUPPORTED_FEATURES = 25,
+ READ_REMOTE_EXTENDED_FEATURES = 26,
+ READ_REMOTE_VERSION_INFORMATION = 27,
+ READ_CLOCK_OFFSET = 30,
+ READ_LMP_HANDLE = 31,
+ HOLD_MODE = 41,
+ SNIFF_MODE = 42,
+ EXIT_SNIFF_MODE = 43,
+ QOS_SETUP = 46,
+ ROLE_DISCOVERY = 47,
+ SWITCH_ROLE = 50,
+ READ_LINK_POLICY_SETTINGS = 51,
+ WRITE_LINK_POLICY_SETTINGS = 52,
+ READ_DEFAULT_LINK_POLICY_SETTINGS = 53,
+ WRITE_DEFAULT_LINK_POLICY_SETTINGS = 54,
+ FLOW_SPECIFICATION = 55,
+ SET_EVENT_MASK = 56,
+ RESET = 57,
+ SET_EVENT_FILTER = 60,
+ FLUSH = 61,
+ READ_PIN_TYPE = 62,
+ WRITE_PIN_TYPE = 63,
+ READ_STORED_LINK_KEY = 65,
+ WRITE_STORED_LINK_KEY = 66,
+ DELETE_STORED_LINK_KEY = 67,
+ WRITE_LOCAL_NAME = 70,
+ READ_LOCAL_NAME = 71,
+ READ_CONNECTION_ACCEPT_TIMEOUT = 72,
+ WRITE_CONNECTION_ACCEPT_TIMEOUT = 73,
+ READ_PAGE_TIMEOUT = 74,
+ WRITE_PAGE_TIMEOUT = 75,
+ READ_SCAN_ENABLE = 76,
+ WRITE_SCAN_ENABLE = 77,
+ READ_PAGE_SCAN_ACTIVITY = 80,
+ WRITE_PAGE_SCAN_ACTIVITY = 81,
+ READ_INQUIRY_SCAN_ACTIVITY = 82,
+ WRITE_INQUIRY_SCAN_ACTIVITY = 83,
+ READ_AUTHENTICATION_ENABLE = 84,
+ WRITE_AUTHENTICATION_ENABLE = 85,
+ READ_CLASS_OF_DEVICE = 90,
+ WRITE_CLASS_OF_DEVICE = 91,
+ READ_VOICE_SETTING = 92,
+ WRITE_VOICE_SETTING = 93,
+ READ_AUTOMATIC_FLUSH_TIMEOUT = 94,
+ WRITE_AUTOMATIC_FLUSH_TIMEOUT = 95,
+ READ_NUM_BROADCAST_RETRANSMITS = 96,
+ WRITE_NUM_BROADCAST_RETRANSMITS = 97,
+ READ_HOLD_MODE_ACTIVITY = 100,
+ WRITE_HOLD_MODE_ACTIVITY = 101,
+ READ_TRANSMIT_POWER_LEVEL = 102,
+ READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE = 103,
+ WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE = 104,
+ SET_CONTROLLER_TO_HOST_FLOW_CONTROL = 105,
+ HOST_BUFFER_SIZE = 106,
+ HOST_NUM_COMPLETED_PACKETS = 107,
+ READ_LINK_SUPERVISION_TIMEOUT = 110,
+ WRITE_LINK_SUPERVISION_TIMEOUT = 111,
+ READ_NUMBER_OF_SUPPORTED_IAC = 112,
+ READ_CURRENT_IAC_LAP = 113,
+ WRITE_CURRENT_IAC_LAP = 114,
+ SET_AFH_HOST_CHANNEL_CLASSIFICATION = 121,
+ READ_INQUIRY_SCAN_TYPE = 124,
+ WRITE_INQUIRY_SCAN_TYPE = 125,
+ READ_INQUIRY_MODE = 126,
+ WRITE_INQUIRY_MODE = 127,
+ READ_PAGE_SCAN_TYPE = 130,
+ WRITE_PAGE_SCAN_TYPE = 131,
+ READ_AFH_CHANNEL_ASSESSMENT_MODE = 132,
+ WRITE_AFH_CHANNEL_ASSESSMENT_MODE = 133,
+ READ_LOCAL_VERSION_INFORMATION = 143,
+ READ_LOCAL_SUPPORTED_FEATURES = 145,
+ READ_LOCAL_EXTENDED_FEATURES = 146,
+ READ_BUFFER_SIZE = 147,
+ READ_BD_ADDR = 151,
+ READ_FAILED_CONTACT_COUNTER = 152,
+ RESET_FAILED_CONTACT_COUNTER = 153,
+ READ_LINK_QUALITY = 154,
+ READ_RSSI = 155,
+ READ_AFH_CHANNEL_MAP = 156,
+ READ_CLOCK = 157,
+ READ_LOOPBACK_MODE = 160,
+ WRITE_LOOPBACK_MODE = 161,
+ ENABLE_DEVICE_UNDER_TEST_MODE = 162,
+ SETUP_SYNCHRONOUS_CONNECTION = 163,
+ ACCEPT_SYNCHRONOUS_CONNECTION = 164,
+ REJECT_SYNCHRONOUS_CONNECTION = 165,
+ READ_EXTENDED_INQUIRY_RESPONSE = 170,
+ WRITE_EXTENDED_INQUIRY_RESPONSE = 171,
+ REFRESH_ENCRYPTION_KEY = 172,
+ SNIFF_SUBRATING = 174,
+ READ_SIMPLE_PAIRING_MODE = 175,
+ WRITE_SIMPLE_PAIRING_MODE = 176,
+ READ_LOCAL_OOB_DATA = 177,
+ READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL = 180,
+ WRITE_INQUIRY_TRANSMIT_POWER_LEVEL = 181,
+ IO_CAPABILITY_REQUEST_REPLY = 187,
+ USER_CONFIRMATION_REQUEST_REPLY = 190,
+ USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY = 191,
+ USER_PASSKEY_REQUEST_REPLY = 192,
+ USER_PASSKEY_REQUEST_NEGATIVE_REPLY = 193,
+ REMOTE_OOB_DATA_REQUEST_REPLY = 194,
+ WRITE_SIMPLE_PAIRING_DEBUG_MODE = 195,
+ REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY = 197,
+ SEND_KEYPRESS_NOTIFICATION = 202,
+ IO_CAPABILITY_REQUEST_NEGATIVE_REPLY = 203,
+ READ_ENCRYPTION_KEY_SIZE = 204,
+ READ_DATA_BLOCK_SIZE = 232,
+ READ_LE_HOST_SUPPORT = 245,
+ WRITE_LE_HOST_SUPPORT = 246,
+ LE_SET_EVENT_MASK = 250,
+ LE_READ_BUFFER_SIZE = 251,
+ LE_READ_LOCAL_SUPPORTED_FEATURES = 252,
+ LE_SET_RANDOM_ADDRESS = 254,
+ LE_SET_ADVERTISING_PARAMETERS = 255,
+ LE_READ_ADVERTISING_CHANNEL_TX_POWER = 256,
+ LE_SET_ADVERTISING_DATA = 257,
+ LE_SET_SCAN_RESPONSE_DATA = 260,
+ LE_SET_ADVERTISING_ENABLE = 261,
+ LE_SET_SCAN_PARAMETERS = 262,
+ LE_SET_SCAN_ENABLE = 263,
+ LE_CREATE_CONNECTION = 264,
+ LE_CREATE_CONNECTION_CANCEL = 265,
+ LE_READ_WHITE_LIST_SIZE = 266,
+ LE_CLEAR_WHITE_LIST = 267,
+ LE_ADD_DEVICE_TO_WHITE_LIST = 270,
+ LE_REMOVE_DEVICE_FROM_WHITE_LIST = 271,
+ LE_CONNECTION_UPDATE = 272,
+ LE_SET_HOST_CHANNEL_CLASSIFICATION = 273,
+ LE_READ_CHANNEL_MAP = 274,
+ LE_READ_REMOTE_FEATURES = 275,
+ LE_ENCRYPT = 276,
+ LE_RAND = 277,
+ LE_START_ENCRYPTION = 280,
+ LE_LONG_TERM_KEY_REQUEST_REPLY = 281,
+ LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY = 282,
+ LE_READ_SUPPORTED_STATES = 283,
+ LE_RECEIVER_TEST = 284,
+ LE_TRANSMITTER_TEST = 285,
+ LE_TEST_END = 286,
+ ENHANCED_SETUP_SYNCHRONOUS_CONNECTION = 293,
+ ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION = 294,
+ READ_LOCAL_SUPPORTED_CODECS = 295,
+ READ_SECURE_CONNECTIONS_HOST_SUPPORT = 322,
+ WRITE_SECURE_CONNECTIONS_HOST_SUPPORT = 323,
+ READ_LOCAL_OOB_EXTENDED_DATA = 326,
+ WRITE_SECURE_CONNECTIONS_TEST_MODE = 327,
+ LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY = 334,
+ LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY = 335,
+ LE_SET_DATA_LENGTH = 336,
+ LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH = 337,
+ LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH = 340,
+ LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND = 341,
+ LE_GENERATE_DHKEY_COMMAND = 342,
+ LE_ADD_DEVICE_TO_RESOLVING_LIST = 343,
+ LE_REMOVE_DEVICE_FROM_RESOLVING_LIST = 344,
+ LE_CLEAR_RESOLVING_LIST = 345,
+ LE_READ_RESOLVING_LIST_SIZE = 346,
+ LE_READ_PEER_RESOLVABLE_ADDRESS = 347,
+ LE_READ_LOCAL_RESOLVABLE_ADDRESS = 350,
+ LE_SET_ADDRESS_RESOLUTION_ENABLE = 351,
+ LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT = 352,
+ LE_READ_MAXIMUM_DATA_LENGTH = 353,
+ LE_READ_PHY = 354,
+ LE_SET_DEFAULT_PHY = 355,
+ LE_SET_PHY = 356,
+ LE_ENHANCED_RECEIVER_TEST = 357,
+ LE_ENHANCED_TRANSMITTER_TEST = 360,
+ LE_SET_EXTENDED_ADVERTISING_RANDOM_ADDRESS = 361,
+ LE_SET_EXTENDED_ADVERTISING_PARAMETERS = 362,
+ LE_SET_EXTENDED_ADVERTISING_DATA = 363,
+ LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE = 364,
+ LE_SET_EXTENDED_ADVERTISING_ENABLE = 365,
+ LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH = 366,
+ LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS = 367,
+ LE_REMOVE_ADVERTISING_SET = 370,
+ LE_CLEAR_ADVERTISING_SETS = 371,
+ LE_SET_PERIODIC_ADVERTISING_PARAM = 372,
+ LE_SET_PERIODIC_ADVERTISING_DATA = 373,
+ LE_SET_PERIODIC_ADVERTISING_ENABLE = 374,
+ LE_SET_EXTENDED_SCAN_PARAMETERS = 375,
+ LE_SET_EXTENDED_SCAN_ENABLE = 376,
+ LE_EXTENDED_CREATE_CONNECTION = 377,
+ LE_PERIODIC_ADVERTISING_CREATE_SYNC = 380,
+ LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL = 381,
+ LE_PERIODIC_ADVERTISING_TERMINATE_SYNC = 382,
+ LE_ADD_DEVICE_TO_PERIODIC_ADVERTISING_LIST = 383,
+ LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISING_LIST = 384,
+ LE_CLEAR_PERIODIC_ADVERTISING_LIST = 385,
+ LE_READ_PERIODIC_ADVERTISING_LIST_SIZE = 386,
+ LE_READ_TRANSMIT_POWER = 387,
+ LE_READ_RF_PATH_COMPENSATION_POWER = 390,
+ LE_WRITE_RF_PATH_COMPENSATION_POWER = 391,
+ LE_SET_PRIVACY_MODE = 392,
+}
+
+packet CommandPacket {
+ op_code : OpCode,
+ _size_(_payload_) : 8,
+ _payload_,
+}
+
+// Packets for interfaces
+
+packet DiscoveryCommand : CommandPacket { _payload_, }
+packet ConnectionManagementCommand : CommandPacket { _payload_, }
+packet SecurityCommand : CommandPacket { _payload_, }
+packet ScoConnectionCommand : CommandPacket { _payload_, }
+packet LeAdvertisingCommand : CommandPacket { _payload_, }
+packet LeScanningCommand : CommandPacket { _payload_, }
+packet LeConnectionManagementCommand : CommandPacket { _payload_, }
+packet LeSecurityCommand : CommandPacket { _payload_, }
+packet VendorCommand : CommandPacket { _payload_, }
+
+// HCI Event Packets
+
+enum EventCode : 8 {
+ INQUIRY_COMPLETE = 0x01,
+ INQUIRY_RESULT = 0x02,
+ CONNECTION_COMPLETE = 0x03,
+ CONNECTION_REQUEST = 0x04,
+ DISCONNECTION_COMPLETE = 0x05,
+ AUTHENTICATION_COMPLETE = 0x06,
+ REMOTE_NAME_REQUEST_COMPLETE = 0x07,
+ ENCRYPTION_CHANGE = 0x08,
+ CHANGE_CONNECTION_LINK_KEY_COMPLETE = 0x09,
+ MASTER_LINK_KEY_COMPLETE = 0x0A,
+ READ_REMOTE_SUPPORTED_FEATURES_COMPLETE = 0x0B,
+ READ_REMOTE_VERSION_INFORMATION_COMPLETE = 0x0C,
+ QOS_SETUP_COMPLETE = 0x0D,
+ COMMAND_COMPLETE = 0x0E,
+ COMMAND_STATUS = 0x0F,
+ HARDWARE_ERROR = 0x10,
+ FLUSH_OCCURRED = 0x11,
+ ROLE_CHANGE = 0x12,
+ NUMBER_OF_COMPLETED_PACKETS = 0x13,
+ MODE_CHANGE = 0x14,
+ RETURN_LINK_KEYS = 0x15,
+ PIN_CODE_REQUEST = 0x16,
+ LINK_KEY_REQUEST = 0x17,
+ LINK_KEY_NOTIFICATION = 0x18,
+ LOOPBACK_COMMAND = 0x19,
+ DATA_BUFFER_OVERFLOW = 0x1A,
+ MAX_SLOTS_CHANGE = 0x1B,
+ READ_CLOCK_OFFSET_COMPLETE = 0x1C,
+ CONNECTION_PACKET_TYPE_CHANGED = 0x1D,
+ QOS_VIOLATION = 0x1E,
+ PAGE_SCAN_REPETITION_MODE_CHANGE = 0x20,
+ FLOW_SPECIFICATION_COMPLETE = 0x21,
+ INQUIRY_RESULT_WITH_RSSI = 0x22,
+ READ_REMOTE_EXTENDED_FEATURES_COMPLETE = 0x23,
+ SYNCHRONOUS_CONNECTION_COMPLETE = 0x2C,
+ SYNCHRONOUS_CONNECTION_CHANGED = 0x2D,
+ SNIFF_SUBRATING = 0x2E,
+ EXTENDED_INQUIRY_RESULT = 0x2F,
+ ENCRYPTION_KEY_REFRESH_COMPLETE = 0x30,
+ IO_CAPABILITY_REQUEST = 0x31,
+ IO_CAPABILITY_RESPONSE = 0x32,
+ USER_CONFIRMATION_REQUEST = 0x33,
+ USER_PASSKEY_REQUEST = 0x34,
+ REMOTE_OOB_DATA_REQUEST = 0x35,
+ SIMPLE_PAIRING_COMPLETE = 0x36,
+ LINK_SUPERVISION_TIMEOUT_CHANGED = 0x38,
+ ENHANCED_FLUSH_COMPLETE = 0x39,
+ USER_PASSKEY_NOTIFICATION = 0x3B,
+ KEYPRESS_NOTIFICATION = 0x3C,
+ REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION = 0x3D,
+ LE_META_EVENT = 0x3e,
+ NUMBER_OF_COMPLETED_DATA_BLOCKS = 0x48,
+ VENDOR_SPECIFIC = 0xFF,
+}
+
+packet EventPacket {
+ event_code : EventCode,
+ _size_(_payload_) : 8,
+ _payload_,
+}
+
+// LE Events
+
+enum SubeventCode : 8 {
+ CONNECTION_COMPLETE = 0x01,
+ ADVERTISING_REPORT = 0x02,
+ CONNECTION_UPDATE_COMPLETE = 0x03,
+ READ_REMOTE_FEATURES_COMPLETE = 0x04,
+ LONG_TERM_KEY_REQUEST = 0x05,
+ REMOTE_CONNECTION_PARAMETER_REQUEST = 0x06,
+ DATA_LENGTH_CHANGE = 0x07,
+ READ_LOCAL_P256_PUBLIC_KEY_COMPLETE = 0x08,
+ GENERATE_DHKEY_COMPLETE = 0x09,
+ ENHANCED_CONNECTION_COMPLETE = 0x0a,
+ DIRECTED_ADVERTISING_REPORT = 0x0b,
+ PHY_UPDATE_COMPLETE = 0x0c,
+ EXTENDED_ADVERTISING_REPORT = 0x0D,
+ PERIODIC_ADVERTISING_SYNC_ESTABLISHED = 0x0E,
+ PERIODIC_ADVERTISING_REPORT = 0x0F,
+ PERIODIC_ADVERTISING_SYNC_LOST = 0x10,
+ SCAN_TIMEOUT = 0x11,
+ ADVERTISING_SET_TERMINATED = 0x12,
+ SCAN_REQUEST_RECEIVED = 0x13,
+}
+
+// Common definitions for commands and events
+
+enum FeatureFlag : 1 {
+ UNSUPPORTED = 0,
+ SUPPORTED = 1,
+}
+
+enum ErrorCode: 8 {
+ SUCCESS = 0x00,
+ UNKNOWN_HCI_COMMAND = 0x01,
+ UNKNOWN_CONNECTION = 0x02,
+ HARDWARE_FAILURE = 0x03,
+ PAGE_TIMEOUT = 0x04,
+ AUTHENTICATION_FAILURE = 0x05,
+ PIN_OR_KEY_MISSING = 0x06,
+ MEMORY_CAPACITY_EXCEEDED = 0x07,
+ CONNECTION_TIMEOUT = 0x08,
+ CONNECTION_LIMIT_EXCEEDED = 0x09,
+ SYNCHRONOUS_CONNECTION_LIMIT_EXCEEDED = 0x0A,
+ CONNECTION_ALREADY_EXISTS = 0x0B,
+ COMMAND_DISALLOWED = 0x0C,
+ CONNECTION_REJECTED_LIMITED_RESOURCES = 0x0D,
+ CONNECTION_REJECTED_SECURITY_REASONS = 0x0E,
+ CONNECTION_REJECTED_UNACCEPTABLE_BD_ADDR = 0x0F,
+ CONNECTION_ACCEPT_TIMEOUT = 0x10,
+ UNSUPORTED_FEATURE_OR_PARAMETER_VALUE = 0x11,
+ INVALID_HCI_COMMAND_PARAMETERS = 0x12,
+ REMOTE_USER_TERMINATED_CONNECTION = 0x13,
+ REMOTE_DEVICE_TERMINATED_CONNECTION_LOW_RESOURCES = 0x14,
+ REMOTE_DEVICE_TERMINATED_CONNECTION_POWER_OFF = 0x15,
+ CONNECTION_TERMINATED_BY_LOCAL_HOST = 0x16,
+ REPEATED_ATTEMPTS = 0x17,
+ PAIRING_NOT_ALLOWED = 0x18,
+ UNKNOWN_LMP_PDU = 0x19,
+ UNSUPPORTED_REMOTE_OR_LMP_FEATURE = 0x1A,
+ SCO_OFFSET_REJECTED = 0x1B,
+ SCO_INTERVAL_REJECTED = 0x1C,
+ SCO_AIR_MODE_REJECTED = 0x1D,
+ INVALID_LMP_OR_LL_PARAMETERS = 0x1E,
+ UNSPECIFIED_ERROR = 0x1F,
+ UNSUPPORTED_LMP_OR_LL_PARAMETER = 0x20,
+ ROLE_CHANGE_NOT_ALLOWED = 0x21,
+ ENCRYPTION_MODE_NOT_ACCEPTABLE = 0x25,
+ CONTROLLER_BUSY = 0x3A,
+}
+
+// Events that are defined with their respective commands
+
+packet CommandComplete : EventPacket (event_code = COMMAND_COMPLETE){
+ num_hci_command_packets : 8,
+ command_op_code : OpCode,
+ _payload_,
+}
+
+packet CommandStatus : EventPacket (event_code = COMMAND_STATUS){
+ status : ErrorCode, // SUCCESS means PENDING
+ num_hci_command_packets : 8,
+ command_op_code : OpCode,
+ _payload_,
+}
+
+ // Credits
+packet NoCommandComplete : CommandComplete (command_op_code = NONE){
+}
+
+struct Lap { // Lower Address Part
+ lap : 6,
+ _reserved_ : 2,
+ _fixed_ = 0x9e8b : 16,
+}
+
+ // LINK_CONTROL
+packet Inquiry : DiscoveryCommand (op_code = INQUIRY) {
+ lap : Lap,
+ inquiry_length : 8, // 0x1 - 0x30 (times 1.28s)
+ num_responses : 8, // 0x00 unlimited
+}
+
+packet InquiryStatus : CommandStatus (command_op_code = INQUIRY) {
+}
+
+packet InquiryCancel : DiscoveryCommand (op_code = INQUIRY_CANCEL) {
+}
+
+packet InquiryCancelComplete : CommandComplete (command_op_code = INQUIRY_CANCEL) {
+ status : ErrorCode,
+}
+
+packet PeriodicInquiryMode : DiscoveryCommand (op_code = PERIODIC_INQUIRY_MODE) {
+ max_period_length : 16, // Range 0x0003 to 0xffff (times 1.28s)
+ min_period_length : 16, // Range 0x0002 to 0xfffe (times 1.28s)
+ lap : Lap,
+ inquiry_length : 8, // 0x1 - 0x30 (times 1.28s)
+ num_responses : 8, // 0x00 unlimited
+}
+
+packet PeriodicInquiryModeComplete : CommandComplete (command_op_code = PERIODIC_INQUIRY_MODE) {
+ status : ErrorCode,
+}
+
+packet ExitPeriodicInquiryMode : DiscoveryCommand (op_code = EXIT_PERIODIC_INQUIRY_MODE) {
+}
+
+packet ExitPeriodicInquiryModeComplete : CommandComplete (command_op_code = EXIT_PERIODIC_INQUIRY_MODE) {
+ status : ErrorCode,
+}
+
+enum PageScanRepetitionMode : 8 {
+ R0 = 0x00,
+ R1 = 0x01,
+ R2 = 0x02,
+}
+
+enum ClockOffsetValid : 1 {
+ INVALID = 0,
+ VALID = 1,
+}
+
+enum CreateConnectionRoleSwitch : 8 {
+ REMAIN_MASTER = 0x00,
+ ALLOW_ROLE_SWITCH = 0x01,
+}
+
+packet CreateConnection : ConnectionManagementCommand (op_code = CREATE_CONNECTION) {
+ bd_addr : Address,
+ packet_type : 16,
+ page_scan_repetition_mode : PageScanRepetitionMode,
+ _reserved_ : 8,
+ clock_offset : 15,
+ clock_offset_valid : ClockOffsetValid,
+ allow_role_switch : CreateConnectionRoleSwitch,
+}
+
+packet CreateConnectionStatus : CommandStatus (command_op_code = CREATE_CONNECTION) {
+}
+
+enum DisconnectReason : 8 {
+ AUTHENTICATION_FAILURE = 0x05,
+ REMOTE_USER_TERMINATED_CONNECTION = 0x13,
+ REMOTE_DEVICE_TERMINATED_CONNECTION_LOW_RESOURCES = 0x14,
+ REMOTE_DEVICE_TERMINATED_CONNECTION_POWER_OFF = 0x15,
+ UNSUPPORTED_REMOTE_FEATURE = 0x1A,
+ PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED = 0x29,
+ UNACCEPTABLE_CONNECTION_PARAMETERS = 0x3B,
+}
+
+packet Disconnect : ConnectionManagementCommand (op_code = DISCONNECT) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ reason : DisconnectReason,
+}
+
+packet DisconnectStatus : CommandStatus (command_op_code = DISCONNECT) {
+}
+
+packet CreateConnectionCancel : ConnectionManagementCommand (op_code = CREATE_CONNECTION_CANCEL) {
+ bd_addr : Address,
+}
+
+packet CreateConnectionCancelComplete : CommandComplete (command_op_code = CREATE_CONNECTION_CANCEL) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+enum AcceptConnectionRequestRole : 8 {
+ BECOME_MASTER = 0x00,
+ REMAIN_SLAVE = 0x01,
+}
+
+packet AcceptConnectionRequest : ConnectionManagementCommand (op_code = ACCEPT_CONNECTION_REQUEST) {
+ bd_addr : Address,
+ role : AcceptConnectionRequestRole,
+}
+
+packet AcceptConnectionRequestStatus : CommandStatus (command_op_code = ACCEPT_CONNECTION_REQUEST) {
+}
+
+enum RejectConnectionReason : 8 {
+ LIMITED_RESOURCES = 0x0D,
+ SECURITY_REASONS = 0x0E,
+ UNACCEPTABLE_BD_ADDR = 0x0F,
+}
+
+packet RejectConnectionRequest : ConnectionManagementCommand (op_code = REJECT_CONNECTION_REQUEST) {
+ bd_addr : Address,
+ reason : RejectConnectionReason,
+}
+
+packet RejectConnectionRequestStatus : CommandStatus (command_op_code = REJECT_CONNECTION_REQUEST) {
+}
+
+packet LinkKeyRequestReply : SecurityCommand (op_code = LINK_KEY_REQUEST_REPLY) {
+ bd_addr : Address,
+ link_key : 8[16],
+}
+
+packet LinkKeyRequestReplyComplete : CommandComplete (command_op_code = LINK_KEY_REQUEST_REPLY) {
+ status : ErrorCode,
+}
+
+packet LinkKeyRequestNegativeReply : SecurityCommand (op_code = LINK_KEY_REQUEST_NEGATIVE_REPLY) {
+ bd_addr : Address,
+}
+
+packet LinkKeyRequestNegativeReplyComplete : CommandComplete (command_op_code = LINK_KEY_REQUEST_NEGATIVE_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet PinCodeRequestReply : SecurityCommand (op_code = PIN_CODE_REQUEST_REPLY) {
+ bd_addr : Address,
+ pin_code_length : 5, // 0x01 - 0x10
+ _reserved_ : 3,
+ pin_code : 8[16], // string parameter, first octet first
+}
+
+packet PinCodeRequestReplyComplete : CommandComplete (command_op_code = PIN_CODE_REQUEST_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet PinCodeRequestNegativeReply : SecurityCommand (op_code = PIN_CODE_REQUEST_NEGATIVE_REPLY) {
+ bd_addr : Address,
+}
+
+packet PinCodeRequestNegativeReplyComplete : CommandComplete (command_op_code = PIN_CODE_REQUEST_NEGATIVE_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet ChangeConnectionPacketType : ConnectionManagementCommand (op_code = CHANGE_CONNECTION_PACKET_TYPE) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ packet_type : 16,
+}
+
+packet ChangeConnectionPacketTypeStatus : CommandStatus (command_op_code = CHANGE_CONNECTION_PACKET_TYPE) {
+}
+
+packet AuthenticationRequested : ConnectionManagementCommand (op_code = AUTHENTICATION_REQUESTED) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet AuthenticationRequestedStatus : CommandStatus (command_op_code = AUTHENTICATION_REQUESTED) {
+}
+
+packet SetConnectionEncryption : ConnectionManagementCommand (op_code = SET_CONNECTION_ENCRYPTION) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ encryption_enable : Enable,
+}
+
+packet SetConnectionEncryptionStatus : CommandStatus (command_op_code = SET_CONNECTION_ENCRYPTION) {
+}
+
+packet ChangeConnectionLinkKey : ConnectionManagementCommand (op_code = CHANGE_CONNECTION_LINK_KEY) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ChangeConnectionLinkKeyStatus : CommandStatus (command_op_code = CHANGE_CONNECTION_LINK_KEY) {
+}
+
+enum KeyFlag : 8 {
+ SEMI_PERMANENT = 0x00,
+ TEMPORARY = 0x01,
+}
+
+packet MasterLinkKey : ConnectionManagementCommand (op_code = MASTER_LINK_KEY) {
+ key_flag : KeyFlag,
+}
+
+packet MasterLinkKeyStatus : CommandStatus (command_op_code = MASTER_LINK_KEY) {
+}
+
+packet RemoteNameRequest : DiscoveryCommand (op_code = REMOTE_NAME_REQUEST) {
+ bd_addr : Address,
+ page_scan_repetition_mode : PageScanRepetitionMode,
+ _reserved_ : 8,
+ clock_offset : 15,
+ clock_offset_valid : ClockOffsetValid,
+}
+
+packet RemoteNameRequestStatus : CommandStatus (command_op_code = REMOTE_NAME_REQUEST) {
+}
+
+packet RemoteNameRequestCancel : DiscoveryCommand (op_code = REMOTE_NAME_REQUEST_CANCEL) {
+ bd_addr : Address,
+}
+
+packet RemoteNameRequestCancelComplete : CommandComplete (command_op_code = REMOTE_NAME_REQUEST_CANCEL) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet ReadRemoteSupportedFeatures : DiscoveryCommand (op_code = READ_REMOTE_SUPPORTED_FEATURES) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadRemoteSupportedFeaturesStatus : CommandStatus (command_op_code = READ_REMOTE_SUPPORTED_FEATURES) {
+}
+
+packet ReadRemoteExtendedFeatures : DiscoveryCommand (op_code = READ_REMOTE_EXTENDED_FEATURES) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ page_number : 8,
+}
+
+packet ReadRemoteExtendedFeaturesStatus : CommandStatus (command_op_code = READ_REMOTE_EXTENDED_FEATURES) {
+}
+
+packet ReadRemoteVersionInformation : DiscoveryCommand (op_code = READ_REMOTE_VERSION_INFORMATION) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadRemoteVersionInformationStatus : CommandStatus (command_op_code = READ_REMOTE_VERSION_INFORMATION) {
+}
+
+packet ReadClockOffset : ConnectionManagementCommand (op_code = READ_CLOCK_OFFSET) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadClockOffsetStatus : CommandStatus (command_op_code = READ_CLOCK_OFFSET) {
+}
+
+packet ReadLmpHandle : ConnectionManagementCommand (op_code = READ_LMP_HANDLE) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadLmpHandleComplete : CommandComplete (command_op_code = READ_LMP_HANDLE) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ lmp_handle : 8,
+ _reserved_ : 32,
+}
+
+packet SetupSynchronousConnection : ScoConnectionCommand (op_code = SETUP_SYNCHRONOUS_CONNECTION) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet AcceptSynchronousConnection : ScoConnectionCommand (op_code = ACCEPT_SYNCHRONOUS_CONNECTION) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet RejectSynchronousConnection : ScoConnectionCommand (op_code = REJECT_SYNCHRONOUS_CONNECTION) {
+ _payload_, // placeholder (unimplemented)
+}
+
+enum IoCapability : 8 {
+ DISPLAY_ONLY = 0x00,
+ DISPLAY_YES_NO = 0x01,
+ KEYBOARD_ONLY = 0x02,
+ NO_INPUT_NO_OUTPUT = 0x03,
+}
+
+enum OobDataPresent : 8 {
+ NOT_PRESENT = 0x00,
+ P_192_PRESENT = 0x01,
+ P_256_PRESENT = 0x02,
+ P_192_AND_256_PRESENT = 0x03,
+}
+
+enum AuthenticationRequirements : 8 {
+ NO_BONDING = 0x00,
+ NO_BONDING_MITM_PROTECTION = 0x01,
+ DEDICATED_BONDING = 0x02,
+ DEDICATED_BONDING_MITM_PROTECTION = 0x03,
+ GENERAL_BONDING = 0x04,
+ GENERAL_BONDING_MITM_PROTECTION = 0x05,
+}
+
+packet IoCapabilityRequestReply : SecurityCommand (op_code = IO_CAPABILITY_REQUEST_REPLY) {
+ bd_addr : Address,
+ io_capability : IoCapability,
+ oob_present : OobDataPresent,
+ authentication_requirements : AuthenticationRequirements,
+}
+
+packet IoCapabilityRequestReplyComplete : CommandComplete (command_op_code = IO_CAPABILITY_REQUEST_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet UserConfirmationRequestReply : SecurityCommand (op_code = USER_CONFIRMATION_REQUEST_REPLY) {
+ bd_addr : Address,
+}
+
+packet UserConfirmationRequestReplyComplete : CommandComplete (command_op_code = USER_CONFIRMATION_REQUEST_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet UserConfirmationRequestNegativeReply : SecurityCommand (op_code = USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY) {
+ bd_addr : Address,
+}
+
+packet UserConfirmationRequestNegativeReplyComplete : CommandComplete (command_op_code = USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet UserPasskeyRequestReply : SecurityCommand (op_code = USER_PASSKEY_REQUEST_REPLY) {
+ bd_addr : Address,
+ numeric_value : 32, // 000000-999999 decimal or 0x0-0xF423F
+}
+
+packet UserPasskeyRequestReplyComplete : CommandComplete (command_op_code = USER_PASSKEY_REQUEST_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet UserPasskeyRequestNegativeReply : SecurityCommand (op_code = USER_PASSKEY_REQUEST_NEGATIVE_REPLY) {
+ bd_addr : Address,
+}
+
+packet UserPasskeyRequestNegativeReplyComplete : CommandComplete (command_op_code = USER_PASSKEY_REQUEST_NEGATIVE_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet RemoteOobDataRequestReply : SecurityCommand (op_code = REMOTE_OOB_DATA_REQUEST_REPLY) {
+ bd_addr : Address,
+ c : 8[16],
+ r : 8[16],
+}
+
+packet RemoteOobDataRequestReplyComplete : CommandComplete (command_op_code = REMOTE_OOB_DATA_REQUEST_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet RemoteOobDataRequestNegativeReply : SecurityCommand (op_code = REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY) {
+ bd_addr : Address,
+}
+
+packet RemoteOobDataRequestNegativeReplyComplete : CommandComplete (command_op_code = REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet IoCapabilityRequestNegativeReply : SecurityCommand (op_code = IO_CAPABILITY_REQUEST_NEGATIVE_REPLY) {
+ bd_addr : Address,
+ reason : ErrorCode,
+}
+
+packet IoCapabilityRequestNegativeReplyComplete : CommandComplete (command_op_code = IO_CAPABILITY_REQUEST_NEGATIVE_REPLY) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet EnhancedSetupSynchronousConnection : ScoConnectionCommand (op_code = ENHANCED_SETUP_SYNCHRONOUS_CONNECTION) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet EnhancedAcceptSynchronousConnection : ScoConnectionCommand (op_code = ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION) {
+ _payload_, // placeholder (unimplemented)
+}
+
+
+ // LINK_POLICY
+packet HoldMode : ConnectionManagementCommand (op_code = HOLD_MODE) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ hold_mode_max_interval: 16, // 0x0002-0xFFFE (1.25ms-40.9s)
+ hold_mode_min_interval: 16, // 0x0002-0xFFFE (1.25ms-40.9s)
+}
+
+packet HoldModeStatus : CommandStatus (command_op_code = HOLD_MODE) {
+}
+
+
+packet SniffMode : ConnectionManagementCommand (op_code = SNIFF_MODE) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ sniff_max_interval: 16, // 0x0002-0xFFFE (1.25ms-40.9s)
+ sniff_min_interval: 16, // 0x0002-0xFFFE (1.25ms-40.9s)
+ sniff_attempt: 16, // 0x0001-0x7FFF (1.25ms-40.9s)
+ sniff_timeout: 16, // 0x0000-0x7FFF (0ms-40.9s)
+}
+
+packet SniffModeStatus : CommandStatus (command_op_code = SNIFF_MODE) {
+}
+
+
+packet ExitSniffMode : ConnectionManagementCommand (op_code = EXIT_SNIFF_MODE) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ExitSniffModeStatus : CommandStatus (command_op_code = EXIT_SNIFF_MODE) {
+}
+
+enum ServiceType : 8 {
+ NO_TRAFFIC = 0x00,
+ BEST_EFFORT = 0x01,
+ GUARANTEED = 0x02,
+}
+
+packet QosSetup : ConnectionManagementCommand (op_code = QOS_SETUP) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ _reserved_ : 8,
+ service_type : ServiceType,
+ token_rate : 32, // Octets/s
+ peak_bandwidth : 32, // Octets/s
+ latency : 32, // Octets/s
+ delay_variation : 32, // microseconds
+}
+
+packet QosSetupStatus : CommandStatus (command_op_code = QOS_SETUP) {
+}
+
+packet RoleDiscovery : ConnectionManagementCommand (op_code = ROLE_DISCOVERY) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+enum Role : 8 {
+ MASTER = 0x00,
+ SLAVE = 0x01,
+}
+
+packet RoleDiscoveryComplete : CommandComplete (command_op_code = ROLE_DISCOVERY) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ current_role : Role,
+}
+
+packet SwitchRole : ConnectionManagementCommand (op_code = SWITCH_ROLE) {
+ bd_addr : Address,
+ role : Role,
+}
+
+packet SwitchRoleStatus : CommandStatus (command_op_code = SWITCH_ROLE) {
+}
+
+
+packet ReadLinkPolicySettings : ConnectionManagementCommand (op_code = READ_LINK_POLICY_SETTINGS) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+enum LinkPolicy : 16 {
+ ENABLE_ROLE_SWITCH = 0x01,
+ ENABLE_HOLD_MODE = 0x02,
+ ENABLE_SNIFF_MODE = 0x04,
+ ENABLE_PARK_MODE = 0x08, // deprecated after 5.0
+}
+
+packet ReadLinkPolicySettingsComplete : CommandComplete (command_op_code = READ_LINK_POLICY_SETTINGS) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ link_policy_settings : 16,
+}
+
+packet WriteLinkPolicySettings : ConnectionManagementCommand (op_code = WRITE_LINK_POLICY_SETTINGS) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ link_policy_settings : 16,
+}
+
+packet WriteLinkPolicySettingsComplete : CommandComplete (command_op_code = WRITE_LINK_POLICY_SETTINGS) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadDefaultLinkPolicySettings : ConnectionManagementCommand (op_code = READ_DEFAULT_LINK_POLICY_SETTINGS) {
+}
+
+packet ReadDefaultLinkPolicySettingsComplete : CommandComplete (command_op_code = READ_DEFAULT_LINK_POLICY_SETTINGS) {
+ status : ErrorCode,
+ default_link_policy_settings : 16,
+}
+
+packet WriteDefaultLinkPolicySettings : ConnectionManagementCommand (op_code = WRITE_DEFAULT_LINK_POLICY_SETTINGS) {
+ default_link_policy_settings : 16,
+}
+
+packet WriteDefaultLinkPolicySettingsComplete : CommandComplete (command_op_code = WRITE_DEFAULT_LINK_POLICY_SETTINGS) {
+ status : ErrorCode,
+}
+
+enum FlowDirection : 8 {
+ OUTGOING_FLOW = 0x00,
+ INCOMING_FLOW = 0x01,
+}
+
+packet FlowSpecification : ConnectionManagementCommand (op_code = FLOW_SPECIFICATION) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ _reserved_ : 8,
+ flow_direction : FlowDirection,
+ service_type : ServiceType,
+ token_rate : 32, // Octets/s
+ token_bucket_size : 32,
+ peak_bandwidth : 32, // Octets/s
+ access_latency : 32, // Octets/s
+}
+
+packet FlowSpecificationStatus : CommandStatus (command_op_code = FLOW_SPECIFICATION) {
+}
+
+packet SniffSubrating : ConnectionManagementCommand (op_code = SNIFF_SUBRATING) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ maximum_latency : 16, // 0x0002-0xFFFE (1.25ms-40.9s)
+ minimum_remote_timeout : 16, // 0x0000-0xFFFE (0-40.9s)
+ minimum_local_timeout: 16, // 0x0000-0xFFFE (0-40.9s)
+}
+
+packet SniffSubratingComplete : CommandComplete (command_op_code = SNIFF_SUBRATING) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+ // CONTROLLER_AND_BASEBAND
+packet SetEventMask : CommandPacket (op_code = SET_EVENT_MASK) {
+ event_mask : 64,
+}
+
+packet SetEventMaskComplete : CommandComplete (command_op_code = SET_EVENT_MASK) {
+ status : ErrorCode,
+}
+
+packet Reset : CommandPacket (op_code = RESET) {
+}
+
+packet ResetComplete : CommandComplete (command_op_code = RESET) {
+ status : ErrorCode,
+}
+
+enum FilterType : 8 {
+ CLEAR_ALL_FILTERS = 0x00,
+ INQUIRY_RESULT = 0x01,
+ CONNECTION_SETUP = 0x02,
+}
+
+packet SetEventFilter : CommandPacket (op_code = SET_EVENT_FILTER) {
+ filter_type : FilterType,
+ _body_,
+}
+
+packet SetEventFilterComplete : CommandComplete (command_op_code = SET_EVENT_FILTER) {
+ status : ErrorCode,
+}
+
+packet SetEventFilterClearAll : SetEventFilter (filter_type = CLEAR_ALL_FILTERS) {
+}
+
+enum FilterConditionType : 8 {
+ ALL_DEVICES = 0x00,
+ CLASS_OF_DEVICE = 0x01,
+ ADDRESS = 0x02,
+}
+
+packet SetEventFilterInquiryResult : SetEventFilter (filter_type = INQUIRY_RESULT) {
+ filter_condition_type : FilterConditionType,
+ _body_,
+}
+
+packet SetEventFilterInquiryResultAllDevices : SetEventFilterInquiryResult (filter_condition_type = ALL_DEVICES) {
+}
+
+packet SetEventFilterInquiryResultClassOfDevice : SetEventFilterInquiryResult (filter_condition_type = CLASS_OF_DEVICE) {
+ class_of_device : ClassOfDevice,
+ class_of_device_mask : ClassOfDevice,
+}
+
+packet SetEventFilterInquiryResultAddress : SetEventFilterInquiryResult (filter_condition_type = ADDRESS) {
+ address : Address,
+}
+
+packet SetEventFilterConnectionSetup : SetEventFilter (filter_type = CONNECTION_SETUP) {
+ filter_condition_type : FilterConditionType,
+ _body_,
+}
+
+enum AutoAcceptFlag : 8 {
+ AUTO_ACCEPT_OFF = 0x01,
+ AUTO_ACCEPT_ON_ROLE_SWITCH_DISABLED = 0x02,
+ AUTO_ACCEPT_ON_ROLE_SWITCH_ENABLED = 0x03,
+}
+
+packet SetEventFilterConnectionSetupAllDevices : SetEventFilterConnectionSetup (filter_condition_type = ALL_DEVICES) {
+ auto_accept_flag : AutoAcceptFlag,
+}
+
+packet SetEventFilterConnectionSetupClassOfDevice : SetEventFilterConnectionSetup (filter_condition_type = CLASS_OF_DEVICE) {
+ class_of_device : ClassOfDevice,
+ class_of_device_mask : ClassOfDevice,
+ auto_accept_flag : AutoAcceptFlag,
+}
+
+packet SetEventFilterConnectionSetupAddress : SetEventFilterConnectionSetup (filter_condition_type = ADDRESS) {
+ address : Address,
+ auto_accept_flag : AutoAcceptFlag,
+}
+
+packet Flush : ConnectionManagementCommand (op_code = FLUSH) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet FlushComplete : CommandComplete (command_op_code = FLUSH) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadPinType : CommandPacket (op_code = READ_PIN_TYPE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet WritePinType : CommandPacket (op_code = WRITE_PIN_TYPE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet CreateNewUnitKey : CommandPacket (op_code = CREATE_NEW_UNIT_KEY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+enum ReadStoredLinkKeyReadAllFlag : 8 {
+ SPECIFIED_BD_ADDR = 0x00,
+ ALL = 0x01,
+}
+
+packet ReadStoredLinkKey : SecurityCommand (op_code = READ_STORED_LINK_KEY) {
+ bd_addr : Address,
+ read_all_flag : ReadStoredLinkKeyReadAllFlag,
+}
+
+packet ReadStoredLinkKeyComplete : CommandComplete (command_op_code = READ_STORED_LINK_KEY) {
+ status : ErrorCode,
+ max_num_keys : 16,
+ num_keys_read : 16,
+}
+
+struct KeyAndAddress {
+ address : Address,
+ link_key : 8[16],
+}
+
+packet WriteStoredLinkKey : SecurityCommand (op_code = WRITE_STORED_LINK_KEY) {
+ _count_(keys_to_write) : 8, // 0x01-0x0B
+ keys_to_write : KeyAndAddress[],
+}
+
+packet WriteStoredLinkKeyComplete : CommandComplete (command_op_code = WRITE_STORED_LINK_KEY) {
+ status : ErrorCode,
+ num_keys_written : 8,
+}
+
+enum DeleteStoredLinkKeyDeleteAllFlag : 8 {
+ SPECIFIED_BD_ADDR = 0x00,
+ ALL = 0x01,
+}
+
+packet DeleteStoredLinkKey : SecurityCommand (op_code = DELETE_STORED_LINK_KEY) {
+ bd_addr : Address,
+ delete_all_flag : DeleteStoredLinkKeyDeleteAllFlag,
+}
+
+packet DeleteStoredLinkKeyComplete : CommandComplete (command_op_code = DELETE_STORED_LINK_KEY) {
+ status : ErrorCode,
+ num_keys_deleted : 16,
+}
+
+packet WriteLocalName : CommandPacket (op_code = WRITE_LOCAL_NAME) {
+ local_name : 8[248], // Null-terminated UTF-8 encoded name
+}
+
+packet WriteLocalNameComplete : CommandComplete (command_op_code = WRITE_LOCAL_NAME) {
+ status : ErrorCode,
+}
+
+packet ReadLocalName : CommandPacket (op_code = READ_LOCAL_NAME) {
+}
+
+packet ReadLocalNameComplete : CommandComplete (command_op_code = READ_LOCAL_NAME) {
+ status : ErrorCode,
+ local_name : 8[248], // Null-terminated UTF-8 encoded name
+}
+
+packet ReadConnectionAcceptTimeout : ConnectionManagementCommand (op_code = READ_CONNECTION_ACCEPT_TIMEOUT) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet WriteConnectionAcceptTimeout : ConnectionManagementCommand (op_code = WRITE_CONNECTION_ACCEPT_TIMEOUT) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet ReadPageTimeout : DiscoveryCommand (op_code = READ_PAGE_TIMEOUT) {
+}
+
+packet ReadPageTimeoutComplete : CommandComplete (command_op_code = READ_PAGE_TIMEOUT) {
+ status : ErrorCode,
+ page_timeout : 16,
+}
+
+packet WritePageTimeout : DiscoveryCommand (op_code = WRITE_PAGE_TIMEOUT) {
+ page_timeout : 16,
+}
+
+packet WritePageTimeoutComplete : CommandComplete (command_op_code = WRITE_PAGE_TIMEOUT) {
+ status : ErrorCode,
+}
+
+enum ScanEnable : 8 {
+ NO_SCANS = 0x00,
+ INQUIRY_SCAN_ONLY = 0x01,
+ PAGE_SCAN_ONLY = 0x02,
+ INQUIRY_AND_PAGE_SCAN = 0x03,
+}
+
+packet ReadScanEnable : DiscoveryCommand (op_code = READ_SCAN_ENABLE) {
+}
+
+packet ReadScanEnableComplete : CommandComplete (command_op_code = READ_SCAN_ENABLE) {
+ status : ErrorCode,
+ scan_enable : ScanEnable,
+}
+
+packet WriteScanEnable : DiscoveryCommand (op_code = WRITE_SCAN_ENABLE) {
+ scan_enable : ScanEnable,
+}
+
+packet WriteScanEnableComplete : CommandComplete (command_op_code = WRITE_SCAN_ENABLE) {
+ status : ErrorCode,
+}
+
+packet ReadPageScanActivity : DiscoveryCommand (op_code = READ_PAGE_SCAN_ACTIVITY) {
+}
+
+packet ReadPageScanActivityComplete : CommandComplete (command_op_code = READ_PAGE_SCAN_ACTIVITY) {
+ status : ErrorCode,
+ page_scan_interval : 16, // Range: 0x0012 to 0x1000; only even values are valid * 0x625 ms
+ page_scan_window : 16, // 0x0011 to PageScanInterval
+}
+
+packet WritePageScanActivity : DiscoveryCommand (op_code = WRITE_PAGE_SCAN_ACTIVITY) {
+ page_scan_interval : 16, // Range: 0x0012 to 0x1000; only even values are valid * 0x625 ms
+ page_scan_window : 16, // 0x0011 to PageScanInterval
+}
+
+packet WritePageScanActivityComplete : CommandComplete (command_op_code = WRITE_PAGE_SCAN_ACTIVITY) {
+ status : ErrorCode,
+}
+
+packet ReadInquiryScanActivity : DiscoveryCommand (op_code = READ_INQUIRY_SCAN_ACTIVITY) {
+}
+
+packet ReadInquiryScanActivityComplete : CommandComplete (command_op_code = READ_INQUIRY_SCAN_ACTIVITY) {
+ status : ErrorCode,
+ inquiry_scan_interval : 16, // Range: 0x0012 to 0x1000; only even values are valid * 0x625 ms
+ inquiry_scan_window : 16, // Range: 0x0011 to 0x1000
+}
+
+packet WriteInquiryScanActivity : DiscoveryCommand (op_code = WRITE_INQUIRY_SCAN_ACTIVITY) {
+ inquiry_scan_interval : 16, // Range: 0x0012 to 0x1000; only even values are valid * 0x625 ms
+ inquiry_scan_window : 16, // Range: 0x0011 to 0x1000
+}
+
+packet WriteInquiryScanActivityComplete : CommandComplete (command_op_code = WRITE_INQUIRY_SCAN_ACTIVITY) {
+ status : ErrorCode,
+}
+
+enum AuthenticationEnable : 8 {
+ NOT_REQUIRED = 0x00,
+ REQUIRED = 0x01,
+}
+
+packet ReadAuthenticationEnable : CommandPacket (op_code = READ_AUTHENTICATION_ENABLE) {
+}
+
+packet ReadAuthenticationEnableComplete : CommandComplete (command_op_code = READ_AUTHENTICATION_ENABLE) {
+ status : ErrorCode,
+ authentication_enable : AuthenticationEnable,
+}
+
+packet WriteAuthenticationEnable : SecurityCommand (op_code = WRITE_AUTHENTICATION_ENABLE) {
+ authentication_enable : AuthenticationEnable,
+}
+
+packet WriteAuthenticationEnableComplete : CommandComplete (command_op_code = WRITE_AUTHENTICATION_ENABLE) {
+ status : ErrorCode,
+}
+
+packet ReadClassOfDevice : DiscoveryCommand (op_code = READ_CLASS_OF_DEVICE) {
+}
+
+packet ReadClassOfDeviceComplete : CommandComplete (command_op_code = READ_CLASS_OF_DEVICE) {
+ status : ErrorCode,
+ class_of_device : ClassOfDevice,
+}
+
+packet WriteClassOfDevice : DiscoveryCommand (op_code = WRITE_CLASS_OF_DEVICE) {
+ class_of_device : ClassOfDevice,
+}
+
+packet WriteClassOfDeviceComplete : CommandComplete (command_op_code = WRITE_CLASS_OF_DEVICE) {
+ status : ErrorCode,
+}
+
+packet ReadVoiceSetting : CommandPacket (op_code = READ_VOICE_SETTING) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet WriteVoiceSetting : CommandPacket (op_code = WRITE_VOICE_SETTING) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet WriteVoiceSettingComplete : CommandComplete (command_op_code = WRITE_VOICE_SETTING) {
+ status : ErrorCode,
+}
+
+packet ReadAutomaticFlushTimeout : ConnectionManagementCommand (op_code = READ_AUTOMATIC_FLUSH_TIMEOUT) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadAutomaticFlushTimeoutComplete : CommandComplete (command_op_code = READ_AUTOMATIC_FLUSH_TIMEOUT) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ flush_timeout : 16,
+}
+
+packet WriteAutomaticFlushTimeout : ConnectionManagementCommand (op_code = WRITE_AUTOMATIC_FLUSH_TIMEOUT) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ flush_timeout : 16, // 0x0000-0x07FF Default 0x0000 (No Automatic Flush)
+}
+
+packet WriteAutomaticFlushTimeoutComplete : CommandComplete (command_op_code = WRITE_AUTOMATIC_FLUSH_TIMEOUT) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadNumBroadcastRetransmits : CommandPacket (op_code = READ_NUM_BROADCAST_RETRANSMITS) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet WriteNumBroadcastRetransmits : CommandPacket (op_code = WRITE_NUM_BROADCAST_RETRANSMITS) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet ReadHoldModeActivity : CommandPacket (op_code = READ_HOLD_MODE_ACTIVITY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet WriteHoldModeActivity : CommandPacket (op_code = WRITE_HOLD_MODE_ACTIVITY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+
+enum TransmitPowerLevelType : 8 {
+ CURRENT = 0x00,
+ MAXIMUM = 0x01,
+}
+
+packet ReadTransmitPowerLevel : ConnectionManagementCommand (op_code = READ_TRANSMIT_POWER_LEVEL) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ type : TransmitPowerLevelType,
+
+}
+
+packet ReadTransmitPowerLevelComplete : CommandComplete (command_op_code = READ_TRANSMIT_POWER_LEVEL) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ transmit_power_level : 8,
+}
+
+packet ReadSynchronousFlowControlEnable : CommandPacket (op_code = READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet WriteSynchronousFlowControlEnable : CommandPacket (op_code = WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet SetControllerToHostFlowControl : CommandPacket (op_code = SET_CONTROLLER_TO_HOST_FLOW_CONTROL) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet HostBufferSize : CommandPacket (op_code = HOST_BUFFER_SIZE) {
+ host_acl_data_packet_length : 16,
+ host_synchronous_data_packet_length : 8,
+ host_total_num_acl_data_packets : 16,
+ host_total_num_synchronous_data_packets : 16,
+}
+
+packet HostBufferSizeComplete : CommandComplete (command_op_code = HOST_BUFFER_SIZE) {
+ status : ErrorCode,
+}
+
+struct CompletedPackets {
+ connection_handle : 12,
+ _reserved_ : 4,
+ host_num_of_completed_packets : 16,
+}
+
+packet HostNumCompletedPackets : CommandPacket (op_code = HOST_NUM_COMPLETED_PACKETS) {
+ _count_(completed_packets) : 8,
+ completed_packets : CompletedPackets[],
+}
+
+packet HostNumCompletedPacketsError : CommandComplete (command_op_code = HOST_NUM_COMPLETED_PACKETS) {
+ error_code : ErrorCode,
+}
+
+packet ReadLinkSupervisionTimeout : ConnectionManagementCommand (op_code = READ_LINK_SUPERVISION_TIMEOUT) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadLinkSupervisionTimeoutComplete : CommandComplete (command_op_code = READ_LINK_SUPERVISION_TIMEOUT) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ link_supervision_timeout : 16, // 0x001-0xFFFF (0.625ms-40.9s)
+}
+
+packet WriteLinkSupervisionTimeout : ConnectionManagementCommand (op_code = WRITE_LINK_SUPERVISION_TIMEOUT) {
+ handle : 12,
+ _reserved_ : 4,
+ link_supervision_timeout : 16, // 0x001-0xFFFF (0.625ms-40.9s)
+}
+
+packet WriteLinkSupervisionTimeoutComplete : CommandComplete (command_op_code = WRITE_LINK_SUPERVISION_TIMEOUT) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadNumberOfSupportedIac : DiscoveryCommand (op_code = READ_NUMBER_OF_SUPPORTED_IAC) {
+}
+
+packet ReadNumberOfSupportedIacComplete : CommandComplete (command_op_code = READ_NUMBER_OF_SUPPORTED_IAC) {
+ status : ErrorCode,
+ num_support_iac : 8,
+}
+
+packet ReadCurrentIacLap : DiscoveryCommand (op_code = READ_CURRENT_IAC_LAP) {
+}
+
+packet ReadCurrentIacLapComplete : CommandComplete (command_op_code = READ_CURRENT_IAC_LAP) {
+ status : ErrorCode,
+ _count_(laps_to_read) : 8,
+ laps_to_read : Lap[],
+}
+
+packet WriteCurrentIacLap : DiscoveryCommand (op_code = WRITE_CURRENT_IAC_LAP) {
+ _count_(laps_to_write) : 8,
+ laps_to_write : Lap[],
+}
+
+packet WriteCurrentIacLapComplete : CommandComplete (command_op_code = WRITE_CURRENT_IAC_LAP) {
+ status : ErrorCode,
+}
+
+packet SetAfhHostChannelClassification : CommandPacket (op_code = SET_AFH_HOST_CHANNEL_CLASSIFICATION) {
+ _payload_, // placeholder (unimplemented)
+}
+
+enum InquiryScanType : 8 {
+ STANDARD = 0x00,
+ INTERLACED = 0x01,
+}
+
+packet ReadInquiryScanType : DiscoveryCommand (op_code = READ_INQUIRY_SCAN_TYPE) {
+}
+
+packet ReadInquiryScanTypeComplete : CommandComplete (command_op_code = READ_INQUIRY_SCAN_TYPE) {
+ status : ErrorCode,
+ inquiry_scan_type : InquiryScanType,
+}
+
+packet WriteInquiryScanType : DiscoveryCommand (op_code = WRITE_INQUIRY_SCAN_TYPE) {
+ inquiry_scan_type : InquiryScanType,
+}
+
+packet WriteInquiryScanTypeComplete : CommandComplete (command_op_code = WRITE_INQUIRY_SCAN_TYPE) {
+ status : ErrorCode,
+}
+
+enum InquiryMode : 8 {
+ STANDARD = 0x00,
+ RSSI = 0x01,
+ RSSI_OR_EXTENDED = 0x02,
+}
+
+packet ReadInquiryMode : DiscoveryCommand (op_code = READ_INQUIRY_MODE) {
+}
+
+packet ReadInquiryModeComplete : CommandComplete (command_op_code = READ_INQUIRY_MODE) {
+ status : ErrorCode,
+ inquiry_mode : InquiryMode,
+}
+
+packet WriteInquiryMode : DiscoveryCommand (op_code = WRITE_INQUIRY_MODE) {
+ inquiry_mode : InquiryMode,
+}
+
+packet WriteInquiryModeComplete : CommandComplete (command_op_code = WRITE_INQUIRY_MODE) {
+ status : ErrorCode,
+}
+
+enum PageScanType : 8 {
+ STANDARD = 0x00,
+ INTERLACED = 0x01,
+}
+
+packet ReadPageScanType : DiscoveryCommand (op_code = READ_PAGE_SCAN_TYPE) {
+}
+
+packet ReadPageScanTypeComplete : CommandComplete (command_op_code = READ_PAGE_SCAN_TYPE) {
+ status : ErrorCode,
+ page_scan_type : PageScanType,
+}
+
+packet WritePageScanType : DiscoveryCommand (op_code = WRITE_PAGE_SCAN_TYPE) {
+ page_scan_type : PageScanType,
+}
+
+packet WritePageScanTypeComplete : CommandComplete (command_op_code = WRITE_PAGE_SCAN_TYPE) {
+ status : ErrorCode,
+}
+
+packet ReadAfhChannelAssessmentMode : CommandPacket (op_code = READ_AFH_CHANNEL_ASSESSMENT_MODE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet WriteAfhChannelAssessmentMode : CommandPacket (op_code = WRITE_AFH_CHANNEL_ASSESSMENT_MODE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+enum FecRequired : 8 {
+ NOT_REQUIRED = 0x00,
+ REQUIRED = 0x01,
+}
+
+packet ReadExtendedInquiryResponse : CommandPacket (op_code = READ_EXTENDED_INQUIRY_RESPONSE) {
+}
+
+packet ReadExtendedInquiryResponseComplete : CommandComplete (command_op_code = READ_EXTENDED_INQUIRY_RESPONSE) {
+ status : ErrorCode,
+ fec_required : FecRequired,
+ extended_inquiry_response : GapData[],
+}
+
+packet WriteExtendedInquiryResponse : CommandPacket (op_code = WRITE_EXTENDED_INQUIRY_RESPONSE) {
+ fec_required : FecRequired,
+ extended_inquiry_response : GapData[],
+ _padding_[244], // Zero padding to be 240 octets (GapData[]) + 2 (opcode) + 1 (size) + 1 (FecRequired)
+}
+
+packet WriteExtendedInquiryResponseComplete : CommandComplete (command_op_code = WRITE_EXTENDED_INQUIRY_RESPONSE) {
+ status : ErrorCode,
+}
+
+packet RefreshEncryptionKey : SecurityCommand (op_code = REFRESH_ENCRYPTION_KEY) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet RefreshEncryptionKeyStatus : CommandStatus (command_op_code = REFRESH_ENCRYPTION_KEY) {
+}
+
+packet ReadSimplePairingMode : SecurityCommand (op_code = READ_SIMPLE_PAIRING_MODE) {
+}
+
+packet ReadSimplePairingModeComplete : CommandComplete (command_op_code = READ_SIMPLE_PAIRING_MODE) {
+ status : ErrorCode,
+ simple_pairing_mode : Enable,
+}
+
+packet WriteSimplePairingMode : SecurityCommand (op_code = WRITE_SIMPLE_PAIRING_MODE) {
+ simple_pairing_mode : Enable,
+}
+
+packet WriteSimplePairingModeComplete : CommandComplete (command_op_code = WRITE_SIMPLE_PAIRING_MODE) {
+ status : ErrorCode,
+}
+
+packet ReadLocalOobData : SecurityCommand (op_code = READ_LOCAL_OOB_DATA) {
+}
+
+packet ReadLocalOobDataComplete : CommandComplete (command_op_code = READ_LOCAL_OOB_DATA) {
+ status : ErrorCode,
+ c : 8[16],
+ r : 8[16],
+}
+
+packet ReadInquiryResponseTransmitPowerLevel : DiscoveryCommand (op_code = READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL) {
+}
+
+packet ReadInquiryResponseTransmitPowerLevelComplete : CommandComplete (command_op_code = READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL) {
+ status : ErrorCode,
+ tx_power : 8, // (-70dBm to 20dBm)
+}
+
+packet WriteInquiryTransmitPowerLevel : DiscoveryCommand (op_code = WRITE_INQUIRY_TRANSMIT_POWER_LEVEL) {
+ tx_power : 8,
+}
+
+packet WriteInquiryResponseTransmitPowerLevelComplete : CommandComplete (command_op_code = WRITE_INQUIRY_TRANSMIT_POWER_LEVEL) {
+ status : ErrorCode,
+}
+
+enum KeypressNotificationType : 8 {
+ ENTRY_STARTED = 0,
+ DIGIT_ENTERED = 1,
+ DIGIT_ERASED = 2,
+ CLEARED = 3,
+ ENTRY_COMPLETED = 4,
+}
+
+packet SendKeypressNotification : SecurityCommand (op_code = SEND_KEYPRESS_NOTIFICATION) {
+ bd_addr : Address,
+ notification_type : KeypressNotificationType,
+}
+
+packet SendKeypressNotificationComplete : CommandComplete (command_op_code = SEND_KEYPRESS_NOTIFICATION) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+enum SimultaneousLeHost : 8 {
+ DISABLED = 0x00,
+}
+
+packet ReadLeHostSupport : CommandPacket (op_code = READ_LE_HOST_SUPPORT) {
+}
+
+packet ReadLeHostSupportComplete : CommandComplete (command_op_code = READ_LE_HOST_SUPPORT) {
+ status : ErrorCode,
+ le_supported_host : Enable,
+ simultaneous_le_host : SimultaneousLeHost,
+}
+
+packet WriteLeHostSupport : CommandPacket (op_code = WRITE_LE_HOST_SUPPORT) {
+ le_supported_host : Enable,
+ simultaneous_le_host : SimultaneousLeHost,
+}
+
+packet WriteLeHostSupportComplete : CommandComplete (command_op_code = WRITE_LE_HOST_SUPPORT) {
+ status : ErrorCode,
+}
+
+packet ReadSecureConnectionsHostSupport : CommandPacket (op_code = READ_SECURE_CONNECTIONS_HOST_SUPPORT) {
+}
+
+packet ReadSecureConnectionsHostSupportComplete : CommandComplete (command_op_code = READ_SECURE_CONNECTIONS_HOST_SUPPORT) {
+ status : ErrorCode,
+ secure_connections_host_support : Enable,
+}
+
+packet WriteSecureConnectionsHostSupport : SecurityCommand (op_code = WRITE_SECURE_CONNECTIONS_HOST_SUPPORT) {
+ secure_connections_host_support : Enable,
+}
+
+packet WriteSecureConnectionsHostSupportComplete : CommandComplete (command_op_code = WRITE_SECURE_CONNECTIONS_HOST_SUPPORT) {
+ status : ErrorCode,
+}
+
+packet ReadLocalOobExtendedData : SecurityCommand (op_code = READ_LOCAL_OOB_EXTENDED_DATA) {
+}
+
+packet ReadLocalOobExtendedDataComplete : CommandComplete (command_op_code = READ_LOCAL_OOB_EXTENDED_DATA) {
+ status : ErrorCode,
+ c_192 : 8[16],
+ r_192 : 8[16],
+ c_256 : 8[16],
+ r_256 : 8[16],
+}
+
+
+ // INFORMATIONAL_PARAMETERS
+packet ReadLocalVersionInformation : CommandPacket (op_code = READ_LOCAL_VERSION_INFORMATION) {
+}
+
+enum HciVersion : 8 {
+ V_1_0B = 0x00,
+ V_1_1 = 0x01,
+ V_1_2 = 0x02,
+ V_2_0 = 0x03, // + EDR
+ V_2_1 = 0x04, // + EDR
+ V_3_0 = 0x05, // + HS
+ V_4_0 = 0x06,
+ V_4_1 = 0x07,
+ V_4_2 = 0x08,
+ V_5_0 = 0x09,
+ V_5_1 = 0x0a,
+}
+
+enum LmpVersion : 8 {
+ V_1_0B = 0x00, // withdrawn
+ V_1_1 = 0x01, // withdrawn
+ V_1_2 = 0x02, // withdrawn
+ V_2_0 = 0x03, // + EDR
+ V_2_1 = 0x04, // + EDR
+ V_3_0 = 0x05, // + HS
+ V_4_0 = 0x06,
+ V_4_1 = 0x07,
+ V_4_2 = 0x08,
+ V_5_0 = 0x09,
+ V_5_1 = 0x0a,
+}
+
+struct LocalVersionInformation {
+ hci_version : HciVersion,
+ hci_revision : 16,
+ lmp_version : LmpVersion,
+ manufacturer_name : 16,
+ lmp_subversion : 16,
+}
+
+packet ReadLocalVersionInformationComplete : CommandComplete (command_op_code = READ_LOCAL_VERSION_INFORMATION) {
+ status : ErrorCode,
+ local_version_information : LocalVersionInformation,
+}
+
+packet ReadLocalSupportedCommands : CommandPacket (op_code = READ_LOCAL_SUPPORTED_COMMANDS) {
+}
+
+packet ReadLocalSupportedCommandsComplete : CommandComplete (command_op_code = READ_LOCAL_SUPPORTED_COMMANDS) {
+ status : ErrorCode,
+ supported_commands : 8[64],
+}
+
+packet ReadLocalSupportedFeatures : CommandPacket (op_code = READ_LOCAL_SUPPORTED_FEATURES) {
+}
+
+packet ReadLocalSupportedFeaturesComplete : CommandComplete (command_op_code = READ_LOCAL_SUPPORTED_FEATURES) {
+ status : ErrorCode,
+ lmp_features : 64,
+}
+
+packet ReadLocalExtendedFeatures : CommandPacket (op_code = READ_LOCAL_EXTENDED_FEATURES) {
+ page_number : 8,
+}
+
+packet ReadLocalExtendedFeaturesComplete : CommandComplete (command_op_code = READ_LOCAL_EXTENDED_FEATURES) {
+ status : ErrorCode,
+ page_number : 8,
+ maximum_page_number : 8,
+ extended_lmp_features : 64,
+}
+
+packet ReadBufferSize : CommandPacket (op_code = READ_BUFFER_SIZE) {
+}
+
+packet ReadBufferSizeComplete : CommandComplete (command_op_code = READ_BUFFER_SIZE) {
+ status : ErrorCode,
+ acl_data_packet_length : 16,
+ synchronous_data_packet_length : 8,
+ total_num_acl_data_packets : 16,
+ total_num_synchronous_data_packets : 16,
+}
+
+packet ReadBdAddr : CommandPacket (op_code = READ_BD_ADDR) {
+}
+
+packet ReadBdAddrComplete : CommandComplete (command_op_code = READ_BD_ADDR) {
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet ReadDataBlockSize : CommandPacket (op_code = READ_DATA_BLOCK_SIZE) {
+}
+
+packet ReadLocalSupportedCodecs : CommandPacket (op_code = READ_LOCAL_SUPPORTED_CODECS) {
+}
+
+packet ReadLocalSupportedCodecsComplete : CommandComplete (command_op_code = READ_LOCAL_SUPPORTED_CODECS) {
+ status : ErrorCode,
+ _size_(supported_codecs) : 8,
+ supported_codecs : 8[],
+ _size_(vendor_specific_codecs) : 8,
+ vendor_specific_codecs : 32[],
+}
+
+ // STATUS_PARAMETERS
+packet ReadFailedContactCounter : ConnectionManagementCommand (op_code = READ_FAILED_CONTACT_COUNTER) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadFailedContactCounterComplete : CommandComplete (command_op_code = READ_FAILED_CONTACT_COUNTER) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ failed_contact_counter : 16,
+}
+
+packet ResetFailedContactCounter : ConnectionManagementCommand (op_code = RESET_FAILED_CONTACT_COUNTER) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ResetFailedContactCounterComplete : CommandComplete (command_op_code = RESET_FAILED_CONTACT_COUNTER) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadLinkQuality : ConnectionManagementCommand (op_code = READ_LINK_QUALITY) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadLinkQualityComplete : CommandComplete (command_op_code = READ_LINK_QUALITY) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ link_quality : 8,
+}
+
+packet ReadRssi : ConnectionManagementCommand (op_code = READ_RSSI) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadRssiComplete : CommandComplete (command_op_code = READ_RSSI) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ rssi : 8,
+}
+
+packet ReadAfhChannelMap : ConnectionManagementCommand (op_code = READ_AFH_CHANNEL_MAP) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+enum AfhMode : 8 {
+ AFH_DISABLED = 0x00,
+ AFH_ENABLED = 0x01,
+}
+
+packet ReadAfhChannelMapComplete : CommandComplete (command_op_code = READ_AFH_CHANNEL_MAP) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ afh_mode : AfhMode,
+ afh_channel_map : 8[10],
+}
+
+
+enum WhichClock : 8 {
+ LOCAL = 0x00,
+ PICONET = 0x01,
+}
+
+packet ReadClock : ConnectionManagementCommand (op_code = READ_CLOCK) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ which_clock : WhichClock,
+}
+
+packet ReadClockComplete : CommandComplete (command_op_code = READ_CLOCK) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ clock : 28,
+ _reserved_ : 4,
+ accuracy : 16,
+}
+
+packet ReadEncryptionKeySize : SecurityCommand (op_code = READ_ENCRYPTION_KEY_SIZE) {
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet ReadEncryptionKeySizeComplete : CommandComplete (command_op_code = READ_ENCRYPTION_KEY_SIZE) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ key_size : 8,
+}
+
+ // TESTING
+enum LoopbackMode : 8 {
+ NO_LOOPBACK = 0x00,
+ ENABLE_LOCAL = 0x01,
+ ENABLE_REMOTE = 0x02,
+}
+
+packet ReadLoopbackMode : CommandPacket (op_code = READ_LOOPBACK_MODE) {
+}
+
+packet ReadLoopbackModeComplete : CommandComplete (command_op_code = READ_LOOPBACK_MODE) {
+ status : ErrorCode,
+ loopback_mode : LoopbackMode,
+}
+
+packet WriteLoopbackMode : CommandPacket (op_code = WRITE_LOOPBACK_MODE) {
+ loopback_mode : LoopbackMode,
+}
+
+packet WriteLoopbackModeComplete : CommandComplete (command_op_code = WRITE_LOOPBACK_MODE) {
+ status : ErrorCode,
+}
+
+packet EnableDeviceUnderTestMode : CommandPacket (op_code = ENABLE_DEVICE_UNDER_TEST_MODE) {
+}
+
+packet EnableDeviceUnderTestModeComplete : CommandComplete (command_op_code = ENABLE_DEVICE_UNDER_TEST_MODE) {
+ status : ErrorCode,
+}
+
+packet WriteSimplePairingDebugMode : CommandPacket (op_code = WRITE_SIMPLE_PAIRING_DEBUG_MODE) {
+ simple_pairing_debug_mode : Enable,
+}
+
+packet WriteSimplePairingDebugModeComplete : CommandComplete (command_op_code = WRITE_SIMPLE_PAIRING_DEBUG_MODE) {
+ status : ErrorCode,
+}
+
+packet WriteSecureConnectionsTestMode : CommandPacket (op_code = WRITE_SECURE_CONNECTIONS_TEST_MODE) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ dm1_aclu_mode : Enable,
+ esco_loopback_mode : Enable,
+}
+
+packet WriteSecureConnectionsTestModeComplete : CommandComplete (command_op_code = WRITE_SECURE_CONNECTIONS_TEST_MODE) {
+ status : ErrorCode,
+}
+
+ // LE_CONTROLLER
+packet LeSetEventMask : CommandPacket (op_code = LE_SET_EVENT_MASK) {
+ le_event_mask : 64,
+}
+
+packet LeSetEventMaskComplete : CommandComplete (command_op_code = LE_SET_EVENT_MASK) {
+ status : ErrorCode,
+}
+
+packet LeReadBufferSize : CommandPacket (op_code = LE_READ_BUFFER_SIZE) {
+}
+
+struct LeBufferSize {
+ le_data_packet_length : 16,
+ total_num_le_packets : 8,
+}
+
+packet LeReadBufferSizeComplete : CommandComplete (command_op_code = LE_READ_BUFFER_SIZE) {
+ status : ErrorCode,
+ le_buffer_size : LeBufferSize,
+}
+
+packet LeReadLocalSupportedFeatures : CommandPacket (op_code = LE_READ_LOCAL_SUPPORTED_FEATURES) {
+}
+
+packet LeReadLocalSupportedFeaturesComplete : CommandComplete (command_op_code = LE_READ_LOCAL_SUPPORTED_FEATURES) {
+ status : ErrorCode,
+ le_features : 64,
+}
+
+packet LeSetRandomAddress : LeAdvertisingCommand (op_code = LE_SET_RANDOM_ADDRESS) {
+ random_address : Address,
+}
+
+packet LeSetRandomAddressComplete : CommandComplete (command_op_code = LE_SET_RANDOM_ADDRESS) {
+ status : ErrorCode,
+}
+
+enum AdvertisingFilterPolicy : 2 {
+ ALL_DEVICES = 0, // Default
+ WHITELISTED_SCAN = 1,
+ WHITELISTED_CONNECT = 2,
+ WHITELISTED_SCAN_AND_CONNECT = 3,
+}
+
+enum PeerAddressType : 8 {
+ PUBLIC_DEVICE_OR_IDENTITY_ADDRESS = 0x00,
+ RANDOM_DEVICE_OR_IDENTITY_ADDRESS = 0x01,
+}
+
+enum AdvertisingEventType : 8 {
+ ADV_IND = 0x00,
+ ADV_DIRECT_IND = 0x01,
+ ADV_SCAN_IND = 0x02,
+ ADV_NONCONN_IND = 0x03,
+ ADV_DIRECT_IND_LOW = 0x04,
+}
+
+enum AddressType : 8 {
+ PUBLIC_DEVICE_ADDRESS = 0x00,
+ RANDOM_DEVICE_ADDRESS = 0x01,
+ PUBLIC_IDENTITY_ADDRESS = 0x02,
+ RANDOM_IDENTITY_ADDRESS = 0x03,
+}
+
+packet LeSetAdvertisingParameters : LeAdvertisingCommand (op_code = LE_SET_ADVERTISING_PARAMETERS) {
+ interval_min : 16,
+ interval_max : 16,
+ type : AdvertisingEventType,
+ own_address_type : AddressType,
+ peer_address_type : PeerAddressType,
+ peer_address : Address,
+ channel_map : 8,
+ filter_policy : AdvertisingFilterPolicy,
+ _reserved_ : 6,
+}
+
+packet LeSetAdvertisingParametersComplete : CommandComplete (command_op_code = LE_SET_ADVERTISING_PARAMETERS) {
+ status : ErrorCode,
+}
+
+packet LeReadAdvertisingChannelTxPower : LeAdvertisingCommand (op_code = LE_READ_ADVERTISING_CHANNEL_TX_POWER) {
+}
+
+packet LeReadAdvertisingChannelTxPowerComplete : CommandComplete (command_op_code = LE_READ_ADVERTISING_CHANNEL_TX_POWER) {
+ status : ErrorCode,
+ transmit_power_level : 8, // (-20dBm to 10dBm) Accuracy: +/-4dB
+}
+
+packet LeSetAdvertisingData : LeAdvertisingCommand (op_code = LE_SET_ADVERTISING_DATA) {
+ _size_(advertising_data) : 8,
+ advertising_data : GapData[],
+ _padding_[31], // Zero padding to 31 bytes of advertising_data
+}
+
+packet LeSetAdvertisingDataComplete : CommandComplete (command_op_code = LE_SET_ADVERTISING_DATA) {
+ status : ErrorCode,
+}
+
+packet LeSetScanResponseData : LeAdvertisingCommand (op_code = LE_SET_SCAN_RESPONSE_DATA) {
+ _size_(advertising_data) : 8,
+ advertising_data : GapData[],
+ _padding_[31], // Zero padding to 31 bytes of advertising_data
+}
+
+packet LeSetScanResponseDataComplete : CommandComplete (command_op_code = LE_SET_SCAN_RESPONSE_DATA) {
+ status : ErrorCode,
+}
+
+packet LeSetAdvertisingEnable : LeAdvertisingCommand (op_code = LE_SET_ADVERTISING_ENABLE) {
+ advertising_enable : Enable, // Default DISABLED
+}
+
+packet LeSetAdvertisingEnableComplete : CommandComplete (command_op_code = LE_SET_ADVERTISING_ENABLE) {
+ status : ErrorCode,
+}
+
+enum LeScanType : 8 {
+ PASSIVE = 0x00, // Default
+ ACTIVE = 0x01,
+}
+
+enum LeSetScanningFilterPolicy : 8 {
+ ACCEPT_ALL = 0x00, // Default
+ WHITE_LIST_ONLY = 0x01,
+ CHECK_INITIATORS_IDENTITY = 0x02,
+ WHITE_LIST_AND_INITIATORS_IDENTITY = 0x03,
+}
+
+packet LeSetScanParameters : LeScanningCommand (op_code = LE_SET_SCAN_PARAMETERS) {
+ le_scan_type : LeScanType,
+ le_scan_interval : 16, // 0x0004-0x4000 Default 0x10 (10ms)
+ le_scan_window : 16, // Default 0x10 (10ms)
+ own_address_type : AddressType,
+ scanning_filter_policy : LeSetScanningFilterPolicy,
+}
+
+packet LeSetScanParametersComplete : CommandComplete (command_op_code = LE_SET_SCAN_PARAMETERS) {
+ status : ErrorCode,
+}
+
+packet LeSetScanEnable : LeScanningCommand (op_code = LE_SET_SCAN_ENABLE) {
+ le_scan_enable : Enable,
+ filter_duplicates : Enable,
+}
+
+packet LeSetScanEnableComplete : CommandComplete (command_op_code = LE_SET_SCAN_ENABLE) {
+ status : ErrorCode,
+}
+
+enum InitiatorFilterPolicy : 8 {
+ USE_PEER_ADDRESS = 0x00,
+ USE_WHITE_LIST = 0x01,
+}
+
+enum OwnAddressType : 8 {
+ PUBLIC_DEVICE_ADDRESS = 0x00,
+ RANDOM_DEVICE_ADDRESS = 0x01,
+ RESOLVABLE_OR_PUBLIC_ADDRESS = 0x02,
+ RESOLVABLE_OR_RANDOM_ADDRESS = 0x03,
+}
+
+packet LeCreateConnection : LeConnectionManagementCommand (op_code = LE_CREATE_CONNECTION) {
+ le_scan_interval : 16, // 0x0004-0x4000
+ le_scan_window : 16, // < = LeScanInterval
+ initiator_filter_policy : InitiatorFilterPolicy,
+ peer_address_type : AddressType,
+ peer_address : Address,
+ own_address_type : OwnAddressType,
+ conn_interval_min : 16, // 0x0006-0x0C80 (7.5ms to 4s)
+ conn_interval_max : 16, // 0x0006-0x0C80 (7.5ms to 4s)
+ conn_latency : 16, // 0x0006-0x01F3
+ supervision_timeout : 16, // 0x00A to 0x0C80 (100ms to 32s)
+ minimum_ce_length : 16, // 0.625ms
+ maximum_ce_length : 16, // 0.625ms
+}
+
+packet LeCreateConnectionStatus : CommandStatus (command_op_code = LE_CREATE_CONNECTION) {
+}
+
+packet LeCreateConnectionCancel : LeConnectionManagementCommand (op_code = LE_CREATE_CONNECTION_CANCEL) {
+}
+
+packet LeCreateConnectionCancelStatus : CommandStatus (command_op_code = LE_CREATE_CONNECTION_CANCEL) {
+}
+
+packet LeCreateConnectionCancelComplete : CommandComplete (command_op_code = LE_CREATE_CONNECTION_CANCEL) {
+ status : ErrorCode,
+}
+
+packet LeReadWhiteListSize : LeConnectionManagementCommand (op_code = LE_READ_WHITE_LIST_SIZE) {
+}
+
+packet LeReadWhiteListSizeComplete : CommandComplete (command_op_code = LE_READ_WHITE_LIST_SIZE) {
+ status : ErrorCode,
+ white_list_size : 8,
+}
+
+packet LeClearWhiteList : LeConnectionManagementCommand (op_code = LE_CLEAR_WHITE_LIST) {
+}
+
+packet LeClearWhiteListComplete : CommandComplete (command_op_code = LE_CLEAR_WHITE_LIST) {
+ status : ErrorCode,
+}
+
+enum WhiteListAddressType : 8 {
+ PUBLIC = 0x00,
+ RANDOM = 0x01,
+ ANONYMOUS_ADVERTISERS = 0xFF,
+}
+
+packet LeAddDeviceToWhiteList : LeConnectionManagementCommand (op_code = LE_ADD_DEVICE_TO_WHITE_LIST) {
+ address_type : WhiteListAddressType,
+ address : Address,
+}
+
+packet LeAddDeviceToWhiteListComplete : CommandComplete (command_op_code = LE_ADD_DEVICE_TO_WHITE_LIST) {
+ status : ErrorCode,
+}
+
+packet LeRemoveDeviceFromWhiteList : LeConnectionManagementCommand (op_code = LE_REMOVE_DEVICE_FROM_WHITE_LIST) {
+ address_type : WhiteListAddressType,
+ address : Address,
+}
+
+packet LeRemoveDeviceFromWhiteListComplete : CommandComplete (command_op_code = LE_REMOVE_DEVICE_FROM_WHITE_LIST) {
+ status : ErrorCode,
+}
+
+packet LeConnectionUpdate : LeConnectionManagementCommand (op_code = LE_CONNECTION_UPDATE) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ conn_interval_min : 16, // 0x0006-0x0C80 (7.5ms to 4s)
+ conn_interval_max : 16, // 0x0006-0x0C80 (7.5ms to 4s)
+ conn_latency : 16, // 0x0006-0x01F3
+ supervision_timeout : 16, // 0x00A to 0x0C80 (100ms to 32s)
+ minimum_ce_length : 16, // 0.625ms
+ maximum_ce_length : 16, // 0.625ms
+}
+
+packet LeConnectionUpdateStatus : CommandStatus (command_op_code = LE_CONNECTION_UPDATE) {
+}
+
+packet LeSetHostChannelClassification : LeConnectionManagementCommand (op_code = LE_SET_HOST_CHANNEL_CLASSIFICATION) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadChannelMap : LeConnectionManagementCommand (op_code = LE_READ_CHANNEL_MAP) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadRemoteFeatures : LeConnectionManagementCommand (op_code = LE_READ_REMOTE_FEATURES) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeEncrypt : LeSecurityCommand (op_code = LE_ENCRYPT) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeRand : LeSecurityCommand (op_code = LE_RAND) {
+}
+
+packet LeRandComplete : CommandComplete (command_op_code = LE_RAND) {
+ status : ErrorCode,
+ random_number : 64,
+}
+
+packet LeStartEncryption : LeSecurityCommand (op_code = LE_START_ENCRYPTION) {
+ connection_handle: 16,
+ rand: 8[8],
+ ediv: 16,
+ ltk: 8[16],
+}
+
+packet LeStartEncryptionStatus : CommandStatus (command_op_code = LE_START_ENCRYPTION) {
+}
+
+packet LeLongTermKeyRequestReply : LeSecurityCommand (op_code = LE_LONG_TERM_KEY_REQUEST_REPLY) {
+ connection_handle: 16,
+ long_term_key: 8[16],
+}
+
+packet LeLongTermKeyRequestNegativeReply : LeSecurityCommand (op_code = LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadSupportedStates : CommandPacket (op_code = LE_READ_SUPPORTED_STATES) {
+}
+
+packet LeReadSupportedStatesComplete : CommandComplete (command_op_code = LE_READ_SUPPORTED_STATES) {
+ status : ErrorCode,
+ le_states : 64,
+}
+
+packet LeReceiverTest : CommandPacket (op_code = LE_RECEIVER_TEST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeTransmitterTest : CommandPacket (op_code = LE_TRANSMITTER_TEST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeTestEnd : CommandPacket (op_code = LE_TEST_END) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeRemoteConnectionParameterRequestReply : LeConnectionManagementCommand (op_code = LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeRemoteConnectionParameterRequestNegativeReply : LeConnectionManagementCommand (op_code = LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+
+packet LeSetDataLength : LeConnectionManagementCommand (op_code = LE_SET_DATA_LENGTH) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadSuggestedDefaultDataLength : LeConnectionManagementCommand (op_code = LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeWriteSuggestedDefaultDataLength : LeConnectionManagementCommand (op_code = LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadLocalP256PublicKeyCommand : LeSecurityCommand (op_code = LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeGenerateDhkeyCommand : LeSecurityCommand (op_code = LE_GENERATE_DHKEY_COMMAND) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeAddDeviceToResolvingList : LeSecurityCommand (op_code = LE_ADD_DEVICE_TO_RESOLVING_LIST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeAddDeviceToResolvingListComplete : CommandComplete (command_op_code = LE_ADD_DEVICE_TO_RESOLVING_LIST) {
+ status : ErrorCode,
+}
+
+packet LeRemoveDeviceFromResolvingList : LeSecurityCommand (op_code = LE_REMOVE_DEVICE_FROM_RESOLVING_LIST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeRemoveDeviceFromResolvingListComplete : CommandComplete (command_op_code = LE_REMOVE_DEVICE_FROM_RESOLVING_LIST) {
+ status : ErrorCode,
+}
+
+packet LeClearResolvingList : LeSecurityCommand (op_code = LE_CLEAR_RESOLVING_LIST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeClearResolvingListComplete : CommandComplete (command_op_code = LE_CLEAR_RESOLVING_LIST) {
+ status : ErrorCode,
+}
+
+packet LeReadResolvingListSize : LeSecurityCommand (op_code = LE_READ_RESOLVING_LIST_SIZE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadPeerResolvableAddress : LeSecurityCommand (op_code = LE_READ_PEER_RESOLVABLE_ADDRESS) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadLocalResolvableAddress : LeSecurityCommand (op_code = LE_READ_LOCAL_RESOLVABLE_ADDRESS) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetAddressResolutionEnable : LeSecurityCommand (op_code = LE_SET_ADDRESS_RESOLUTION_ENABLE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetResolvablePrivateAddressTimeout : LeSecurityCommand (op_code = LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadMaximumDataLength : CommandPacket (op_code = LE_READ_MAXIMUM_DATA_LENGTH) {
+}
+
+struct LeMaximumDataLength {
+ supported_max_tx_octets : 16,
+ supported_max_tx_time: 16,
+ supported_max_rx_octets : 16,
+ supported_max_rx_time: 16,
+}
+
+
+packet LeReadMaximumDataLengthComplete : CommandComplete (command_op_code = LE_READ_MAXIMUM_DATA_LENGTH) {
+ status : ErrorCode,
+ le_maximum_data_length : LeMaximumDataLength,
+}
+
+packet LeReadPhy : LeConnectionManagementCommand (op_code = LE_READ_PHY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetDefaultPhy : LeConnectionManagementCommand (op_code = LE_SET_DEFAULT_PHY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetPhy : LeConnectionManagementCommand (op_code = LE_SET_PHY) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeEnhancedReceiverTest : CommandPacket (op_code = LE_ENHANCED_RECEIVER_TEST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeEnhancedTransmitterTest : CommandPacket (op_code = LE_ENHANCED_TRANSMITTER_TEST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetExtendedAdvertisingRandomAddress : LeAdvertisingCommand (op_code = LE_SET_EXTENDED_ADVERTISING_RANDOM_ADDRESS) {
+ advertising_handle : 8,
+ advertising_random_address : Address,
+}
+
+packet LeSetExtendedAdvertisingRandomAddressComplete : CommandComplete (command_op_code = LE_SET_EXTENDED_ADVERTISING_RANDOM_ADDRESS) {
+ status : ErrorCode,
+}
+
+// The lower 4 bits of the advertising event properties
+enum LegacyAdvertisingProperties : 4 {
+ ADV_IND = 0x3,
+ ADV_DIRECT_IND_LOW = 0x5,
+ ADV_DIRECT_IND_HIGH = 0xD,
+ ADV_SCAN_IND = 0x2,
+ ADV_NONCONN_IND = 0,
+}
+
+enum PrimaryPhyType : 8 {
+ LE_1M = 0x01,
+ LE_CODED = 0x03,
+}
+
+enum SecondaryPhyType : 8 {
+ NO_PACKETS = 0x00,
+ LE_1M = 0x01,
+ LE_2M = 0x02,
+ LE_CODED = 0x03,
+}
+
+packet LeSetExtendedAdvertisingLegacyParameters : LeAdvertisingCommand (op_code = LE_SET_EXTENDED_ADVERTISING_PARAMETERS) {
+ advertising_handle : 8,
+ advertising_event_legacy_properties : LegacyAdvertisingProperties,
+ _fixed_ = 0x1 : 1, // legacy bit set
+ _reserved_ : 11, // advertising_event_properties
+ primary_advertising_interval_min : 24, // 0x20 - 0xFFFFFF N * 0.625 ms
+ primary_advertising_interval_max : 24, // 0x20 - 0xFFFFFF N * 0.625 ms
+ primary_advertising_channel_map : 3, // bit 0 - Channel 37, bit 1 - 38, bit 2 - 39
+ _reserved_ : 5,
+ own_address_type : OwnAddressType,
+ peer_address_type : PeerAddressType,
+ peer_address : Address,
+ advertising_filter_policy : AdvertisingFilterPolicy,
+ _reserved_ : 6,
+ advertising_tx_power : 8, // -127 to +20, 0x7F - no preference
+ primary_advertising_phy : PrimaryPhyType,
+ _reserved_ : 8, // secondary_advertising_max_skip
+ _reserved_ : 8, // secondary_advertising_phy
+ advertising_sid : 8, // SID subfield from the ADI field of the PDU
+ scan_request_notification_enable : Enable,
+}
+
+packet LeSetExtendedAdvertisingParameters : LeAdvertisingCommand (op_code = LE_SET_EXTENDED_ADVERTISING_PARAMETERS) {
+ advertising_handle : 8,
+ advertising_event_legacy_properties : 4,
+ _fixed_ = 0 : 1, // legacy bit cleared
+ advertising_event_properties : 3,
+ _reserved_ : 8,
+ primary_advertising_interval_min : 24, // 0x20 - 0xFFFFFF N * 0.625 ms
+ primary_advertising_interval_max : 24, // 0x20 - 0xFFFFFF N * 0.625 ms
+ primary_advertising_channel_map : 3, // bit 0 - Channel 37, bit 1 - 38, bit 2 - 39
+ _reserved_ : 5,
+ own_address_type : OwnAddressType,
+ peer_address_type : PeerAddressType,
+ peer_address : Address,
+ advertising_filter_policy : AdvertisingFilterPolicy,
+ _reserved_ : 6,
+ advertising_tx_power : 8, // -127 to +20, 0x7F - no preference
+ primary_advertising_phy : PrimaryPhyType,
+ secondary_advertising_max_skip : 8, // 1 to 255, 0x00 - AUX_ADV_IND sent before next advertising event
+ secondary_advertising_phy : SecondaryPhyType,
+ advertising_sid : 8, // SID subfield from the ADI field of the PDU
+ scan_request_notification_enable : Enable,
+}
+
+packet LeSetExtendedAdvertisingParametersComplete : CommandComplete (command_op_code = LE_SET_EXTENDED_ADVERTISING_PARAMETERS) {
+ status : ErrorCode,
+ selected_tx_power : 8, // -127 to +20
+}
+
+enum Operation : 3 {
+ INTERMEDIATE_FRAGMENT = 0,
+ FIRST_FRAGMENT = 1,
+ LAST_FRAGMENT = 2,
+ COMPLETE_ADVERTISMENT = 3,
+ UNCHANGED_DATA = 4,
+}
+
+enum FragmentPreference : 1 {
+ CONTROLLER_MAY_FRAGMENT = 0,
+ CONTROLLER_SHOULD_NOT = 1,
+}
+
+packet LeSetExtendedAdvertisingData : LeAdvertisingCommand (op_code = LE_SET_EXTENDED_ADVERTISING_DATA) {
+ advertising_handle : 8,
+ operation : Operation,
+ _reserved_ : 5,
+ fragment_preference : FragmentPreference,
+ _reserved_ : 7,
+ _size_(advertising_data) : 8,
+ advertising_data : GapData[],
+}
+
+packet LeSetExtendedAdvertisingDataRaw : LeAdvertisingCommand (op_code = LE_SET_EXTENDED_ADVERTISING_DATA) {
+ advertising_handle : 8,
+ operation : Operation,
+ _reserved_ : 5,
+ fragment_preference : FragmentPreference,
+ _reserved_ : 7,
+ _size_(advertising_data) : 8,
+ advertising_data : 8[],
+}
+
+packet LeSetExtendedAdvertisingDataComplete : CommandComplete (command_op_code = LE_SET_EXTENDED_ADVERTISING_DATA) {
+ status : ErrorCode,
+}
+
+packet LeSetExtendedAdvertisingScanResponse : LeAdvertisingCommand (op_code = LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE) {
+ advertising_handle : 8,
+ operation : Operation,
+ _reserved_ : 5,
+ fragment_preference : FragmentPreference,
+ _reserved_ : 7,
+ _size_(scan_response_data) : 8,
+ scan_response_data : GapData[],
+}
+
+packet LeSetExtendedAdvertisingScanResponseRaw : LeAdvertisingCommand (op_code = LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE) {
+ advertising_handle : 8,
+ operation : Operation,
+ _reserved_ : 5,
+ fragment_preference : FragmentPreference,
+ _reserved_ : 7,
+ _size_(scan_response_data) : 8,
+ scan_response_data : 8[],
+}
+
+packet LeSetExtendedAdvertisingScanResponseComplete : CommandComplete (command_op_code = LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE) {
+ status : ErrorCode,
+}
+
+packet LeSetExtendedAdvertisingEnableDisableAll : LeAdvertisingCommand (op_code = LE_SET_EXTENDED_ADVERTISING_ENABLE) {
+ _fixed_ = 0x00 : 8, // Enable::DISABLED
+ _fixed_ = 0x00 : 8, // Disable all sets
+}
+
+struct EnabledSet {
+ advertising_handle : 8,
+ duration : 16,
+ max_extended_advertising_events : 8,
+}
+
+struct DisabledSet {
+ advertising_handle : 8,
+ _fixed_ = 0x00 : 16, // duration
+ _fixed_ = 0x00 : 8, // max_extended_advertising_events
+}
+
+packet LeSetExtendedAdvertisingDisable : LeAdvertisingCommand (op_code = LE_SET_EXTENDED_ADVERTISING_ENABLE) {
+ _fixed_ = 0x00 : 8, // Enable::DISABLED
+ _count_(disabled_sets) : 8,
+ disabled_sets : DisabledSet[],
+}
+
+packet LeSetExtendedAdvertisingEnable : LeAdvertisingCommand (op_code = LE_SET_EXTENDED_ADVERTISING_ENABLE) {
+ enable : Enable,
+ _count_(enabled_sets) : 8,
+ enabled_sets : EnabledSet[],
+}
+
+packet LeSetExtendedAdvertisingEnableComplete : CommandComplete (command_op_code = LE_SET_EXTENDED_ADVERTISING_ENABLE) {
+ status : ErrorCode,
+}
+
+packet LeReadMaximumAdvertisingDataLength : CommandPacket (op_code = LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH) {
+}
+
+packet LeReadMaximumAdvertisingDataLengthComplete : CommandComplete (command_op_code = LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH) {
+ status : ErrorCode,
+ maximum_advertising_data_length : 16,
+}
+
+packet LeReadNumberOfSupportedAdvertisingSets : CommandPacket (op_code = LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS) {
+}
+
+packet LeReadNumberOfSupportedAdvertisingSetsComplete : CommandComplete (command_op_code = LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS) {
+ status : ErrorCode,
+ number_supported_advertising_sets : 8,
+}
+
+packet LeRemoveAdvertisingSet : LeAdvertisingCommand (op_code = LE_REMOVE_ADVERTISING_SET) {
+ advertising_handle : 8,
+}
+
+packet LeRemoveAdvertisingSetComplete : CommandComplete (command_op_code = LE_REMOVE_ADVERTISING_SET) {
+ status : ErrorCode,
+}
+
+packet LeClearAdvertisingSets : LeAdvertisingCommand (op_code = LE_CLEAR_ADVERTISING_SETS) {
+}
+
+packet LeClearAdvertisingSetsComplete : CommandComplete (command_op_code = LE_CLEAR_ADVERTISING_SETS) {
+ status : ErrorCode,
+}
+
+packet LeSetPeriodicAdvertisingParam : LeAdvertisingCommand (op_code = LE_SET_PERIODIC_ADVERTISING_PARAM) {
+ advertising_handle : 8,
+ periodic_advertising_interval_min : 16, // 0x006 to 0xFFFF (7.5 ms to 82s)
+ periodic_advertising_interval_max : 16, // 0x006 to 0xFFFF (7.5 ms to 82s)
+ _reserved_ : 6,
+ include_tx_power : 1,
+ _reserved_ : 9,
+}
+
+packet LeSetPeriodicAdvertisingParamComplete : CommandComplete (command_op_code = LE_SET_PERIODIC_ADVERTISING_PARAM) {
+ status : ErrorCode,
+}
+
+packet LeSetPeriodicAdvertisingData : LeAdvertisingCommand (op_code = LE_SET_PERIODIC_ADVERTISING_DATA) {
+ advertising_handle : 8,
+ operation : Operation,
+ _reserved_ : 5,
+ _size_(scan_response_data) : 8,
+ scan_response_data : 8[],
+}
+
+packet LeSetPeriodicAdvertisingDataComplete : CommandComplete (command_op_code = LE_SET_PERIODIC_ADVERTISING_DATA) {
+ status : ErrorCode,
+}
+
+packet LeSetPeriodicAdvertisingEnable : LeAdvertisingCommand (op_code = LE_SET_PERIODIC_ADVERTISING_ENABLE) {
+ advertising_handle : 8,
+ enable : Enable,
+}
+
+packet LeSetPeriodicAdvertisingEnableComplete : CommandComplete (command_op_code = LE_SET_PERIODIC_ADVERTISING_ENABLE) {
+ status : ErrorCode,
+}
+
+struct PhyScanParameters {
+ le_scan_type : LeScanType,
+ le_scan_interval : 16, // 0x0004-0xFFFF Default 0x10 (10ms)
+ le_scan_window : 16, // 0x004-0xFFFF Default 0x10 (10ms)
+}
+
+packet LeSetExtendedScanParameters : LeScanningCommand (op_code = LE_SET_EXTENDED_SCAN_PARAMETERS) {
+ own_address_type : AddressType,
+ scanning_filter_policy : LeSetScanningFilterPolicy,
+ scanning_phys : 8,
+ parameters : PhyScanParameters[],
+}
+
+packet LeSetExtendedScanParametersComplete : CommandComplete (command_op_code = LE_SET_EXTENDED_SCAN_PARAMETERS) {
+ status : ErrorCode,
+}
+
+enum FilterDuplicates : 8 {
+ DISABLED = 0,
+ ENABLED = 1,
+ RESET_EACH_PERIOD = 2,
+}
+
+packet LeSetExtendedScanEnable : LeScanningCommand (op_code = LE_SET_EXTENDED_SCAN_ENABLE) {
+ enable : Enable,
+ filter_duplicates : FilterDuplicates,
+ duration : 16, // 0 - Scan continuously, N * 10 ms
+ period : 16, // 0 - Scan continuously, N * 1.28 sec
+}
+
+packet LeSetExtendedScanEnableComplete : CommandComplete (command_op_code = LE_SET_EXTENDED_SCAN_ENABLE) {
+ status : ErrorCode,
+}
+
+packet LeExtendedCreateConnection : LeConnectionManagementCommand (op_code = LE_EXTENDED_CREATE_CONNECTION) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LePeriodicAdvertisingCreateSync : LeAdvertisingCommand (op_code = LE_PERIODIC_ADVERTISING_CREATE_SYNC) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LePeriodicAdvertisingCreateSyncCancel : LeAdvertisingCommand (op_code = LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LePeriodicAdvertisingTerminateSync : LeAdvertisingCommand (op_code = LE_PERIODIC_ADVERTISING_TERMINATE_SYNC) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeAddDeviceToPeriodicAdvertisingList : LeAdvertisingCommand (op_code = LE_ADD_DEVICE_TO_PERIODIC_ADVERTISING_LIST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeRemoveDeviceFromPeriodicAdvertisingList : LeAdvertisingCommand (op_code = LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISING_LIST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeClearPeriodicAdvertisingList : LeAdvertisingCommand (op_code = LE_CLEAR_PERIODIC_ADVERTISING_LIST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadPeriodicAdvertisingListSize : LeAdvertisingCommand (op_code = LE_READ_PERIODIC_ADVERTISING_LIST_SIZE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadTransmitPower : LeAdvertisingCommand (op_code = LE_READ_TRANSMIT_POWER) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeReadRfPathCompensationPower : LeAdvertisingCommand (op_code = LE_READ_RF_PATH_COMPENSATION_POWER) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeWriteRfPathCompensationPower : LeAdvertisingCommand (op_code = LE_WRITE_RF_PATH_COMPENSATION_POWER) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetPrivacyMode : LeSecurityCommand (op_code = LE_SET_PRIVACY_MODE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeSetPrivacyModeComplete : CommandComplete (command_op_code = LE_SET_PRIVACY_MODE) {
+ status : ErrorCode,
+}
+
+ // VENDOR_SPECIFIC
+packet LeGetVendorCapabilities : VendorCommand (op_code = LE_GET_VENDOR_CAPABILITIES) {
+}
+
+struct VendorCapabilities {
+ is_supported : 8,
+ max_advt_instances: 8,
+ offloaded_resolution_of_private_address : 8,
+ total_scan_results_storage: 16,
+ max_irk_list_sz: 8,
+ filtering_support: 8,
+ max_filter: 8,
+ activity_energy_info_support: 8,
+ version_supported: 16,
+ total_num_of_advt_tracked: 16,
+ extended_scan_support: 8,
+ debug_logging_supported: 8,
+ le_address_generation_offloading_support: 8,
+ a2dp_source_offload_capability_mask: 32,
+ bluetooth_quality_report_support: 8
+}
+
+struct BaseVendorCapabilities {
+ max_advt_instances: 8,
+ offloaded_resolution_of_private_address : 8,
+ total_scan_results_storage: 16,
+ max_irk_list_sz: 8,
+ filtering_support: 8,
+ max_filter: 8,
+ activity_energy_info_support: 8,
+}
+
+packet LeGetVendorCapabilitiesComplete : CommandComplete (command_op_code = LE_GET_VENDOR_CAPABILITIES) {
+ status : ErrorCode,
+ base_vendor_capabilities : BaseVendorCapabilities,
+ _payload_,
+}
+packet LeGetVendorCapabilitiesComplete095 : LeGetVendorCapabilitiesComplete {
+ version_supported: 16,
+ total_num_of_advt_tracked: 16,
+ extended_scan_support: 8,
+ debug_logging_supported: 8,
+ _payload_,
+}
+packet LeGetVendorCapabilitiesComplete096 : LeGetVendorCapabilitiesComplete095 {
+ le_address_generation_offloading_support: 8,
+ _payload_,
+}
+
+packet LeGetVendorCapabilitiesComplete098 : LeGetVendorCapabilitiesComplete096 {
+ a2dp_source_offload_capability_mask: 32,
+ bluetooth_quality_report_support: 8
+}
+
+enum SubOcf : 8 {
+ SET_PARAM = 0x01,
+ SET_DATA = 0x02,
+ SET_SCAN_RESP = 0x03,
+ SET_RANDOM_ADDR = 0x04,
+ SET_ENABLE = 0x05,
+}
+
+packet LeMultiAdvt : LeAdvertisingCommand (op_code = LE_MULTI_ADVT) {
+ sub_cmd : SubOcf,
+ _body_,
+}
+
+packet LeMultiAdvtComplete : CommandComplete (command_op_code = LE_MULTI_ADVT) {
+ status : ErrorCode,
+ sub_cmd : SubOcf,
+}
+
+packet LeMultiAdvtParam : LeMultiAdvt (sub_cmd = SET_PARAM) {
+ interval_min : 16,
+ interval_max : 16,
+ type : AdvertisingEventType,
+ own_address_type : AddressType,
+ peer_address_type : PeerAddressType,
+ peer_address : Address,
+ channel_map : 8,
+ filter_policy : AdvertisingFilterPolicy,
+ _reserved_ : 6,
+ instance : 8,
+ tx_power : 8,
+}
+
+packet LeMultiAdvtParamComplete : LeMultiAdvtComplete (sub_cmd = SET_PARAM) {
+}
+
+packet LeMultiAdvtSetData : LeMultiAdvt (sub_cmd = SET_DATA) {
+ _size_(advertising_data) : 8,
+ advertising_data : GapData[],
+ _padding_[31], // Zero padding to 31 bytes of advertising_data
+ advertising_instance : 8,
+}
+
+packet LeMultiAdvtSetDataComplete : LeMultiAdvtComplete (sub_cmd = SET_DATA) {
+}
+
+packet LeMultiAdvtSetScanResp : LeMultiAdvt (sub_cmd = SET_SCAN_RESP) {
+ _size_(advertising_data) : 8,
+ advertising_data : GapData[],
+ _padding_[31], // Zero padding to 31 bytes of advertising_data
+ advertising_instance : 8,
+}
+
+packet LeMultiAdvtSetScanRespComplete : LeMultiAdvtComplete (sub_cmd = SET_SCAN_RESP) {
+}
+
+packet LeMultiAdvtSetRandomAddr : LeMultiAdvt (sub_cmd = SET_RANDOM_ADDR) {
+ random_address : Address,
+ advertising_instance : 8,
+}
+
+packet LeMultiAdvtSetRandomAddrComplete : LeMultiAdvtComplete (sub_cmd = SET_RANDOM_ADDR) {
+}
+
+packet LeMultiAdvtSetEnable : LeMultiAdvt (sub_cmd = SET_ENABLE) {
+ advertising_enable : Enable, // Default DISABLED
+ advertising_instance : 8,
+}
+
+packet LeMultiAdvtSetEnableComplete : LeMultiAdvtComplete (sub_cmd = SET_ENABLE) {
+}
+
+packet LeBatchScan : VendorCommand (op_code = LE_BATCH_SCAN) {
+ _payload_, // placeholder (unimplemented)
+}
+
+enum ApcfOpcode : 8 {
+ ENABLE = 0x00,
+ SET_FILTERING_PARAMETERS = 0x01,
+ BROADCASTER_ADDRESS = 0x02,
+ SERVICE_UUID = 0x03,
+ SERVICE_SOLICITATION_UUID = 0x04,
+ LOCAL_NAME = 0x05,
+ MANUFACTURER_DATA = 0x06,
+ SERVICE_DATA = 0x07,
+}
+
+packet LeAdvFilter : VendorCommand (op_code = LE_ADV_FILTER) {
+ apcf_opcode : ApcfOpcode,
+ _body_,
+}
+
+packet LeAdvFilterComplete : CommandComplete (command_op_code = LE_ADV_FILTER) {
+ status : ErrorCode,
+ apcf_opcode : ApcfOpcode,
+}
+
+packet LeTrackAdv : VendorCommand (op_code = LE_TRACK_ADV) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeEnergyInfo : VendorCommand (op_code = LE_ENERGY_INFO) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeExtendedScanParams : LeScanningCommand (op_code = LE_EXTENDED_SCAN_PARAMS) {
+ le_scan_type : LeScanType,
+ le_scan_interval : 32, // 0x0004-0x4000 Default 0x10 (10ms)
+ le_scan_window : 32, // Default 0x10 (10ms)
+ own_address_type : AddressType,
+ scanning_filter_policy : LeSetScanningFilterPolicy,
+}
+
+packet LeExtendedScanParamsComplete : CommandComplete (command_op_code = LE_EXTENDED_SCAN_PARAMS) {
+ status : ErrorCode,
+}
+
+packet ControllerDebugInfo : VendorCommand (op_code = CONTROLLER_DEBUG_INFO) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet ControllerA2DPOpcode : VendorCommand (op_code = CONTROLLER_A2DP_OPCODE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+// HCI Event Packets
+
+packet InquiryComplete : EventPacket (event_code = INQUIRY_COMPLETE){
+ status : ErrorCode,
+}
+
+packet InquiryResult : EventPacket (event_code = INQUIRY_RESULT){
+ num_responses : 8,
+ bd_addr : Address,
+ page_scan_repetition_mode : PageScanRepetitionMode,
+ _reserved_ : 8,
+ _reserved_ : 8,
+ class_of_device : ClassOfDevice,
+ clock_offset : 15,
+ _reserved_ : 1,
+}
+
+enum LinkType : 8 {
+ SCO = 0x00,
+ ACL = 0x01,
+}
+
+packet ConnectionComplete : EventPacket (event_code = CONNECTION_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ bd_addr : Address,
+ link_type : LinkType,
+ encryption_enabled : Enable,
+}
+
+enum ConnectionRequestLinkType : 8 {
+ SCO = 0x00,
+ ACL = 0x01,
+ ESCO = 0x02,
+}
+
+packet ConnectionRequest : EventPacket (event_code = CONNECTION_REQUEST){
+ bd_addr : Address,
+ class_of_device : ClassOfDevice,
+ link_type : ConnectionRequestLinkType,
+}
+
+packet DisconnectionComplete : EventPacket (event_code = DISCONNECTION_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ reason : ErrorCode,
+}
+
+packet AuthenticationComplete : EventPacket (event_code = AUTHENTICATION_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet RemoteNameRequestComplete : EventPacket (event_code = REMOTE_NAME_REQUEST_COMPLETE){
+ status : ErrorCode,
+ bd_addr : Address,
+ remote_name : 8[248], // UTF-8 encoded user-friendly descriptive name
+}
+
+enum EncryptionEnabled : 8 {
+ OFF = 0x00,
+ ON = 0x01, // E0 for BR/EDR and AES-CCM for LE
+ BR_EDR_AES_CCM = 0x02,
+}
+
+packet EncryptionChange : EventPacket (event_code = ENCRYPTION_CHANGE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ encryption_enabled : EncryptionEnabled,
+}
+
+packet ChangeConnectionLinkKeyComplete : EventPacket (event_code = CHANGE_CONNECTION_LINK_KEY_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet MasterLinkKeyComplete : EventPacket (event_code = MASTER_LINK_KEY_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ key_flag : KeyFlag,
+}
+
+packet ReadRemoteSupportedFeaturesComplete : EventPacket (event_code = READ_REMOTE_SUPPORTED_FEATURES_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ lmp_features : 64,
+}
+
+packet ReadRemoteVersionInformationComplete : EventPacket (event_code = READ_REMOTE_VERSION_INFORMATION_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ version : 8,
+ manufacturer_name : 16,
+ sub_version : 16,
+}
+
+packet QosSetupComplete : EventPacket (event_code = QOS_SETUP_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ _reserved_ : 8,
+ service_type : ServiceType,
+ token_rate : 32, // Octets/s
+ peak_bandwidth : 32, // Octets/s
+ latency : 32, // Octets/s
+ delay_variation : 32, // microseconds
+}
+
+// Command Complete and Command Status Events are implemented above Commands.
+
+packet HardwareError : EventPacket (event_code = HARDWARE_ERROR){
+ hardware_code : 8,
+}
+
+packet FlushOccurred : EventPacket (event_code = FLUSH_OCCURRED){
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet RoleChange : EventPacket (event_code = ROLE_CHANGE){
+ status : ErrorCode,
+ bd_addr : Address,
+ new_role : Role,
+}
+
+packet NumberOfCompletedPackets : EventPacket (event_code = NUMBER_OF_COMPLETED_PACKETS){
+ _count_(completed_packets) : 8,
+ completed_packets : CompletedPackets[],
+}
+
+enum Mode : 8 {
+ ACTIVE = 0x00,
+ HOLD = 0x01,
+ SNIFF = 0x02,
+}
+
+packet ModeChange : EventPacket (event_code = MODE_CHANGE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ current_mode : Mode,
+ interval : 16, // 0x002 - 0xFFFE (1.25ms - 40.9s)
+}
+
+struct ZeroKeyAndAddress {
+ address : Address,
+ _fixed_ = 0 : 64,
+ _fixed_ = 0 : 64,
+}
+
+packet ReturnLinkKeys : EventPacket (event_code = RETURN_LINK_KEYS){
+ _count_(keys) : 8,
+ keys : ZeroKeyAndAddress[],
+}
+
+packet PinCodeRequest : EventPacket (event_code = PIN_CODE_REQUEST){
+ bd_addr : Address,
+}
+
+packet LinkKeyRequest : EventPacket (event_code = LINK_KEY_REQUEST){
+ bd_addr : Address,
+}
+
+enum KeyType : 8 {
+ COMBINATION = 0x00,
+ DEBUG_COMBINATION = 0x03,
+ UNAUTHENTICATED_P192 = 0x04,
+ AUTHENTICATED_P192 = 0x05,
+ CHANGED = 0x06,
+ UNAUTHENTICATED_P256 = 0x07,
+ AUTHENTICATED_P256 = 0x08,
+}
+
+packet LinkKeyNotification : EventPacket (event_code = LINK_KEY_NOTIFICATION){
+ bd_addr : Address,
+ link_key : 8[16],
+ key_type : KeyType,
+}
+
+packet LoopbackCommand : EventPacket (event_code = LOOPBACK_COMMAND){
+ _payload_, // placeholder (unimplemented)
+}
+
+packet DataBufferOverflow : EventPacket (event_code = DATA_BUFFER_OVERFLOW){
+ link_type : LinkType,
+}
+
+packet MaxSlotsChange : EventPacket (event_code = MAX_SLOTS_CHANGE){
+ connection_handle : 12,
+ _reserved_ : 4,
+ lmp_max_slots : 8,
+}
+
+packet ReadClockOffsetComplete : EventPacket (event_code = READ_CLOCK_OFFSET_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ clock_offset : 15,
+ _reserved_ : 1,
+}
+
+packet ConnectionPacketTypeChanged : EventPacket (event_code = CONNECTION_PACKET_TYPE_CHANGED){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ packet_type : 16,
+}
+
+packet QosViolation : EventPacket (event_code = QOS_VIOLATION){
+ _payload_, // placeholder (unimplemented)
+}
+
+packet PageScanRepetitionModeChange : EventPacket (event_code = PAGE_SCAN_REPETITION_MODE_CHANGE){
+ _payload_, // placeholder (unimplemented)
+}
+
+packet FlowSpecificationComplete : EventPacket (event_code = FLOW_SPECIFICATION_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ _reserved_ : 8,
+ flow_direction : FlowDirection,
+ service_type : ServiceType,
+ token_rate : 32, // Octets/s
+ token_bucket_size : 32,
+ peak_bandwidth : 32, // Octets/s
+ access_latency : 32, // Octets/s
+}
+
+packet InquiryResultWithRssi : EventPacket (event_code = INQUIRY_RESULT_WITH_RSSI){
+ num_responses : 8,
+ address : Address,
+ page_scan_repetition_mode : PageScanRepetitionMode,
+ _reserved_ : 8,
+ class_of_device : ClassOfDevice,
+ clock_offset : 15,
+ _reserved_ : 1,
+ rssi : 8,
+}
+
+packet ReadRemoteExtendedFeaturesComplete : EventPacket (event_code = READ_REMOTE_EXTENDED_FEATURES_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ page_number : 8,
+ maximum_page_number : 8,
+ extended_lmp_features : 64,
+}
+
+packet SynchronousConnectionComplete : EventPacket (event_code = SYNCHRONOUS_CONNECTION_COMPLETE){
+ _payload_, // placeholder (unimplemented)
+}
+
+packet SynchronousConnectionChanged : EventPacket (event_code = SYNCHRONOUS_CONNECTION_CHANGED){
+ _payload_, // placeholder (unimplemented)
+}
+
+packet SniffSubratingEvent : EventPacket (event_code = SNIFF_SUBRATING){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ maximum_transmit_latency : 16, // 0x000 - 0xFFFE (0s - 40.9s)
+ maximum_receive_latency : 16, // 0x000 - 0xFFFE (0s - 40.9s)
+ minimum_remote_timeout : 16, // 0x000 - 0xFFFE (0s - 40.9s)
+ minimum_local_timeout : 16, // 0x000 - 0xFFFE (0s - 40.9s)
+}
+
+packet ExtendedInquiryResult : EventPacket (event_code = EXTENDED_INQUIRY_RESULT) {
+ _fixed_ = 0x01 : 8,
+ address : Address,
+ page_scan_repetition_mode : PageScanRepetitionMode,
+ _reserved_ : 8,
+ class_of_device : ClassOfDevice,
+ clock_offset : 15,
+ _reserved_ : 1,
+ rssi : 8,
+ extended_inquiry_response : GapData[],
+}
+
+packet EncryptionKeyRefreshComplete : EventPacket (event_code = ENCRYPTION_KEY_REFRESH_COMPLETE){
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet IoCapabilityRequest : EventPacket (event_code = IO_CAPABILITY_REQUEST){
+ bd_addr : Address,
+}
+
+packet IoCapabilityResponse : EventPacket (event_code = IO_CAPABILITY_RESPONSE){
+ bd_addr : Address,
+ io_capability : IoCapability,
+ oob_data_present : OobDataPresent,
+ authentication_requirements : AuthenticationRequirements,
+}
+
+packet UserConfirmationRequest : EventPacket (event_code = USER_CONFIRMATION_REQUEST){
+ bd_addr : Address,
+ numeric_value : 20, // 0x00000-0xF423F (000000 - 999999)
+ _reserved_ : 12,
+}
+
+packet UserPasskeyRequest : EventPacket (event_code = USER_PASSKEY_REQUEST){
+ bd_addr : Address,
+}
+
+packet RemoteOobDataRequest : EventPacket (event_code = REMOTE_OOB_DATA_REQUEST){
+ bd_addr : Address,
+}
+
+packet SimplePairingComplete : EventPacket (event_code = SIMPLE_PAIRING_COMPLETE){
+ status : ErrorCode,
+ bd_addr : Address,
+}
+
+packet LinkSupervisionTimeoutChanged : EventPacket (event_code = LINK_SUPERVISION_TIMEOUT_CHANGED){
+ connection_handle : 12,
+ _reserved_ : 4,
+ link_supervision_timeout : 16, // 0x001-0xFFFF (0.625ms-40.9s)
+}
+
+packet EnhancedFlushComplete : EventPacket (event_code = ENHANCED_FLUSH_COMPLETE){
+ connection_handle : 12,
+ _reserved_ : 4,
+}
+
+packet UserPasskeyNotification : EventPacket (event_code = USER_PASSKEY_NOTIFICATION){
+ bd_addr : Address,
+ passkey : 20, // 0x00000-0xF423F (000000 - 999999)
+ _reserved_ : 12,
+}
+
+packet KeypressNotification : EventPacket (event_code = KEYPRESS_NOTIFICATION){
+ bd_addr : Address,
+ notification_type : KeypressNotificationType,
+}
+
+packet RemoteHostSupportedFeaturesNotification : EventPacket (event_code = REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION){
+ bd_addr : Address,
+ host_supported_features : 64,
+}
+
+packet LeMetaEvent : EventPacket (event_code = LE_META_EVENT) {
+ subevent_code : SubeventCode,
+ _payload_,
+}
+
+packet NumberOfCompletedDataBlocks : EventPacket (event_code = NUMBER_OF_COMPLETED_DATA_BLOCKS){
+ _payload_, // placeholder (unimplemented)
+}
+
+// LE Events
+
+enum MasterClockAccuracy : 8 {
+ PPM_500 = 0x00,
+ PPM_250 = 0x01,
+ PPM_150 = 0x02,
+ PPM_100 = 0x03,
+ PPM_75 = 0x04,
+ PPM_50 = 0x05,
+ PPM_30 = 0x06,
+ PPM_20 = 0x07,
+}
+
+packet LeConnectionComplete : LeMetaEvent (subevent_code = CONNECTION_COMPLETE) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ role : Role,
+ peer_address_type : AddressType,
+ peer_address : Address,
+ conn_interval : 16, // 0x006 - 0x0C80 (7.5ms - 4000ms)
+ conn_latency : 16, // Number of connection events
+ supervision_timeout : 16, // 0x000A to 0x0C80 (100ms to 32s)
+ master_clock_accuracy : MasterClockAccuracy,
+}
+
+struct LeAdvertisingReport {
+ event_type : AdvertisingEventType,
+ address_type : AddressType,
+ address : Address,
+ _size_(advertising_data) : 8,
+ advertising_data : GapData[],
+ rssi : 8,
+}
+
+packet LeAdvertisingReport : LeMetaEvent (subevent_code = ADVERTISING_REPORT) {
+ _count_(advertising_reports) : 8,
+ advertising_reports : LeAdvertisingReport[],
+}
+
+packet LeConnectionUpdateComplete : LeMetaEvent (subevent_code = CONNECTION_UPDATE_COMPLETE) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ conn_interval : 16, // 0x006 - 0x0C80 (7.5ms - 4000ms)
+ conn_latency : 16, // Number of connection events
+ supervision_timeout : 16, // 0x000A to 0x0C80 (100ms to 32s)
+}
+
+packet LeReadRemoteFeaturesComplete : LeMetaEvent (subevent_code = READ_REMOTE_FEATURES_COMPLETE) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ le_features : 64,
+}
+
+packet LeLongTermKeyRequest : LeMetaEvent (subevent_code = LONG_TERM_KEY_REQUEST) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ random_number : 64,
+ encrypted_diversifier : 16,
+}
+
+packet LeRemoteConnectionParameterRequest : LeMetaEvent (subevent_code = REMOTE_CONNECTION_PARAMETER_REQUEST) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ interval_min : 16, // 0x006 - 0x0C80 (7.5ms - 4s)
+ interval_max : 16, // 0x006 - 0x0C80 (7.5ms - 4s)
+ latency : 16, // Number of connection events (0x0000 to 0x01f3 (499)
+ timeout : 16, // 0x000A to 0x0C80 (100ms to 32s)
+}
+
+packet LeDataLengthChange : LeMetaEvent (subevent_code = DATA_LENGTH_CHANGE) {
+ connection_handle : 12,
+ _reserved_ : 4,
+ max_tx_octets : 16, // 0x001B - 0x00FB
+ max_tx_time : 16, // 0x0148 - 0x4290
+ max_rx_octets : 16, // 0x001B - 0x00FB
+ max_rx_time : 16, // 0x0148 - 0x4290
+}
+
+packet ReadLocalP256PublicKeyComplete : LeMetaEvent (subevent_code = READ_LOCAL_P256_PUBLIC_KEY_COMPLETE) {
+ status : ErrorCode,
+ local_p_256_public_key : 8[64],
+}
+
+packet GenerateDhKeyComplete : LeMetaEvent (subevent_code = GENERATE_DHKEY_COMPLETE) {
+ status : ErrorCode,
+ dh_key : 8[32],
+}
+
+packet LeEnhancedConnectionComplete : LeMetaEvent (subevent_code = ENHANCED_CONNECTION_COMPLETE) {
+ status : ErrorCode,
+ connection_handle : 12,
+ _reserved_ : 4,
+ role : Role,
+ peer_address_type : AddressType,
+ peer_address : Address,
+ local_resolvable_private_address : Address,
+ peer_resolvable_private_address : Address,
+ conn_interval : 16, // 0x006 - 0x0C80 (7.5ms - 4000ms)
+ conn_latency : 16, // Number of connection events
+ supervision_timeout : 16, // 0x000A to 0x0C80 (100ms to 32s)
+ master_clock_accuracy : MasterClockAccuracy,
+}
+
+enum DirectAdvertisingAddressType : 8 {
+ PUBLIC_DEVICE_ADDRESS = 0x00,
+ RANDOM_DEVICE_ADDRESS = 0x01,
+ PUBLIC_IDENTITY_ADDRESS = 0x02,
+ RANDOM_IDENTITY_ADDRESS = 0x03,
+ CONTROLLER_UNABLE_TO_RESOLVE = 0xFE,
+ NO_ADDRESS = 0xFF,
+}
+
+enum DirectAdvertisingEventType : 8 {
+ ADV_DIRECT_IND = 0x01,
+}
+
+enum DirectAddressType : 8 {
+ RANDOM_DEVICE_ADDRESS = 0x01,
+}
+
+struct LeDirectedAdvertisingReport {
+ event_type : DirectAdvertisingEventType,
+ address_type : DirectAdvertisingAddressType,
+ address : Address,
+ direct_address_type : DirectAddressType,
+ direct_address : Address,
+ rssi : 8,
+}
+
+packet LeDirectedAdvertisingReport : LeMetaEvent (subevent_code = DIRECTED_ADVERTISING_REPORT) {
+ _count_(advertising_reports) : 8,
+ advertising_reports : LeDirectedAdvertisingReport[],
+}
+
+packet LePhyUpdateComplete : LeMetaEvent (subevent_code = PHY_UPDATE_COMPLETE) {
+ _payload_, // placeholder (unimplemented)
+}
+
+enum DataStatus : 2 {
+ COMPLETE = 0x0,
+ CONTINUING = 0x1,
+ TRUNCATED = 0x2,
+ RESERVED = 0x3,
+}
+
+struct LeExtendedAdvertisingReport {
+ connectable : 1,
+ scannable : 1,
+ directed : 1,
+ scan_response : 1,
+ data_status : DataStatus,
+ _reserved_ : 10,
+ address_type : DirectAdvertisingAddressType,
+ address : Address,
+ primary_phy : PrimaryPhyType,
+ secondary_phy : SecondaryPhyType,
+ advertising_sid : 4, // SID subfield in the ADI field
+ _reserved_ : 4,
+ tx_power : 8,
+ rssi : 8, // -127 to +20 (0x7F means not available)
+ periodic_advertising_interval : 16, // 0x006 to 0xFFFF (7.5 ms to 82s)
+ direct_address_type : DirectAdvertisingAddressType,
+ direct_address : Address,
+ _size_(advertising_data) : 8,
+ advertising_data : GapData[],
+}
+
+packet LeExtendedAdvertisingReport : LeMetaEvent (subevent_code = EXTENDED_ADVERTISING_REPORT) {
+ _count_(advertising_reports) : 8,
+ advertising_reports : LeExtendedAdvertisingReport[],
+}
+
+packet LePeriodicAdvertisingSyncEstablished : LeMetaEvent (subevent_code = PERIODIC_ADVERTISING_SYNC_ESTABLISHED) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LePeriodicAdvertisingReport : LeMetaEvent (subevent_code = PERIODIC_ADVERTISING_REPORT) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LePeriodicAdvertisingSyncLost : LeMetaEvent (subevent_code = PERIODIC_ADVERTISING_SYNC_LOST) {
+ _payload_, // placeholder (unimplemented)
+}
+
+packet LeScanTimeout : LeMetaEvent (subevent_code = SCAN_TIMEOUT) {
+}
+
+packet LeAdvertisingSetTerminated : LeMetaEvent (subevent_code = ADVERTISING_SET_TERMINATED) {
+ status : ErrorCode,
+ advertising_handle : 8,
+ connection_handle : 12,
+ _reserved_ : 4,
+ num_completed_extended_advertising_events : 8,
+}
+
+packet LeScanRequestReceived : LeMetaEvent (subevent_code = SCAN_REQUEST_RECEIVED) {
+ advertising_handle : 8,
+ scanner_address_type : AddressType,
+ scanner_address : Address,
+}
diff --git a/gd/hci/hci_packets_fuzz_test.cc b/gd/hci/hci_packets_fuzz_test.cc
new file mode 100644
index 0000000..5ef3ef6
--- /dev/null
+++ b/gd/hci/hci_packets_fuzz_test.cc
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#define PACKET_FUZZ_TESTING
+#include "hci/hci_packets.h"
+
+#include <memory>
+
+#include "os/log.h"
+#include "packet/bit_inserter.h"
+#include "packet/raw_builder.h"
+
+using bluetooth::packet::BitInserter;
+using bluetooth::packet::RawBuilder;
+using std::vector;
+
+namespace bluetooth {
+namespace hci {
+
+std::vector<void (*)(const uint8_t*, size_t)> hci_packet_fuzz_tests;
+
+DEFINE_AND_REGISTER_ResetReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ResetCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadBufferSizeReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadBufferSizeCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_HostBufferSizeReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_HostBufferSizeCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadLocalVersionInformationReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadLocalVersionInformationCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadBdAddrReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadBdAddrCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadLocalSupportedCommandsReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadLocalSupportedCommandsCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WriteSimplePairingModeReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WriteSimplePairingModeCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WriteLeHostSupportReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WriteLeHostSupportCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadLocalExtendedFeaturesReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadLocalExtendedFeaturesCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WriteSecureConnectionsHostSupportReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WriteSecureConnectionsHostSupportCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_LeReadWhiteListSizeReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_LeReadWhiteListSizeCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_LeReadBufferSizeReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_LeReadBufferSizeCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WriteCurrentIacLapReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WriteCurrentIacLapCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WriteInquiryScanActivityReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WriteInquiryScanActivityCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadInquiryScanActivityReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadInquiryScanActivityCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadCurrentIacLapReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadCurrentIacLapCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadNumberOfSupportedIacReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadNumberOfSupportedIacCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadPageTimeoutReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ReadPageTimeoutCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WritePageTimeoutReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_WritePageTimeoutCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_InquiryReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_InquiryStatusReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_InquiryCancelReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_InquiryCancelCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_PeriodicInquiryModeReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_PeriodicInquiryModeCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ExitPeriodicInquiryModeReflectionFuzzTest(hci_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ExitPeriodicInquiryModeCompleteReflectionFuzzTest(hci_packet_fuzz_tests);
+
+} // namespace hci
+} // namespace bluetooth
+
+void RunHciPacketFuzzTest(const uint8_t* data, size_t size) {
+ if (data == nullptr) return;
+ for (auto test_function : bluetooth::hci::hci_packet_fuzz_tests) {
+ test_function(data, size);
+ }
+}
\ No newline at end of file
diff --git a/gd/hci/hci_packets_test.cc b/gd/hci/hci_packets_test.cc
new file mode 100644
index 0000000..48a929c
--- /dev/null
+++ b/gd/hci/hci_packets_test.cc
@@ -0,0 +1,598 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#define PACKET_TESTING
+#include "hci/hci_packets.h"
+
+#include <gtest/gtest.h>
+#include <forward_list>
+#include <memory>
+
+#include "os/log.h"
+#include "packet/bit_inserter.h"
+#include "packet/raw_builder.h"
+
+using bluetooth::packet::BitInserter;
+using bluetooth::packet::RawBuilder;
+using std::vector;
+
+namespace bluetooth {
+namespace hci {
+
+std::vector<uint8_t> reset = {0x03, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_ResetReflectionTest(reset);
+
+std::vector<uint8_t> reset_complete = {0x0e, 0x04, 0x01, 0x03, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_ResetCompleteReflectionTest(reset_complete);
+
+std::vector<uint8_t> read_buffer_size = {0x05, 0x10, 0x00};
+DEFINE_AND_INSTANTIATE_ReadBufferSizeReflectionTest(read_buffer_size);
+
+std::vector<uint8_t> read_buffer_size_complete = {0x0e, 0x0b, 0x01, 0x05, 0x10, 0x00, 0x00,
+ 0x04, 0x3c, 0x07, 0x00, 0x08, 0x00};
+DEFINE_AND_INSTANTIATE_ReadBufferSizeCompleteReflectionTest(read_buffer_size_complete);
+
+std::vector<uint8_t> host_buffer_size = {0x33, 0x0c, 0x07, 0x9b, 0x06, 0xff, 0x14, 0x00, 0x0a, 0x00};
+DEFINE_AND_INSTANTIATE_HostBufferSizeReflectionTest(host_buffer_size);
+
+std::vector<uint8_t> host_buffer_size_complete = {0x0e, 0x04, 0x01, 0x33, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_HostBufferSizeCompleteReflectionTest(host_buffer_size_complete);
+
+std::vector<uint8_t> read_local_version_information = {0x01, 0x10, 0x00};
+DEFINE_AND_INSTANTIATE_ReadLocalVersionInformationReflectionTest(read_local_version_information);
+
+std::vector<uint8_t> read_local_version_information_complete = {0x0e, 0x0c, 0x01, 0x01, 0x10, 0x00, 0x09,
+ 0x00, 0x00, 0x09, 0x1d, 0x00, 0xbe, 0x02};
+DEFINE_AND_INSTANTIATE_ReadLocalVersionInformationCompleteReflectionTest(read_local_version_information_complete);
+
+std::vector<uint8_t> read_bd_addr = {0x09, 0x10, 0x00};
+DEFINE_AND_INSTANTIATE_ReadBdAddrReflectionTest(read_bd_addr);
+
+std::vector<uint8_t> read_bd_addr_complete = {0x0e, 0x0a, 0x01, 0x09, 0x10, 0x00, 0x14, 0x8e, 0x61, 0x5f, 0x36, 0x88};
+DEFINE_AND_INSTANTIATE_ReadBdAddrCompleteReflectionTest(read_bd_addr_complete);
+
+std::vector<uint8_t> read_local_supported_commands = {0x02, 0x10, 0x00};
+DEFINE_AND_INSTANTIATE_ReadLocalSupportedCommandsReflectionTest(read_local_supported_commands);
+
+std::vector<uint8_t> read_local_supported_commands_complete = {
+ 0x0e, 0x44, 0x01, 0x02, 0x10, 0x00, /* Supported commands start here (total 64 bytes) */
+ 0xff, 0xff, 0xff, 0x03, 0xce, 0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xf2, 0x0f, 0xe8, 0xfe,
+ 0x3f, 0xf7, 0x83, 0xff, 0x1c, 0x00, 0x00, 0x00, 0x61, 0xff, 0xff, 0xff, 0x7f, 0xbe, 0x20, 0xf5,
+ 0xff, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+DEFINE_AND_INSTANTIATE_ReadLocalSupportedCommandsCompleteReflectionTest(read_local_supported_commands_complete);
+
+std::vector<uint8_t> read_local_extended_features_0 = {0x04, 0x10, 0x01, 0x00};
+
+std::vector<uint8_t> read_local_extended_features_complete_0 = {0x0e, 0x0e, 0x01, 0x04, 0x10, 0x00, 0x00, 0x02,
+ 0xff, 0xfe, 0x8f, 0xfe, 0xd8, 0x3f, 0x5b, 0x87};
+
+std::vector<uint8_t> write_simple_paring_mode = {0x56, 0x0c, 0x01, 0x01};
+DEFINE_AND_INSTANTIATE_WriteSimplePairingModeReflectionTest(write_simple_paring_mode);
+
+std::vector<uint8_t> write_simple_paring_mode_complete = {0x0e, 0x04, 0x01, 0x56, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_WriteSimplePairingModeCompleteReflectionTest(write_simple_paring_mode_complete);
+
+std::vector<uint8_t> write_le_host_supported = {0x6d, 0x0c, 0x02, 0x01, 0x01};
+DEFINE_AND_INSTANTIATE_WriteLeHostSupportReflectionTest(write_le_host_supported);
+
+std::vector<uint8_t> write_le_host_supported_complete = {0x0e, 0x04, 0x01, 0x6d, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_WriteLeHostSupportCompleteReflectionTest(write_le_host_supported_complete);
+
+std::vector<uint8_t> read_local_extended_features_1 = {0x04, 0x10, 0x01, 0x01};
+
+std::vector<uint8_t> read_local_extended_features_complete_1 = {0x0e, 0x0e, 0x01, 0x04, 0x10, 0x00, 0x01, 0x02,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+std::vector<uint8_t> read_local_extended_features_2 = {0x04, 0x10, 0x01, 0x02};
+DEFINE_AND_INSTANTIATE_ReadLocalExtendedFeaturesReflectionTest(read_local_extended_features_0,
+ read_local_extended_features_1,
+ read_local_extended_features_2);
+
+std::vector<uint8_t> read_local_extended_features_complete_2 = {0x0e, 0x0e, 0x01, 0x04, 0x10, 0x00, 0x02, 0x02,
+ 0x45, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+DEFINE_AND_INSTANTIATE_ReadLocalExtendedFeaturesCompleteReflectionTest(read_local_extended_features_complete_0,
+ read_local_extended_features_complete_1,
+ read_local_extended_features_complete_2);
+
+std::vector<uint8_t> write_secure_connections_host_support = {0x7a, 0x0c, 0x01, 0x01};
+DEFINE_AND_INSTANTIATE_WriteSecureConnectionsHostSupportReflectionTest(write_secure_connections_host_support);
+
+std::vector<uint8_t> write_secure_connections_host_support_complete = {0x0e, 0x04, 0x01, 0x7a, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_WriteSecureConnectionsHostSupportCompleteReflectionTest(
+ write_secure_connections_host_support_complete);
+
+std::vector<uint8_t> le_read_white_list_size = {0x0f, 0x20, 0x00};
+DEFINE_AND_INSTANTIATE_LeReadWhiteListSizeReflectionTest(le_read_white_list_size);
+
+std::vector<uint8_t> le_read_white_list_size_complete = {0x0e, 0x05, 0x01, 0x0f, 0x20, 0x00, 0x80};
+DEFINE_AND_INSTANTIATE_LeReadWhiteListSizeCompleteReflectionTest(le_read_white_list_size_complete);
+
+std::vector<uint8_t> le_read_buffer_size = {0x02, 0x20, 0x00};
+DEFINE_AND_INSTANTIATE_LeReadBufferSizeReflectionTest(le_read_buffer_size);
+
+std::vector<uint8_t> le_read_buffer_size_complete = {0x0e, 0x07, 0x01, 0x02, 0x20, 0x00, 0xfb, 0x00, 0x10};
+DEFINE_AND_INSTANTIATE_LeReadBufferSizeCompleteReflectionTest(le_read_buffer_size_complete);
+
+std::vector<uint8_t> write_current_iac_laps = {0x3a, 0x0c, 0x07, 0x02, 0x11, 0x8b, 0x9e, 0x22, 0x8b, 0x9e};
+DEFINE_AND_INSTANTIATE_WriteCurrentIacLapReflectionTest(write_current_iac_laps);
+
+std::vector<uint8_t> write_current_iac_laps_complete = {0x0e, 0x04, 0x01, 0x3a, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_WriteCurrentIacLapCompleteReflectionTest(write_current_iac_laps_complete);
+
+std::vector<uint8_t> write_inquiry_scan_activity = {0x1e, 0x0c, 0x04, 0x00, 0x08, 0x12, 0x00};
+DEFINE_AND_INSTANTIATE_WriteInquiryScanActivityReflectionTest(write_inquiry_scan_activity);
+
+std::vector<uint8_t> write_inquiry_scan_activity_complete = {0x0e, 0x04, 0x01, 0x1e, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_WriteInquiryScanActivityCompleteReflectionTest(write_inquiry_scan_activity_complete);
+
+std::vector<uint8_t> read_inquiry_scan_activity = {0x1d, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_ReadInquiryScanActivityReflectionTest(read_inquiry_scan_activity);
+
+std::vector<uint8_t> read_inquiry_scan_activity_complete = {0x0e, 0x08, 0x01, 0x1d, 0x0c, 0x00, 0xaa, 0xbb, 0xcc, 0xdd};
+DEFINE_AND_INSTANTIATE_ReadInquiryScanActivityCompleteReflectionTest(read_inquiry_scan_activity_complete);
+
+std::vector<uint8_t> read_current_iac_lap = {0x39, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_ReadCurrentIacLapReflectionTest(read_current_iac_lap);
+
+std::vector<uint8_t> read_current_iac_lap_complete = {0x0e, 0x0b, 0x01, 0x39, 0x0c, 0x00, 0x02,
+ 0x11, 0x8b, 0x9e, 0x22, 0x8b, 0x9e};
+DEFINE_AND_INSTANTIATE_ReadCurrentIacLapCompleteReflectionTest(read_current_iac_lap_complete);
+
+std::vector<uint8_t> read_number_of_supported_iac = {0x38, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_ReadNumberOfSupportedIacReflectionTest(read_number_of_supported_iac);
+
+std::vector<uint8_t> read_number_of_supported_iac_complete = {0x0e, 0x05, 0x01, 0x38, 0x0c, 0x00, 0x99};
+DEFINE_AND_INSTANTIATE_ReadNumberOfSupportedIacCompleteReflectionTest(read_number_of_supported_iac_complete);
+
+std::vector<uint8_t> read_page_timeout = {0x17, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_ReadPageTimeoutReflectionTest(read_page_timeout);
+
+std::vector<uint8_t> read_page_timeout_complete = {0x0e, 0x06, 0x01, 0x17, 0x0c, 0x00, 0x11, 0x22};
+DEFINE_AND_INSTANTIATE_ReadPageTimeoutCompleteReflectionTest(read_page_timeout_complete);
+
+std::vector<uint8_t> write_page_timeout = {0x18, 0x0c, 0x02, 0x00, 0x20};
+DEFINE_AND_INSTANTIATE_WritePageTimeoutReflectionTest(write_page_timeout);
+
+std::vector<uint8_t> write_page_timeout_complete = {0x0e, 0x04, 0x01, 0x18, 0x0c, 0x00};
+DEFINE_AND_INSTANTIATE_WritePageTimeoutCompleteReflectionTest(write_page_timeout_complete);
+
+std::vector<uint8_t> inquiry = {0x01, 0x04, 0x05, 0x33, 0x8b, 0x9e, 0xaa, 0xbb};
+DEFINE_AND_INSTANTIATE_InquiryReflectionTest(inquiry);
+
+std::vector<uint8_t> inquiry_status = {0x0f, 0x04, 0x00, 0x01, 0x01, 0x04};
+DEFINE_AND_INSTANTIATE_InquiryStatusReflectionTest(inquiry_status);
+
+std::vector<uint8_t> inquiry_cancel = {0x02, 0x04, 0x00};
+DEFINE_AND_INSTANTIATE_InquiryCancelReflectionTest(inquiry_cancel);
+
+std::vector<uint8_t> inquiry_cancel_complete = {0x0e, 0x04, 0x01, 0x02, 0x04, 0x00};
+DEFINE_AND_INSTANTIATE_InquiryCancelCompleteReflectionTest(inquiry_cancel_complete);
+
+std::vector<uint8_t> periodic_inquiry_mode = {0x03, 0x04, 0x09, 0x12, 0x34, 0x56, 0x78, 0x11, 0x8b, 0x9e, 0x9a, 0xbc};
+DEFINE_AND_INSTANTIATE_PeriodicInquiryModeReflectionTest(periodic_inquiry_mode);
+
+std::vector<uint8_t> periodic_inquiry_mode_complete = {0x0e, 0x04, 0x01, 0x03, 0x04, 0x00};
+DEFINE_AND_INSTANTIATE_PeriodicInquiryModeCompleteReflectionTest(periodic_inquiry_mode_complete);
+
+std::vector<uint8_t> exit_periodic_inquiry_mode = {0x04, 0x04, 0x00};
+DEFINE_AND_INSTANTIATE_ExitPeriodicInquiryModeReflectionTest(exit_periodic_inquiry_mode);
+
+std::vector<uint8_t> exit_periodic_inquiry_mode_complete = {0x0e, 0x04, 0x01, 0x04, 0x04, 0x00};
+DEFINE_AND_INSTANTIATE_ExitPeriodicInquiryModeCompleteReflectionTest(exit_periodic_inquiry_mode_complete);
+
+std::vector<uint8_t> pixel_3_xl_write_extended_inquiry_response{
+ 0x52, 0x0c, 0xf1, 0x01, 0x0b, 0x09, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x33, 0x20, 0x58, 0x4c, 0x19, 0x03, 0x05,
+ 0x11, 0x0a, 0x11, 0x0c, 0x11, 0x0e, 0x11, 0x12, 0x11, 0x15, 0x11, 0x16, 0x11, 0x1f, 0x11, 0x2d, 0x11, 0x2f, 0x11,
+ 0x00, 0x12, 0x32, 0x11, 0x01, 0x05, 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+std::vector<uint8_t> pixel_3_xl_write_extended_inquiry_response_no_uuids{
+ 0x52, 0x0c, 0xf1, 0x01, 0x0b, 0x09, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x33, 0x20, 0x58, 0x4c, 0x01, 0x03, 0x01,
+ 0x05, 0x81, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+
+std::vector<uint8_t> pixel_3_xl_write_extended_inquiry_response_no_uuids_just_eir{
+ pixel_3_xl_write_extended_inquiry_response_no_uuids.begin() + 4, // skip command, size, and fec_required
+ pixel_3_xl_write_extended_inquiry_response_no_uuids.end()};
+
+TEST(HciPacketsTest, testWriteExtendedInquiryResponse) {
+ std::shared_ptr<std::vector<uint8_t>> view_bytes =
+ std::make_shared<std::vector<uint8_t>>(pixel_3_xl_write_extended_inquiry_response);
+
+ PacketView<kLittleEndian> packet_bytes_view(view_bytes);
+ auto view = WriteExtendedInquiryResponseView::Create(CommandPacketView::Create(packet_bytes_view));
+ ASSERT_TRUE(view.IsValid());
+ auto gap_data = view.GetExtendedInquiryResponse();
+ ASSERT_GE(gap_data.size(), 4);
+ ASSERT_EQ(gap_data[0].data_type_, GapDataType::COMPLETE_LOCAL_NAME);
+ ASSERT_EQ(gap_data[0].data_.size(), 10);
+ ASSERT_EQ(gap_data[1].data_type_, GapDataType::COMPLETE_LIST_16_BIT_UUIDS);
+ ASSERT_EQ(gap_data[1].data_.size(), 24);
+ ASSERT_EQ(gap_data[2].data_type_, GapDataType::COMPLETE_LIST_32_BIT_UUIDS);
+ ASSERT_EQ(gap_data[2].data_.size(), 0);
+ ASSERT_EQ(gap_data[3].data_type_, GapDataType::COMPLETE_LIST_128_BIT_UUIDS);
+ ASSERT_EQ(gap_data[3].data_.size(), 128);
+
+ std::vector<GapData> no_padding{gap_data.begin(), gap_data.begin() + 4};
+ auto builder = WriteExtendedInquiryResponseBuilder::Create(view.GetFecRequired(), no_padding);
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ builder->Serialize(it);
+
+ EXPECT_EQ(packet_bytes->size(), view_bytes->size());
+ for (size_t i = 0; i < view_bytes->size(); i++) {
+ ASSERT_EQ(packet_bytes->at(i), view_bytes->at(i));
+ }
+}
+
+// TODO: Revisit reflection tests for EIR
+// DEFINE_AND_INSTANTIATE_WriteExtendedInquiryResponseReflectionTest(pixel_3_xl_write_extended_inquiry_response,
+// pixel_3_xl_write_extended_inquiry_response_no_uuids);
+
+std::vector<uint8_t> le_set_scan_parameters{
+ 0x0b, 0x20, 0x07, 0x01, 0x12, 0x00, 0x12, 0x00, 0x01, 0x00,
+};
+TEST(HciPacketsTest, testLeSetScanParameters) {
+ PacketView<kLittleEndian> packet_bytes_view(std::make_shared<std::vector<uint8_t>>(le_set_scan_parameters));
+ auto view =
+ LeSetScanParametersView::Create(LeScanningCommandView::Create(CommandPacketView::Create(packet_bytes_view)));
+
+ ASSERT(view.IsValid());
+ ASSERT_EQ(LeScanType::ACTIVE, view.GetLeScanType());
+ ASSERT_EQ(0x12, view.GetLeScanInterval());
+ ASSERT_EQ(0x12, view.GetLeScanWindow());
+ ASSERT_EQ(AddressType::RANDOM_DEVICE_ADDRESS, view.GetOwnAddressType());
+ ASSERT_EQ(LeSetScanningFilterPolicy::ACCEPT_ALL, view.GetScanningFilterPolicy());
+}
+
+DEFINE_AND_INSTANTIATE_LeSetScanParametersReflectionTest(le_set_scan_parameters);
+
+std::vector<uint8_t> le_set_scan_enable{
+ 0x0c, 0x20, 0x02, 0x01, 0x00,
+};
+TEST(HciPacketsTest, testLeSetScanEnable) {
+ PacketView<kLittleEndian> packet_bytes_view(std::make_shared<std::vector<uint8_t>>(le_set_scan_enable));
+ auto view = LeSetScanEnableView::Create(LeScanningCommandView::Create(CommandPacketView::Create(packet_bytes_view)));
+
+ ASSERT(view.IsValid());
+ ASSERT_EQ(Enable::ENABLED, view.GetLeScanEnable());
+ ASSERT_EQ(Enable::DISABLED, view.GetFilterDuplicates());
+}
+
+DEFINE_AND_INSTANTIATE_LeSetScanEnableReflectionTest(le_set_scan_enable);
+
+std::vector<uint8_t> le_get_vendor_capabilities{
+ 0x53,
+ 0xfd,
+ 0x00,
+};
+TEST(HciPacketsTest, testLeGetVendorCapabilities) {
+ PacketView<kLittleEndian> packet_bytes_view(std::make_shared<std::vector<uint8_t>>(le_get_vendor_capabilities));
+ auto view =
+ LeGetVendorCapabilitiesView::Create(VendorCommandView::Create(CommandPacketView::Create(packet_bytes_view)));
+
+ ASSERT(view.IsValid());
+}
+
+DEFINE_AND_INSTANTIATE_LeGetVendorCapabilitiesReflectionTest(le_get_vendor_capabilities);
+
+std::vector<uint8_t> le_get_vendor_capabilities_complete{
+ 0x0e, 0x0c, 0x01, 0x53, 0xfd, 0x00, 0x05, 0x01, 0x00, 0x04, 0x80, 0x01, 0x10, 0x01,
+};
+TEST(HciPacketsTest, testLeGetVendorCapabilitiesComplete) {
+ PacketView<kLittleEndian> packet_bytes_view(
+ std::make_shared<std::vector<uint8_t>>(le_get_vendor_capabilities_complete));
+ auto view = LeGetVendorCapabilitiesCompleteView::Create(
+ CommandCompleteView::Create(EventPacketView::Create(packet_bytes_view)));
+
+ ASSERT(view.IsValid());
+ auto base_capabilities = view.GetBaseVendorCapabilities();
+ ASSERT_EQ(5, base_capabilities.max_advt_instances_);
+ ASSERT_EQ(1, base_capabilities.offloaded_resolution_of_private_address_);
+ ASSERT_EQ(1024, base_capabilities.total_scan_results_storage_);
+ ASSERT_EQ(128, base_capabilities.max_irk_list_sz_);
+ ASSERT_EQ(1, base_capabilities.filtering_support_);
+ ASSERT_EQ(16, base_capabilities.max_filter_);
+ ASSERT_EQ(1, base_capabilities.activity_energy_info_support_);
+}
+
+DEFINE_AND_INSTANTIATE_LeGetVendorCapabilitiesCompleteReflectionTest(le_get_vendor_capabilities_complete);
+
+std::vector<uint8_t> le_set_extended_scan_parameters{
+ 0x41, 0x20, 0x08, 0x01, 0x00, 0x01, 0x01, 0x12, 0x00, 0x12, 0x00,
+};
+
+TEST(HciPacketsTest, testLeSetExtendedScanParameters) {
+ PacketView<kLittleEndian> packet_bytes_view(std::make_shared<std::vector<uint8_t>>(le_set_extended_scan_parameters));
+ auto view = LeSetExtendedScanParametersView::Create(
+ LeScanningCommandView::Create(CommandPacketView::Create(packet_bytes_view)));
+
+ ASSERT(view.IsValid());
+ ASSERT_EQ(1, view.GetScanningPhys());
+ auto params = view.GetParameters();
+ ASSERT_EQ(1, params.size());
+ ASSERT_EQ(LeScanType::ACTIVE, params[0].le_scan_type_);
+ ASSERT_EQ(18, params[0].le_scan_interval_);
+ ASSERT_EQ(18, params[0].le_scan_window_);
+}
+
+std::vector<uint8_t> le_set_extended_scan_parameters_6553{
+ 0x41, 0x20, 0x08, 0x01, 0x00, 0x01, 0x01, 0x99, 0x19, 0x99, 0x19,
+};
+
+TEST(HciPacketsTest, testLeSetExtendedScanParameters_6553) {
+ PacketView<kLittleEndian> packet_bytes_view(
+ std::make_shared<std::vector<uint8_t>>(le_set_extended_scan_parameters_6553));
+ auto view = LeSetExtendedScanParametersView::Create(
+ LeScanningCommandView::Create(CommandPacketView::Create(packet_bytes_view)));
+
+ ASSERT(view.IsValid());
+ ASSERT_EQ(1, view.GetScanningPhys());
+ auto params = view.GetParameters();
+ ASSERT_EQ(1, params.size());
+ ASSERT_EQ(LeScanType::ACTIVE, params[0].le_scan_type_);
+ ASSERT_EQ(6553, params[0].le_scan_interval_);
+ ASSERT_EQ(6553, params[0].le_scan_window_);
+}
+
+DEFINE_AND_INSTANTIATE_LeSetExtendedScanParametersReflectionTest(le_set_extended_scan_parameters,
+ le_set_extended_scan_parameters_6553);
+
+std::vector<uint8_t> le_set_extended_scan_parameters_complete{
+ 0x0e, 0x04, 0x01, 0x41, 0x20, 0x00,
+};
+DEFINE_AND_INSTANTIATE_LeSetExtendedScanParametersCompleteReflectionTest(le_set_extended_scan_parameters_complete);
+
+std::vector<uint8_t> le_set_extended_scan_enable{
+ 0x42, 0x20, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+TEST(HciPacketsTest, testLeSetExtendedScanEnable) {
+ PacketView<kLittleEndian> packet_bytes_view(std::make_shared<std::vector<uint8_t>>(le_set_extended_scan_enable));
+ auto view =
+ LeSetExtendedScanEnableView::Create(LeScanningCommandView::Create(CommandPacketView::Create(packet_bytes_view)));
+
+ ASSERT(view.IsValid());
+ ASSERT_EQ(FilterDuplicates::DISABLED, view.GetFilterDuplicates());
+ ASSERT_EQ(Enable::ENABLED, view.GetEnable());
+ ASSERT_EQ(0, view.GetDuration());
+ ASSERT_EQ(0, view.GetPeriod());
+}
+
+std::vector<uint8_t> le_set_extended_scan_enable_disable{
+ 0x42, 0x20, 0x06, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+};
+
+TEST(HciPacketsTest, testLeSetExtendedScanEnableDisable) {
+ PacketView<kLittleEndian> packet_bytes_view(
+ std::make_shared<std::vector<uint8_t>>(le_set_extended_scan_enable_disable));
+ auto view =
+ LeSetExtendedScanEnableView::Create(LeScanningCommandView::Create(CommandPacketView::Create(packet_bytes_view)));
+
+ ASSERT(view.IsValid());
+ ASSERT_EQ(FilterDuplicates::ENABLED, view.GetFilterDuplicates());
+ ASSERT_EQ(Enable::DISABLED, view.GetEnable());
+ ASSERT_EQ(0, view.GetDuration());
+ ASSERT_EQ(0, view.GetPeriod());
+}
+
+DEFINE_AND_INSTANTIATE_LeSetExtendedScanEnableReflectionTest(le_set_extended_scan_enable,
+ le_set_extended_scan_enable_disable);
+
+std::vector<uint8_t> le_set_extended_scan_enable_complete{
+ 0x0e, 0x04, 0x01, 0x42, 0x20, 0x00,
+};
+DEFINE_AND_INSTANTIATE_LeSetExtendedScanEnableCompleteReflectionTest(le_set_extended_scan_enable_complete);
+
+std::vector<uint8_t> le_extended_create_connection = {
+ 0x43, 0x20, 0x2a, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x08,
+ 0x30, 0x00, 0x18, 0x00, 0x28, 0x00, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x30, 0x00, 0x18, 0x00, 0x28, 0x00, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00, 0x00, 0x00};
+DEFINE_AND_INSTANTIATE_LeExtendedCreateConnectionReflectionTest(le_extended_create_connection);
+
+TEST(HciPacketsTest, testLeExtendedCreateConnection) {
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+ std::make_shared<std::vector<uint8_t>>(le_extended_create_connection);
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = LeExtendedCreateConnectionView::Create(
+ LeConnectionManagementCommandView::Create(CommandPacketView::Create(packet_bytes_view)));
+ ASSERT_TRUE(view.IsValid());
+}
+
+std::vector<uint8_t> le_set_extended_advertising_random_address = {
+ 0x35, 0x20, 0x07, 0x00, 0x77, 0x58, 0xeb, 0xd3, 0x1c, 0x6e,
+};
+
+TEST(HciPacketsTest, testLeSetExtendedAdvertisingRandomAddress) {
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+ std::make_shared<std::vector<uint8_t>>(le_set_extended_advertising_random_address);
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = LeSetExtendedAdvertisingRandomAddressView::Create(
+ LeAdvertisingCommandView::Create(CommandPacketView::Create(packet_bytes_view)));
+ ASSERT_TRUE(view.IsValid());
+ uint8_t random_address_bytes[] = {0x77, 0x58, 0xeb, 0xd3, 0x1c, 0x6e};
+ ASSERT_EQ(0, view.GetAdvertisingHandle());
+ ASSERT_EQ(Address(random_address_bytes), view.GetAdvertisingRandomAddress());
+}
+DEFINE_AND_INSTANTIATE_LeSetExtendedAdvertisingRandomAddressReflectionTest(le_set_extended_advertising_random_address);
+
+std::vector<uint8_t> le_set_extended_advertising_random_address_complete{
+ 0x0e, 0x04, 0x01, 0x35, 0x20, 0x00,
+};
+DEFINE_AND_INSTANTIATE_LeSetExtendedAdvertisingRandomAddressCompleteReflectionTest(
+ le_set_extended_advertising_random_address_complete);
+
+std::vector<uint8_t> le_set_extended_advertising_data{
+ 0x37, 0x20, 0x12, 0x00, 0x03, 0x01, 0x0e, 0x02, 0x01, 0x02, 0x0a,
+ 0x09, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x33, 0x20, 0x58,
+};
+TEST(HciPacketsTest, testLeSetExtendedAdvertisingData) {
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+ std::make_shared<std::vector<uint8_t>>(le_set_extended_advertising_data);
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = LeSetExtendedAdvertisingDataRawView::Create(
+ LeAdvertisingCommandView::Create(CommandPacketView::Create(packet_bytes_view)));
+ ASSERT_TRUE(view.IsValid());
+ ASSERT_EQ(0, view.GetAdvertisingHandle());
+ ASSERT_EQ(Operation::COMPLETE_ADVERTISMENT, view.GetOperation());
+ ASSERT_EQ(FragmentPreference::CONTROLLER_SHOULD_NOT, view.GetFragmentPreference());
+ std::vector<uint8_t> advertising_data{
+ 0x02, 0x01, 0x02, 0x0a, 0x09, 0x50, 0x69, 0x78, 0x65, 0x6c, 0x20, 0x33, 0x20, 0x58,
+ };
+ ASSERT_EQ(advertising_data, view.GetAdvertisingData());
+}
+
+DEFINE_AND_INSTANTIATE_LeSetExtendedAdvertisingDataRawReflectionTest(le_set_extended_advertising_data);
+
+std::vector<uint8_t> le_set_extended_advertising_data_complete{
+ 0x0e, 0x04, 0x01, 0x37, 0x20, 0x00,
+};
+DEFINE_AND_INSTANTIATE_LeSetExtendedAdvertisingDataCompleteReflectionTest(le_set_extended_advertising_data_complete);
+
+std::vector<uint8_t> le_set_extended_advertising_parameters_set_0{
+ 0x36, 0x20, 0x19, 0x00, 0x13, 0x00, 0x90, 0x01, 0x00, 0xc2, 0x01, 0x00, 0x07, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x01, 0x00, 0x00 /*0x01*/, 0x01, 0x00,
+};
+TEST(HciPacketsTest, testLeSetExtendedAdvertisingParametersLegacySet0) {
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+ std::make_shared<std::vector<uint8_t>>(le_set_extended_advertising_parameters_set_0);
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = LeSetExtendedAdvertisingLegacyParametersView::Create(
+ LeAdvertisingCommandView::Create(CommandPacketView::Create(packet_bytes_view)));
+ ASSERT_TRUE(view.IsValid());
+ ASSERT_EQ(0, view.GetAdvertisingHandle());
+ ASSERT_EQ(400, view.GetPrimaryAdvertisingIntervalMin());
+ ASSERT_EQ(450, view.GetPrimaryAdvertisingIntervalMax());
+ ASSERT_EQ(0x7, view.GetPrimaryAdvertisingChannelMap());
+ ASSERT_EQ(OwnAddressType::RANDOM_DEVICE_ADDRESS, view.GetOwnAddressType());
+ ASSERT_EQ(PeerAddressType::PUBLIC_DEVICE_OR_IDENTITY_ADDRESS, view.GetPeerAddressType());
+ ASSERT_EQ(Address::kEmpty, view.GetPeerAddress());
+ ASSERT_EQ(AdvertisingFilterPolicy::ALL_DEVICES, view.GetAdvertisingFilterPolicy());
+ ASSERT_EQ(PrimaryPhyType::LE_1M, view.GetPrimaryAdvertisingPhy());
+ ASSERT_EQ(1, view.GetAdvertisingSid());
+ ASSERT_EQ(Enable::DISABLED, view.GetScanRequestNotificationEnable());
+}
+
+std::vector<uint8_t> le_set_extended_advertising_parameters_set_1{
+ 0x36, 0x20, 0x19, 0x01, 0x13, 0x00, 0x90, 0x01, 0x00, 0xc2, 0x01, 0x00, 0x07, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf9, 0x01, 0x00, 0x00 /*0x01*/, 0x01, 0x00,
+};
+TEST(HciPacketsTest, testLeSetExtendedAdvertisingParametersSet1) {
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+ std::make_shared<std::vector<uint8_t>>(le_set_extended_advertising_parameters_set_1);
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = LeSetExtendedAdvertisingLegacyParametersView::Create(
+ LeAdvertisingCommandView::Create(CommandPacketView::Create(packet_bytes_view)));
+ ASSERT_TRUE(view.IsValid());
+ ASSERT_EQ(1, view.GetAdvertisingHandle());
+ ASSERT_EQ(400, view.GetPrimaryAdvertisingIntervalMin());
+ ASSERT_EQ(450, view.GetPrimaryAdvertisingIntervalMax());
+ ASSERT_EQ(0x7, view.GetPrimaryAdvertisingChannelMap());
+ ASSERT_EQ(OwnAddressType::RANDOM_DEVICE_ADDRESS, view.GetOwnAddressType());
+ ASSERT_EQ(PeerAddressType::PUBLIC_DEVICE_OR_IDENTITY_ADDRESS, view.GetPeerAddressType());
+ ASSERT_EQ(Address::kEmpty, view.GetPeerAddress());
+ ASSERT_EQ(AdvertisingFilterPolicy::ALL_DEVICES, view.GetAdvertisingFilterPolicy());
+ ASSERT_EQ(PrimaryPhyType::LE_1M, view.GetPrimaryAdvertisingPhy());
+ ASSERT_EQ(1, view.GetAdvertisingSid());
+ ASSERT_EQ(Enable::DISABLED, view.GetScanRequestNotificationEnable());
+}
+
+DEFINE_AND_INSTANTIATE_LeSetExtendedAdvertisingLegacyParametersReflectionTest(
+ le_set_extended_advertising_parameters_set_0, le_set_extended_advertising_parameters_set_1);
+
+std::vector<uint8_t> le_set_extended_advertising_parameters_complete{0x0e, 0x05, 0x01, 0x36, 0x20, 0x00, 0xf5};
+TEST(HciPacketsTest, testLeSetExtendedAdvertisingParametersComplete) {
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+ std::make_shared<std::vector<uint8_t>>(le_set_extended_advertising_parameters_complete);
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = LeSetExtendedAdvertisingParametersCompleteView::Create(
+ CommandCompleteView::Create(EventPacketView::Create(packet_bytes_view)));
+ ASSERT_TRUE(view.IsValid());
+ ASSERT_EQ(static_cast<uint8_t>(-11), view.GetSelectedTxPower());
+}
+
+DEFINE_AND_INSTANTIATE_LeSetExtendedAdvertisingParametersCompleteReflectionTest(
+ le_set_extended_advertising_parameters_complete);
+
+std::vector<uint8_t> le_remove_advertising_set_1{
+ 0x3c,
+ 0x20,
+ 0x01,
+ 0x01,
+};
+TEST(HciPacketsTest, testLeRemoveAdvertisingSet1) {
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+ std::make_shared<std::vector<uint8_t>>(le_remove_advertising_set_1);
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = LeRemoveAdvertisingSetView::Create(
+ LeAdvertisingCommandView::Create(CommandPacketView::Create(packet_bytes_view)));
+ ASSERT_TRUE(view.IsValid());
+ ASSERT_EQ(1, view.GetAdvertisingHandle());
+}
+
+DEFINE_AND_INSTANTIATE_LeRemoveAdvertisingSetReflectionTest(le_remove_advertising_set_1);
+
+std::vector<uint8_t> le_remove_advertising_set_complete{
+ 0x0e, 0x04, 0x01, 0x3c, 0x20, 0x00,
+};
+DEFINE_AND_INSTANTIATE_LeRemoveAdvertisingSetCompleteReflectionTest(le_remove_advertising_set_complete);
+
+std::vector<uint8_t> le_set_extended_advertising_disable_1{
+ 0x39, 0x20, 0x06, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00,
+};
+TEST(HciPacketsTest, testLeSetExtendedAdvertisingDisable1) {
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+ std::make_shared<std::vector<uint8_t>>(le_set_extended_advertising_disable_1);
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = LeSetExtendedAdvertisingDisableView::Create(
+ LeAdvertisingCommandView::Create(CommandPacketView::Create(packet_bytes_view)));
+ ASSERT_TRUE(view.IsValid());
+ auto disabled_set = view.GetDisabledSets();
+ ASSERT_EQ(1, disabled_set.size());
+ ASSERT_EQ(1, disabled_set[0].advertising_handle_);
+}
+
+DEFINE_AND_INSTANTIATE_LeSetExtendedAdvertisingDisableReflectionTest(le_set_extended_advertising_disable_1);
+
+std::vector<uint8_t> le_set_extended_advertising_enable_complete{
+ 0x0e, 0x04, 0x01, 0x39, 0x20, 0x00,
+};
+DEFINE_AND_INSTANTIATE_LeSetExtendedAdvertisingEnableCompleteReflectionTest(
+ le_set_extended_advertising_enable_complete);
+
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/le_advertising_interface.h b/gd/hci/le_advertising_interface.h
new file mode 100644
index 0000000..f915c02
--- /dev/null
+++ b/gd/hci/le_advertising_interface.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "common/callback.h"
+#include "hci/hci_packets.h"
+#include "os/handler.h"
+#include "os/utils.h"
+
+namespace bluetooth {
+namespace hci {
+
+class LeAdvertisingInterface {
+ public:
+ LeAdvertisingInterface() = default;
+ virtual ~LeAdvertisingInterface() = default;
+ DISALLOW_COPY_AND_ASSIGN(LeAdvertisingInterface);
+
+ virtual void EnqueueCommand(std::unique_ptr<LeAdvertisingCommandBuilder> command,
+ common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) = 0;
+
+ virtual void EnqueueCommand(std::unique_ptr<LeAdvertisingCommandBuilder> command,
+ common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) = 0;
+
+ static constexpr hci::SubeventCode LeAdvertisingEvents[] = {
+ hci::SubeventCode::SCAN_REQUEST_RECEIVED,
+ hci::SubeventCode::ADVERTISING_SET_TERMINATED,
+ };
+};
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/le_advertising_manager.cc b/gd/hci/le_advertising_manager.cc
new file mode 100644
index 0000000..3362ea3
--- /dev/null
+++ b/gd/hci/le_advertising_manager.cc
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2019 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 <memory>
+#include <mutex>
+
+#include "hci/controller.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "hci/le_advertising_interface.h"
+#include "hci/le_advertising_manager.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace hci {
+
+const ModuleFactory LeAdvertisingManager::Factory = ModuleFactory([]() { return new LeAdvertisingManager(); });
+
+enum class AdvertisingApiType {
+ LE_4_0 = 1,
+ ANDROID_HCI = 2,
+ LE_5_0 = 3,
+};
+
+struct Advertiser {
+ os::Handler* handler;
+ common::Callback<void(Address, AddressType)> scan_callback;
+ common::Callback<void(ErrorCode, uint8_t, uint8_t)> set_terminated_callback;
+};
+
+struct LeAdvertisingManager::impl {
+ impl(Module* module) : module_(module), le_advertising_interface_(nullptr), num_instances_(0) {}
+
+ void start(os::Handler* handler, hci::HciLayer* hci_layer, hci::Controller* controller) {
+ module_handler_ = handler;
+ hci_layer_ = hci_layer;
+ controller_ = controller;
+ le_advertising_interface_ = hci_layer_->GetLeAdvertisingInterface(
+ common::Bind(&LeAdvertisingManager::impl::handle_event, common::Unretained(this)), module_handler_);
+ num_instances_ = controller_->GetControllerLeNumberOfSupportedAdverisingSets();
+ if (controller_->IsSupported(hci::OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS)) {
+ advertising_api_type_ = AdvertisingApiType::LE_5_0;
+ } else if (controller_->IsSupported(hci::OpCode::LE_MULTI_ADVT)) {
+ advertising_api_type_ = AdvertisingApiType::ANDROID_HCI;
+ } else {
+ advertising_api_type_ = AdvertisingApiType::LE_4_0;
+ }
+ }
+
+ size_t GetNumberOfAdvertisingInstances() const {
+ return num_instances_;
+ }
+
+ void handle_event(LeMetaEventView event) {
+ switch (event.GetSubeventCode()) {
+ case hci::SubeventCode::SCAN_REQUEST_RECEIVED:
+ handle_scan_request(LeScanRequestReceivedView::Create(event));
+ break;
+ case hci::SubeventCode::ADVERTISING_SET_TERMINATED:
+ handle_set_terminated(LeAdvertisingSetTerminatedView::Create(event));
+ break;
+ default:
+ LOG_INFO("Unknown subevent in scanner %s", hci::SubeventCodeText(event.GetSubeventCode()).c_str());
+ }
+ }
+
+ void handle_scan_request(LeScanRequestReceivedView event_view) {
+ if (!event_view.IsValid()) {
+ LOG_INFO("Dropping invalid scan request event");
+ return;
+ }
+ registered_handler_->Post(
+ common::BindOnce(scan_callback_, event_view.GetScannerAddress(), event_view.GetScannerAddressType()));
+ }
+
+ void handle_set_terminated(LeAdvertisingSetTerminatedView event_view) {
+ if (!event_view.IsValid()) {
+ LOG_INFO("Dropping invalid advertising event");
+ return;
+ }
+ registered_handler_->Post(common::BindOnce(set_terminated_callback_, event_view.GetStatus(),
+ event_view.GetAdvertisingHandle(),
+ event_view.GetNumCompletedExtendedAdvertisingEvents()));
+ }
+
+ AdvertiserId allocate_advertiser() {
+ AdvertiserId id = 0;
+ {
+ std::unique_lock lock(id_mutex_);
+ while (id < num_instances_ && advertising_sets_.count(id) != 0) {
+ id++;
+ }
+ }
+ if (id == num_instances_) {
+ return kInvalidId;
+ }
+ return id;
+ }
+
+ void remove_advertiser(AdvertiserId id) {
+ std::unique_lock lock(id_mutex_);
+ if (advertising_sets_.count(id) == 0) {
+ return;
+ }
+ advertising_sets_.erase(id);
+ }
+
+ void create_advertiser(AdvertiserId id, const AdvertisingConfig& config,
+ const common::Callback<void(Address, AddressType)>& scan_callback,
+ const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback,
+ os::Handler* handler) {
+ advertising_sets_[id].scan_callback = scan_callback;
+ advertising_sets_[id].set_terminated_callback = set_terminated_callback;
+ advertising_sets_[id].handler = handler;
+ switch (advertising_api_type_) {
+ case (AdvertisingApiType::LE_4_0):
+ le_advertising_interface_->EnqueueCommand(
+ hci::LeSetAdvertisingParametersBuilder::Create(
+ config.interval_min, config.interval_max, config.event_type, config.address_type,
+ config.peer_address_type, config.peer_address, config.channel_map, config.filter_policy),
+ common::BindOnce(impl::check_status<LeSetAdvertisingParametersCompleteView>), module_handler_);
+ le_advertising_interface_->EnqueueCommand(hci::LeSetRandomAddressBuilder::Create(config.random_address),
+ common::BindOnce(impl::check_status<LeSetRandomAddressCompleteView>),
+ module_handler_);
+ if (!config.scan_response.empty()) {
+ le_advertising_interface_->EnqueueCommand(
+ hci::LeSetScanResponseDataBuilder::Create(config.scan_response),
+ common::BindOnce(impl::check_status<LeSetScanResponseDataCompleteView>), module_handler_);
+ }
+ le_advertising_interface_->EnqueueCommand(
+ hci::LeSetAdvertisingDataBuilder::Create(config.advertisement),
+ common::BindOnce(impl::check_status<LeSetAdvertisingDataCompleteView>), module_handler_);
+ le_advertising_interface_->EnqueueCommand(
+ hci::LeSetAdvertisingEnableBuilder::Create(Enable::ENABLED),
+ common::BindOnce(impl::check_status<LeSetAdvertisingEnableCompleteView>), module_handler_);
+ break;
+ case (AdvertisingApiType::ANDROID_HCI):
+ le_advertising_interface_->EnqueueCommand(
+ hci::LeMultiAdvtParamBuilder::Create(config.interval_min, config.interval_max, config.event_type,
+ config.address_type, config.peer_address_type, config.peer_address,
+ config.channel_map, config.filter_policy, id, config.tx_power),
+ common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), module_handler_);
+ le_advertising_interface_->EnqueueCommand(hci::LeMultiAdvtSetDataBuilder::Create(config.advertisement, id),
+ common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>),
+ module_handler_);
+ if (!config.scan_response.empty()) {
+ le_advertising_interface_->EnqueueCommand(
+ hci::LeMultiAdvtSetScanRespBuilder::Create(config.scan_response, id),
+ common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), module_handler_);
+ }
+ le_advertising_interface_->EnqueueCommand(
+ hci::LeMultiAdvtSetRandomAddrBuilder::Create(config.random_address, id),
+ common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>), module_handler_);
+ le_advertising_interface_->EnqueueCommand(hci::LeMultiAdvtSetEnableBuilder::Create(Enable::ENABLED, id),
+ common::BindOnce(impl::check_status<LeMultiAdvtCompleteView>),
+ module_handler_);
+ break;
+ case (AdvertisingApiType::LE_5_0): {
+ ExtendedAdvertisingConfig new_config;
+ AdvertisingConfig* base_config_ptr = &new_config;
+ *(base_config_ptr) = config;
+ create_extended_advertiser(id, new_config, scan_callback, set_terminated_callback, handler);
+ } break;
+ }
+ }
+
+ void create_extended_advertiser(AdvertiserId id, const ExtendedAdvertisingConfig& config,
+ const common::Callback<void(Address, AddressType)>& scan_callback,
+ const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback,
+ os::Handler* handler) {
+ if (advertising_api_type_ != AdvertisingApiType::LE_5_0) {
+ create_advertiser(id, config, scan_callback, set_terminated_callback, handler);
+ return;
+ }
+ LOG_ALWAYS_FATAL("LE_SET_EXTENDED_ADVERTISING_PARAMETERS isn't implemented.");
+
+ /*
+ le_advertising_interface_->EnqueueCommand(hci::LeSetExtendedAdvertisingParametersBuilder::Create(config.interval_min,
+ config.interval_max, config.event_type, config.address_type, config.peer_address_type, config.peer_address,
+ config.channel_map, config.filter_policy, id, config.tx_power), common::BindOnce(impl::check_status),
+ module_handler_);
+ */
+ advertising_sets_[id].scan_callback = scan_callback;
+ advertising_sets_[id].set_terminated_callback = set_terminated_callback;
+ advertising_sets_[id].handler = handler;
+ }
+
+ void stop_advertising(AdvertiserId advertising_set) {
+ if (advertising_sets_.find(advertising_set) == advertising_sets_.end()) {
+ LOG_INFO("Unknown advertising set %u", advertising_set);
+ return;
+ }
+ le_advertising_interface_->EnqueueCommand(hci::LeSetAdvertisingEnableBuilder::Create(Enable::DISABLED),
+ common::BindOnce(impl::check_status<LeSetAdvertisingEnableCompleteView>),
+ module_handler_);
+ std::unique_lock lock(id_mutex_);
+ advertising_sets_.erase(advertising_set);
+ }
+
+ common::Callback<void(Address, AddressType)> scan_callback_;
+ common::Callback<void(ErrorCode, uint8_t, uint8_t)> set_terminated_callback_;
+ os::Handler* registered_handler_{nullptr};
+ Module* module_;
+ os::Handler* module_handler_;
+ hci::HciLayer* hci_layer_;
+ hci::Controller* controller_;
+ hci::LeAdvertisingInterface* le_advertising_interface_;
+ std::map<AdvertiserId, Advertiser> advertising_sets_;
+
+ std::mutex id_mutex_;
+ size_t num_instances_;
+
+ AdvertisingApiType advertising_api_type_{0};
+
+ template <class View>
+ static void check_status(CommandCompleteView view) {
+ ASSERT(view.IsValid());
+ auto status_view = View::Create(view);
+ ASSERT(status_view.IsValid());
+ if (status_view.GetStatus() != ErrorCode::SUCCESS) {
+ LOG_INFO("SetEnable returned status %s", ErrorCodeText(status_view.GetStatus()).c_str());
+ }
+ }
+};
+
+LeAdvertisingManager::LeAdvertisingManager() {
+ pimpl_ = std::make_unique<impl>(this);
+}
+
+void LeAdvertisingManager::ListDependencies(ModuleList* list) {
+ list->add<hci::HciLayer>();
+ list->add<hci::Controller>();
+}
+
+void LeAdvertisingManager::Start() {
+ pimpl_->start(GetHandler(), GetDependency<hci::HciLayer>(), GetDependency<hci::Controller>());
+}
+
+void LeAdvertisingManager::Stop() {
+ pimpl_.reset();
+}
+
+std::string LeAdvertisingManager::ToString() const {
+ return "Le Advertising Manager";
+}
+
+size_t LeAdvertisingManager::GetNumberOfAdvertisingInstances() const {
+ return pimpl_->GetNumberOfAdvertisingInstances();
+}
+
+AdvertiserId LeAdvertisingManager::CreateAdvertiser(
+ const AdvertisingConfig& config, const common::Callback<void(Address, AddressType)>& scan_callback,
+ const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback, os::Handler* handler) {
+ if (config.peer_address == Address::kEmpty) {
+ if (config.address_type == hci::AddressType::PUBLIC_IDENTITY_ADDRESS ||
+ config.address_type == hci::AddressType::RANDOM_IDENTITY_ADDRESS) {
+ LOG_WARN("Peer address can not be empty");
+ return kInvalidId;
+ }
+ if (config.event_type == hci::AdvertisingEventType::ADV_DIRECT_IND ||
+ config.event_type == hci::AdvertisingEventType::ADV_DIRECT_IND_LOW) {
+ LOG_WARN("Peer address can not be empty for directed advertising");
+ return kInvalidId;
+ }
+ }
+ AdvertiserId id = pimpl_->allocate_advertiser();
+ if (id == kInvalidId) {
+ return id;
+ }
+ GetHandler()->Post(common::BindOnce(&impl::create_advertiser, common::Unretained(pimpl_.get()), id, config,
+ scan_callback, set_terminated_callback, handler));
+ return id;
+}
+
+AdvertiserId LeAdvertisingManager::CreateAdvertiser(
+ const ExtendedAdvertisingConfig& config, const common::Callback<void(Address, AddressType)>& scan_callback,
+ const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback, os::Handler* handler) {
+ if (config.directed) {
+ if (config.peer_address == Address::kEmpty) {
+ LOG_INFO("Peer address can not be empty for directed advertising");
+ return kInvalidId;
+ }
+ }
+ if (config.channel_map == 0) {
+ LOG_INFO("At least one channel must be set in the map");
+ return kInvalidId;
+ }
+ if (!config.legacy_pdus) {
+ if (config.connectable && config.scannable) {
+ LOG_INFO("Extended advertising PDUs can not be connectable and scannable");
+ return kInvalidId;
+ }
+ if (config.high_duty_directed_connectable) {
+ LOG_INFO("Extended advertising PDUs can not be high duty cycle");
+ return kInvalidId;
+ }
+ }
+ if (config.interval_min > config.interval_max) {
+ LOG_INFO("Advertising interval: min (%hu) > max (%hu)", config.interval_min, config.interval_max);
+ return kInvalidId;
+ }
+ AdvertiserId id = pimpl_->allocate_advertiser();
+ if (id == kInvalidId) {
+ return id;
+ }
+ GetHandler()->Post(common::BindOnce(&impl::create_extended_advertiser, common::Unretained(pimpl_.get()), id, config,
+ scan_callback, set_terminated_callback, handler));
+ return id;
+}
+
+void LeAdvertisingManager::RemoveAdvertiser(AdvertiserId id) {
+ pimpl_->remove_advertiser(id);
+}
+
+} // namespace hci
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/hci/le_advertising_manager.h b/gd/hci/le_advertising_manager.h
new file mode 100644
index 0000000..4bbcfc1
--- /dev/null
+++ b/gd/hci/le_advertising_manager.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <memory>
+
+#include "hci/hci_packets.h"
+#include "module.h"
+
+namespace bluetooth {
+namespace hci {
+
+class AdvertisingConfig {
+ public:
+ std::vector<GapData> advertisement;
+ std::vector<GapData> scan_response;
+ Address random_address;
+ uint16_t interval_min;
+ uint16_t interval_max;
+ AdvertisingEventType event_type;
+ AddressType address_type;
+ PeerAddressType peer_address_type;
+ Address peer_address;
+ uint8_t channel_map;
+ AdvertisingFilterPolicy filter_policy;
+ uint8_t tx_power; // -127 to +20 (0x7f is no preference)
+};
+
+class ExtendedAdvertisingConfig : public AdvertisingConfig {
+ public:
+ bool connectable;
+ bool scannable;
+ bool directed;
+ bool high_duty_directed_connectable;
+ bool legacy_pdus;
+ bool anonymous;
+ bool include_tx_power;
+ bool use_le_coded_phy; // Primary advertisement PHY is LE Coded
+ uint8_t secondary_max_skip; // maximum advertising events to be skipped, 0x0 send AUX_ADV_IND prior ot the next event
+ uint8_t secondary_advertising_phy; // 1 = 1M, 2 = 2M, 3 = coded
+ uint8_t sid;
+ bool enable_scan_request_notifications;
+};
+
+using AdvertiserId = int32_t;
+
+class LeAdvertisingManager : public bluetooth::Module {
+ public:
+ static constexpr AdvertiserId kInvalidId = -1;
+ LeAdvertisingManager();
+
+ size_t GetNumberOfAdvertisingInstances() const;
+
+ // Return -1 if the advertiser was not created, otherwise the advertiser ID.
+ AdvertiserId CreateAdvertiser(const AdvertisingConfig& config,
+ const common::Callback<void(Address, AddressType)>& scan_callback,
+ const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback,
+ os::Handler* handler);
+ AdvertiserId CreateAdvertiser(const ExtendedAdvertisingConfig& config,
+ const common::Callback<void(Address, AddressType)>& scan_callback,
+ const common::Callback<void(ErrorCode, uint8_t, uint8_t)>& set_terminated_callback,
+ os::Handler* handler);
+
+ void RemoveAdvertiser(AdvertiserId id);
+
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override;
+
+ void Start() override;
+
+ void Stop() override;
+
+ std::string ToString() const override;
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+ DISALLOW_COPY_AND_ASSIGN(LeAdvertisingManager);
+};
+
+} // namespace hci
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/hci/le_advertising_manager_test.cc b/gd/hci/le_advertising_manager_test.cc
new file mode 100644
index 0000000..c4f40ad
--- /dev/null
+++ b/gd/hci/le_advertising_manager_test.cc
@@ -0,0 +1,356 @@
+/*
+ * Copyright 2019 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 "hci/le_advertising_manager.h"
+
+#include <algorithm>
+#include <chrono>
+#include <future>
+#include <map>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "common/bind.h"
+#include "hci/address.h"
+#include "hci/controller.h"
+#include "hci/hci_layer.h"
+#include "os/thread.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace hci {
+namespace {
+
+using packet::kLittleEndian;
+using packet::PacketView;
+using packet::RawBuilder;
+
+PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+ auto bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter i(*bytes);
+ bytes->reserve(packet->size());
+ packet->Serialize(i);
+ return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+class TestController : public Controller {
+ public:
+ bool IsSupported(OpCode op_code) const override {
+ return supported_opcodes_.count(op_code) == 1;
+ }
+
+ void AddSupported(OpCode op_code) {
+ supported_opcodes_.insert(op_code);
+ }
+
+ uint16_t GetControllerLeNumberOfSupportedAdverisingSets() const override {
+ return num_advertisers;
+ }
+
+ uint16_t num_advertisers{0};
+
+ protected:
+ void Start() override {}
+ void Stop() override {}
+ void ListDependencies(ModuleList* list) override {}
+
+ private:
+ std::set<OpCode> supported_opcodes_{};
+};
+
+class TestHciLayer : public HciLayer {
+ public:
+ TestHciLayer() {
+ RegisterEventHandler(EventCode::COMMAND_COMPLETE,
+ base::Bind(&TestHciLayer::CommandCompleteCallback, common::Unretained(this)), nullptr);
+ RegisterEventHandler(EventCode::COMMAND_STATUS,
+ base::Bind(&TestHciLayer::CommandStatusCallback, common::Unretained(this)), nullptr);
+ }
+
+ void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+ common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) override {
+ command_queue_.push_back(std::move(command));
+ command_status_callbacks.push_back(std::move(on_status));
+ if (command_promise_ != nullptr) {
+ command_promise_->set_value(command_queue_.size());
+ command_promise_.reset();
+ }
+ }
+
+ void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+ common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) override {
+ command_queue_.push_back(std::move(command));
+ command_complete_callbacks.push_back(std::move(on_complete));
+ if (command_promise_ != nullptr) {
+ command_promise_->set_value(command_queue_.size());
+ command_promise_.reset();
+ }
+ }
+
+ std::future<size_t> GetCommandFuture() {
+ ASSERT_LOG(command_promise_ == nullptr, "Promises promises ... Only one at a time");
+ command_promise_ = std::make_unique<std::promise<size_t>>();
+ return command_promise_->get_future();
+ }
+
+ std::unique_ptr<CommandPacketBuilder> GetLastCommand() {
+ ASSERT(!command_queue_.empty());
+ auto last = std::move(command_queue_.front());
+ command_queue_.pop_front();
+ return last;
+ }
+
+ ConnectionManagementCommandView GetCommandPacket(OpCode op_code) {
+ auto packet_view = GetPacketView(GetLastCommand());
+ CommandPacketView command_packet_view = CommandPacketView::Create(packet_view);
+ ConnectionManagementCommandView command = ConnectionManagementCommandView::Create(command_packet_view);
+ ASSERT(command.IsValid());
+ EXPECT_EQ(command.GetOpCode(), op_code);
+
+ return command;
+ }
+
+ void RegisterEventHandler(EventCode event_code, common::Callback<void(EventPacketView)> event_handler,
+ os::Handler* handler) override {
+ registered_events_[event_code] = event_handler;
+ }
+
+ void RegisterLeEventHandler(SubeventCode subevent_code, common::Callback<void(LeMetaEventView)> event_handler,
+ os::Handler* handler) override {
+ registered_le_events_[subevent_code] = event_handler;
+ }
+
+ void IncomingEvent(std::unique_ptr<EventPacketBuilder> event_builder) {
+ auto packet = GetPacketView(std::move(event_builder));
+ EventPacketView event = EventPacketView::Create(packet);
+ ASSERT_TRUE(event.IsValid());
+ EventCode event_code = event.GetEventCode();
+ ASSERT_TRUE(registered_events_.find(event_code) != registered_events_.end()) << EventCodeText(event_code);
+ registered_events_[event_code].Run(event);
+ }
+
+ void IncomingLeMetaEvent(std::unique_ptr<LeMetaEventBuilder> event_builder) {
+ auto packet = GetPacketView(std::move(event_builder));
+ EventPacketView event = EventPacketView::Create(packet);
+ LeMetaEventView meta_event_view = LeMetaEventView::Create(event);
+ ASSERT_TRUE(meta_event_view.IsValid());
+ SubeventCode subevent_code = meta_event_view.GetSubeventCode();
+ ASSERT_TRUE(registered_le_events_.find(subevent_code) != registered_le_events_.end())
+ << SubeventCodeText(subevent_code);
+ registered_le_events_[subevent_code].Run(meta_event_view);
+ }
+
+ void CommandCompleteCallback(EventPacketView event) {
+ CommandCompleteView complete_view = CommandCompleteView::Create(event);
+ ASSERT(complete_view.IsValid());
+ std::move(command_complete_callbacks.front()).Run(complete_view);
+ command_complete_callbacks.pop_front();
+ }
+
+ void CommandStatusCallback(EventPacketView event) {
+ CommandStatusView status_view = CommandStatusView::Create(event);
+ ASSERT(status_view.IsValid());
+ std::move(command_status_callbacks.front()).Run(status_view);
+ command_status_callbacks.pop_front();
+ }
+
+ void ListDependencies(ModuleList* list) override {}
+ void Start() override {}
+ void Stop() override {}
+
+ private:
+ std::map<EventCode, common::Callback<void(EventPacketView)>> registered_events_;
+ std::map<SubeventCode, common::Callback<void(LeMetaEventView)>> registered_le_events_;
+ std::list<base::OnceCallback<void(CommandCompleteView)>> command_complete_callbacks;
+ std::list<base::OnceCallback<void(CommandStatusView)>> command_status_callbacks;
+
+ std::list<std::unique_ptr<CommandPacketBuilder>> command_queue_;
+ mutable std::mutex mutex_;
+ std::unique_ptr<std::promise<size_t>> command_promise_{};
+};
+
+class LeAdvertisingManagerTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ test_hci_layer_ = new TestHciLayer; // Ownership is transferred to registry
+ test_controller_ = new TestController;
+ test_controller_->AddSupported(param_opcode_);
+ fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_);
+ fake_registry_.InjectTestModule(&Controller::Factory, test_controller_);
+ client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory);
+ ASSERT_NE(client_handler_, nullptr);
+ test_controller_->num_advertisers = 1;
+ fake_registry_.Start<LeAdvertisingManager>(&thread_);
+ le_advertising_manager_ =
+ static_cast<LeAdvertisingManager*>(fake_registry_.GetModuleUnderTest(&LeAdvertisingManager::Factory));
+ }
+
+ void TearDown() override {
+ fake_registry_.SynchronizeModuleHandler(&LeAdvertisingManager::Factory, std::chrono::milliseconds(20));
+ fake_registry_.StopAll();
+ }
+
+ TestModuleRegistry fake_registry_;
+ TestHciLayer* test_hci_layer_ = nullptr;
+ TestController* test_controller_ = nullptr;
+ os::Thread& thread_ = fake_registry_.GetTestThread();
+ LeAdvertisingManager* le_advertising_manager_ = nullptr;
+ os::Handler* client_handler_ = nullptr;
+
+ const common::Callback<void(Address, AddressType)> scan_callback =
+ common::Bind(&LeAdvertisingManagerTest::on_scan, common::Unretained(this));
+ const common::Callback<void(ErrorCode, uint8_t, uint8_t)> set_terminated_callback =
+ common::Bind(&LeAdvertisingManagerTest::on_set_terminated, common::Unretained(this));
+
+ std::future<Address> GetOnScanPromise() {
+ ASSERT_LOG(address_promise_ == nullptr, "Promises promises ... Only one at a time");
+ address_promise_ = std::make_unique<std::promise<Address>>();
+ return address_promise_->get_future();
+ }
+ void on_scan(Address address, AddressType address_type) {
+ if (address_promise_ == nullptr) {
+ return;
+ }
+ address_promise_->set_value(address);
+ address_promise_.reset();
+ }
+
+ std::future<ErrorCode> GetSetTerminatedPromise() {
+ ASSERT_LOG(set_terminated_promise_ == nullptr, "Promises promises ... Only one at a time");
+ set_terminated_promise_ = std::make_unique<std::promise<ErrorCode>>();
+ return set_terminated_promise_->get_future();
+ }
+ void on_set_terminated(ErrorCode error_code, uint8_t, uint8_t) {
+ if (set_terminated_promise_ != nullptr) {
+ return;
+ }
+ set_terminated_promise_->set_value(error_code);
+ set_terminated_promise_.reset();
+ }
+
+ std::unique_ptr<std::promise<Address>> address_promise_{};
+ std::unique_ptr<std::promise<ErrorCode>> set_terminated_promise_{};
+
+ OpCode param_opcode_{OpCode::LE_SET_ADVERTISING_PARAMETERS};
+};
+
+class LeAndroidHciAdvertisingManagerTest : public LeAdvertisingManagerTest {
+ protected:
+ void SetUp() override {
+ param_opcode_ = OpCode::LE_MULTI_ADVT;
+ LeAdvertisingManagerTest::SetUp();
+ test_controller_->num_advertisers = 3;
+ }
+};
+
+class LeExtendedAdvertisingManagerTest : public LeAdvertisingManagerTest {
+ protected:
+ void SetUp() override {
+ param_opcode_ = OpCode::LE_SET_EXTENDED_ADVERTISING_PARAMETERS;
+ LeAdvertisingManagerTest::SetUp();
+ test_controller_->num_advertisers = 5;
+ }
+};
+
+TEST_F(LeAdvertisingManagerTest, startup_teardown) {}
+
+TEST_F(LeAndroidHciAdvertisingManagerTest, startup_teardown) {}
+
+TEST_F(LeExtendedAdvertisingManagerTest, startup_teardown) {}
+
+TEST_F(LeAdvertisingManagerTest, create_advertiser_test) {
+ AdvertisingConfig advertising_config{};
+ advertising_config.event_type = AdvertisingEventType::ADV_IND;
+ advertising_config.address_type = AddressType::PUBLIC_DEVICE_ADDRESS;
+ std::vector<GapData> gap_data{};
+ GapData data_item{};
+ data_item.data_type_ = GapDataType::FLAGS;
+ data_item.data_ = {0x34};
+ gap_data.push_back(data_item);
+ data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
+ data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
+ gap_data.push_back(data_item);
+ advertising_config.advertisement = gap_data;
+ advertising_config.scan_response = gap_data;
+
+ auto next_command_future = test_hci_layer_->GetCommandFuture();
+ auto id = le_advertising_manager_->CreateAdvertiser(advertising_config, scan_callback, set_terminated_callback,
+ client_handler_);
+ ASSERT_NE(LeAdvertisingManager::kInvalidId, id);
+ std::vector<OpCode> adv_opcodes = {
+ OpCode::LE_SET_ADVERTISING_PARAMETERS, OpCode::LE_SET_RANDOM_ADDRESS, OpCode::LE_SET_SCAN_RESPONSE_DATA,
+ OpCode::LE_SET_ADVERTISING_DATA, OpCode::LE_SET_ADVERTISING_ENABLE,
+ };
+ auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100)));
+ ASSERT_NE(std::future_status::timeout, result);
+ size_t num_commands = next_command_future.get();
+ for (size_t i = 0; i < adv_opcodes.size(); i++) {
+ auto packet = test_hci_layer_->GetCommandPacket(adv_opcodes[i]);
+ std::vector<uint8_t> success_vector{static_cast<uint8_t>(ErrorCode::SUCCESS)};
+ test_hci_layer_->IncomingEvent(
+ CommandCompleteBuilder::Create(uint8_t{1}, adv_opcodes[i], std::make_unique<RawBuilder>(success_vector)));
+ if (i < adv_opcodes.size() - 1 && --num_commands == 1) {
+ next_command_future = test_hci_layer_->GetCommandFuture();
+ result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100)));
+ ASSERT_NE(std::future_status::timeout, result);
+ num_commands = next_command_future.get();
+ }
+ }
+}
+
+TEST_F(LeAndroidHciAdvertisingManagerTest, create_advertiser_test) {
+ AdvertisingConfig advertising_config{};
+ advertising_config.event_type = AdvertisingEventType::ADV_IND;
+ advertising_config.address_type = AddressType::PUBLIC_DEVICE_ADDRESS;
+ std::vector<GapData> gap_data{};
+ GapData data_item{};
+ data_item.data_type_ = GapDataType::FLAGS;
+ data_item.data_ = {0x34};
+ gap_data.push_back(data_item);
+ data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
+ data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
+ gap_data.push_back(data_item);
+ advertising_config.advertisement = gap_data;
+ advertising_config.scan_response = gap_data;
+
+ auto next_command_future = test_hci_layer_->GetCommandFuture();
+ auto id = le_advertising_manager_->CreateAdvertiser(advertising_config, scan_callback, set_terminated_callback,
+ client_handler_);
+ ASSERT_NE(LeAdvertisingManager::kInvalidId, id);
+ std::vector<SubOcf> sub_ocf = {
+ SubOcf::SET_PARAM, SubOcf::SET_DATA, SubOcf::SET_SCAN_RESP, SubOcf::SET_RANDOM_ADDR, SubOcf::SET_ENABLE,
+ };
+ auto result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100)));
+ ASSERT_NE(std::future_status::timeout, result);
+ size_t num_commands = next_command_future.get();
+ for (size_t i = 0; i < sub_ocf.size(); i++) {
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_MULTI_ADVT);
+ std::vector<uint8_t> success_vector{static_cast<uint8_t>(ErrorCode::SUCCESS), static_cast<uint8_t>(sub_ocf[i])};
+ test_hci_layer_->IncomingEvent(CommandCompleteBuilder::Create(uint8_t{1}, OpCode::LE_MULTI_ADVT,
+ std::make_unique<RawBuilder>(success_vector)));
+ if (i < sub_ocf.size() - 1 && --num_commands == 1) {
+ next_command_future = test_hci_layer_->GetCommandFuture();
+ result = next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100)));
+ ASSERT_NE(std::future_status::timeout, result);
+ num_commands = next_command_future.get();
+ }
+ }
+}
+
+} // namespace
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/le_device.h b/gd/hci/le_device.h
new file mode 100644
index 0000000..35a620b
--- /dev/null
+++ b/gd/hci/le_device.h
@@ -0,0 +1,89 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+#pragma once
+
+#include "hci/device.h"
+
+namespace bluetooth::hci {
+
+/**
+ * TODO(optedoblivion): Build out AddressType getter/setter
+ */
+// enum AddressType {};
+
+/**
+ * A device representing a LE device.
+ *
+ * <p>This can be a LE only or a piece of a DUAL MODE device.
+ *
+ * <p>LE specific public address logic goes here.
+ */
+class LeDevice : public Device {
+ public:
+ void SetPublicAddress(Address public_address) {
+ public_address_ = public_address;
+ }
+
+ Address GetPublicAddress() {
+ return public_address_;
+ }
+
+ void SetIrk(uint8_t irk) {
+ irk_ = irk;
+ // TODO(optedoblivion): Set derived Address
+ }
+
+ uint8_t GetIrk() {
+ return irk_;
+ }
+
+ protected:
+ friend class DeviceDatabase;
+ // TODO(optedoblivion): How to set public address. Do I set it when no IRK is known?
+ // Right now my thought is to do this:
+ // 1. Construct LeDevice with address of all 0s
+ // 2. IF NO IRK AND NO PRIVATE ADDRESS: (i.e. nothing in disk cache)
+ // a. Hopefully pairing will happen
+ // b. Pending successful pairing get the IRK and Private Address
+ // c. Set Both to device.
+ // (d). If available set IRK to the controller (later iteration)
+ // [#3 should indicate we have a bug]
+ // 3. IF YES IRK AND NO PRIVATE ADDRESS: (Partial Disk Cache Information)
+ // a. Set IRK
+ // b. Generate Private Address
+ // c. Set Private Address to device
+ // (d). If available set IRK to the controller (later iteration)
+ // 4. IF YES IRK AND YES PRIVATE ADDRESS: (i.e. Disk cache hit)
+ // a. Construct with private address
+ // b. Set IRK
+ // (c). If available set IRK to the controller (later iteration)
+ // 5. IF NO IRK AND YES PRIVATE ADDRESS (we have a bug)
+ // a1. -Construct with private address-
+ // b. -Indicate we need to repair or query for IRK?-
+ //
+ // or
+ //
+ // a2. Don't use class
+ explicit LeDevice(Address address) : Device(address, DeviceType::LE), public_address_(), irk_(0) {}
+
+ private:
+ Address public_address_;
+ uint8_t irk_;
+};
+
+} // namespace bluetooth::hci
diff --git a/gd/hci/le_report.h b/gd/hci/le_report.h
new file mode 100644
index 0000000..7dc075f
--- /dev/null
+++ b/gd/hci/le_report.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <memory>
+
+#include "hci/hci_packets.h"
+
+namespace bluetooth::hci {
+
+class LeReport {
+ public:
+ explicit LeReport(const LeAdvertisingReport& advertisement)
+ : report_type_(ReportType::ADVERTISING_EVENT), advertising_event_type_(advertisement.event_type_),
+ address_(advertisement.address_), address_type_(advertisement.address_type_), rssi_(advertisement.rssi_),
+ gap_data_(advertisement.advertising_data_) {}
+ explicit LeReport(const LeDirectedAdvertisingReport& advertisement)
+ : report_type_(ReportType::DIRECTED_ADVERTISING_EVENT), address_(advertisement.address_),
+ rssi_(advertisement.rssi_) {}
+ explicit LeReport(const LeExtendedAdvertisingReport& advertisement)
+ : report_type_(ReportType::EXTENDED_ADVERTISING_EVENT), address_(advertisement.address_),
+ rssi_(advertisement.rssi_), gap_data_(advertisement.advertising_data_) {}
+ virtual ~LeReport() = default;
+
+ enum class ReportType {
+ ADVERTISING_EVENT = 1,
+ DIRECTED_ADVERTISING_EVENT = 2,
+ EXTENDED_ADVERTISING_EVENT = 3,
+ };
+ const ReportType report_type_;
+
+ ReportType GetReportType() const {
+ return report_type_;
+ }
+
+ // Advertising Event
+ const AdvertisingEventType advertising_event_type_{};
+ const Address address_{};
+ const AddressType address_type_{};
+ const uint8_t rssi_;
+ const std::vector<GapData> gap_data_{};
+};
+
+class DirectedLeReport : public LeReport {
+ public:
+ explicit DirectedLeReport(const LeDirectedAdvertisingReport& advertisement)
+ : LeReport(advertisement), direct_address_type_(advertisement.address_type_) {}
+ explicit DirectedLeReport(const LeExtendedAdvertisingReport& advertisement)
+ : LeReport(advertisement), direct_address_type_(advertisement.address_type_) {}
+
+ const DirectAdvertisingAddressType direct_address_type_{};
+};
+
+class ExtendedLeReport : public DirectedLeReport {
+ public:
+ explicit ExtendedLeReport(const LeExtendedAdvertisingReport& advertisement)
+ : DirectedLeReport(advertisement), connectable_(advertisement.connectable_), scannable_(advertisement.scannable_),
+ directed_(advertisement.directed_), scan_response_(advertisement.scan_response_),
+ complete_(advertisement.data_status_ == DataStatus::COMPLETE),
+ truncated_(advertisement.data_status_ == DataStatus::TRUNCATED) {}
+
+ // Extended
+ bool connectable_;
+ bool scannable_;
+ bool directed_;
+ bool scan_response_;
+ bool complete_;
+ bool truncated_;
+};
+} // namespace bluetooth::hci
\ No newline at end of file
diff --git a/gd/hci/le_scanning_interface.h b/gd/hci/le_scanning_interface.h
new file mode 100644
index 0000000..97a6766
--- /dev/null
+++ b/gd/hci/le_scanning_interface.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "common/callback.h"
+#include "hci/hci_packets.h"
+#include "os/handler.h"
+#include "os/utils.h"
+
+namespace bluetooth {
+namespace hci {
+
+class LeScanningInterface {
+ public:
+ LeScanningInterface() = default;
+ virtual ~LeScanningInterface() = default;
+ DISALLOW_COPY_AND_ASSIGN(LeScanningInterface);
+
+ virtual void EnqueueCommand(std::unique_ptr<LeScanningCommandBuilder> command,
+ common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) = 0;
+
+ virtual void EnqueueCommand(std::unique_ptr<LeScanningCommandBuilder> command,
+ common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) = 0;
+
+ static constexpr hci::SubeventCode LeScanningEvents[] = {
+ hci::SubeventCode::SCAN_TIMEOUT,
+ hci::SubeventCode::ADVERTISING_REPORT,
+ hci::SubeventCode::DIRECTED_ADVERTISING_REPORT,
+ hci::SubeventCode::EXTENDED_ADVERTISING_REPORT,
+ hci::SubeventCode::PERIODIC_ADVERTISING_REPORT,
+ hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_ESTABLISHED,
+ hci::SubeventCode::PERIODIC_ADVERTISING_SYNC_LOST,
+ };
+};
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/le_scanning_manager.cc b/gd/hci/le_scanning_manager.cc
new file mode 100644
index 0000000..ad88b44
--- /dev/null
+++ b/gd/hci/le_scanning_manager.cc
@@ -0,0 +1,258 @@
+/*
+ * Copyright 2019 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 <memory>
+#include <mutex>
+#include <set>
+
+#include "hci/controller.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "hci/le_scanning_interface.h"
+#include "hci/le_scanning_manager.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace hci {
+
+const ModuleFactory LeScanningManager::Factory = ModuleFactory([]() { return new LeScanningManager(); });
+
+enum class ScanApiType {
+ LE_4_0 = 1,
+ ANDROID_HCI = 2,
+ LE_5_0 = 3,
+};
+
+struct LeScanningManager::impl {
+ impl(Module* module) : module_(module), le_scanning_interface_(nullptr) {}
+
+ void start(os::Handler* handler, hci::HciLayer* hci_layer, hci::Controller* controller) {
+ module_handler_ = handler;
+ hci_layer_ = hci_layer;
+ controller_ = controller;
+ le_scanning_interface_ = hci_layer_->GetLeScanningInterface(
+ common::Bind(&LeScanningManager::impl::handle_scan_results, common::Unretained(this)), module_handler_);
+ if (controller_->IsSupported(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS)) {
+ api_type_ = ScanApiType::LE_5_0;
+ } else if (controller_->IsSupported(OpCode::LE_EXTENDED_SCAN_PARAMS)) {
+ api_type_ = ScanApiType::ANDROID_HCI;
+ } else {
+ api_type_ = ScanApiType::LE_4_0;
+ }
+ configure_scan();
+ }
+
+ void handle_scan_results(LeMetaEventView event) {
+ switch (event.GetSubeventCode()) {
+ case hci::SubeventCode::ADVERTISING_REPORT:
+ handle_advertising_report<LeAdvertisingReportView, LeAdvertisingReport, LeReport>(
+ LeAdvertisingReportView::Create(event));
+ break;
+ case hci::SubeventCode::DIRECTED_ADVERTISING_REPORT:
+ handle_advertising_report<LeDirectedAdvertisingReportView, LeDirectedAdvertisingReport, DirectedLeReport>(
+ LeDirectedAdvertisingReportView::Create(event));
+ break;
+ case hci::SubeventCode::EXTENDED_ADVERTISING_REPORT:
+ handle_advertising_report<LeExtendedAdvertisingReportView, LeExtendedAdvertisingReport, ExtendedLeReport>(
+ LeExtendedAdvertisingReportView::Create(event));
+ break;
+ case hci::SubeventCode::SCAN_TIMEOUT:
+ if (registered_callback_ != nullptr) {
+ registered_callback_->handler->Post(
+ common::BindOnce(&LeScanningManagerCallbacks::on_timeout, common::Unretained(registered_callback_)));
+ registered_callback_ = nullptr;
+ }
+ break;
+ default:
+ LOG_ALWAYS_FATAL("Unknown advertising subevent %s", hci::SubeventCodeText(event.GetSubeventCode()).c_str());
+ }
+ }
+
+ template <class EventType, class ReportStructType, class ReportType>
+ void handle_advertising_report(EventType event_view) {
+ if (registered_callback_ == nullptr) {
+ LOG_INFO("Dropping advertising event (no registered handler)");
+ return;
+ }
+ if (!event_view.IsValid()) {
+ LOG_INFO("Dropping invalid advertising event");
+ return;
+ }
+ std::vector<ReportStructType> report_vector = event_view.GetAdvertisingReports();
+ if (report_vector.empty()) {
+ LOG_INFO("Zero results in advertising event");
+ return;
+ }
+ std::vector<std::shared_ptr<LeReport>> param;
+ param.reserve(report_vector.size());
+ for (const ReportStructType& report : report_vector) {
+ param.push_back(std::shared_ptr<LeReport>(static_cast<LeReport*>(new ReportType(report))));
+ }
+ registered_callback_->handler->Post(common::BindOnce(&LeScanningManagerCallbacks::on_advertisements,
+ common::Unretained(registered_callback_), param));
+ }
+
+ void configure_scan() {
+ std::vector<PhyScanParameters> parameter_vector;
+ PhyScanParameters phy_scan_parameters;
+ phy_scan_parameters.le_scan_window_ = 0;
+ phy_scan_parameters.le_scan_interval_ = 0;
+ phy_scan_parameters.le_scan_type_ = LeScanType::ACTIVE;
+ parameter_vector.push_back(phy_scan_parameters);
+ uint8_t phys_in_use = 1;
+
+ switch (api_type_) {
+ case ScanApiType::LE_5_0:
+ le_scanning_interface_->EnqueueCommand(hci::LeSetExtendedScanParametersBuilder::Create(
+ own_address_type_, filter_policy_, phys_in_use, parameter_vector),
+ common::BindOnce(impl::check_status), module_handler_);
+ break;
+ case ScanApiType::ANDROID_HCI:
+ le_scanning_interface_->EnqueueCommand(
+ hci::LeExtendedScanParamsBuilder::Create(LeScanType::ACTIVE, interval_ms_, window_ms_, own_address_type_,
+ filter_policy_),
+ common::BindOnce(impl::check_status), module_handler_);
+
+ break;
+ case ScanApiType::LE_4_0:
+ le_scanning_interface_->EnqueueCommand(
+ hci::LeSetScanParametersBuilder::Create(LeScanType::ACTIVE, interval_ms_, window_ms_, own_address_type_,
+ filter_policy_),
+ common::BindOnce(impl::check_status), module_handler_);
+ break;
+ }
+ }
+
+ void start_scan(LeScanningManagerCallbacks* le_scanning_manager_callbacks) {
+ registered_callback_ = le_scanning_manager_callbacks;
+ switch (api_type_) {
+ case ScanApiType::LE_5_0:
+ le_scanning_interface_->EnqueueCommand(
+ hci::LeSetExtendedScanEnableBuilder::Create(Enable::ENABLED,
+ FilterDuplicates::DISABLED /* filter duplicates */, 0, 0),
+ common::BindOnce(impl::check_status), module_handler_);
+ break;
+ case ScanApiType::ANDROID_HCI:
+ case ScanApiType::LE_4_0:
+ le_scanning_interface_->EnqueueCommand(
+ hci::LeSetScanEnableBuilder::Create(Enable::ENABLED, Enable::DISABLED /* filter duplicates */),
+ common::BindOnce(impl::check_status), module_handler_);
+ break;
+ }
+ }
+
+ void stop_scan(common::Callback<void()> on_stopped) {
+ if (registered_callback_ == nullptr) {
+ return;
+ }
+ registered_callback_->handler->Post(std::move(on_stopped));
+ switch (api_type_) {
+ case ScanApiType::LE_5_0:
+ le_scanning_interface_->EnqueueCommand(
+ hci::LeSetExtendedScanEnableBuilder::Create(Enable::DISABLED,
+ FilterDuplicates::DISABLED /* filter duplicates */, 0, 0),
+ common::BindOnce(impl::check_status), module_handler_);
+ registered_callback_->handler = nullptr;
+ break;
+ case ScanApiType::ANDROID_HCI:
+ case ScanApiType::LE_4_0:
+ le_scanning_interface_->EnqueueCommand(
+ hci::LeSetScanEnableBuilder::Create(Enable::DISABLED, Enable::DISABLED /* filter duplicates */),
+ common::BindOnce(impl::check_status), module_handler_);
+ registered_callback_->handler = nullptr;
+ break;
+ }
+ }
+
+ ScanApiType api_type_;
+
+ LeScanningManagerCallbacks* registered_callback_;
+ Module* module_;
+ os::Handler* module_handler_;
+ hci::HciLayer* hci_layer_;
+ hci::Controller* controller_;
+ hci::LeScanningInterface* le_scanning_interface_;
+
+ uint32_t interval_ms_{1000};
+ uint16_t window_ms_{1000};
+ AddressType own_address_type_{AddressType::PUBLIC_DEVICE_ADDRESS};
+ LeSetScanningFilterPolicy filter_policy_{LeSetScanningFilterPolicy::ACCEPT_ALL};
+
+ static void check_status(CommandCompleteView view) {
+ switch (view.GetCommandOpCode()) {
+ case (OpCode::LE_SET_SCAN_ENABLE): {
+ auto status_view = LeSetScanEnableCompleteView::Create(view);
+ ASSERT(status_view.IsValid());
+ ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
+ } break;
+ case (OpCode::LE_SET_EXTENDED_SCAN_ENABLE): {
+ auto status_view = LeSetExtendedScanEnableCompleteView::Create(view);
+ ASSERT(status_view.IsValid());
+ ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
+ } break;
+ case (OpCode::LE_SET_SCAN_PARAMETERS): {
+ auto status_view = LeSetScanParametersCompleteView::Create(view);
+ ASSERT(status_view.IsValid());
+ ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
+ } break;
+ case (OpCode::LE_EXTENDED_SCAN_PARAMS): {
+ auto status_view = LeExtendedScanParamsCompleteView::Create(view);
+ ASSERT(status_view.IsValid());
+ ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
+ } break;
+ case (OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS): {
+ auto status_view = LeSetExtendedScanParametersCompleteView::Create(view);
+ ASSERT(status_view.IsValid());
+ ASSERT(status_view.GetStatus() == ErrorCode::SUCCESS);
+ } break;
+ default:
+ LOG_ALWAYS_FATAL("Unhandled event %s", OpCodeText(view.GetCommandOpCode()).c_str());
+ }
+ }
+};
+
+LeScanningManager::LeScanningManager() {
+ pimpl_ = std::make_unique<impl>(this);
+}
+
+void LeScanningManager::ListDependencies(ModuleList* list) {
+ list->add<hci::HciLayer>();
+ list->add<hci::Controller>();
+}
+
+void LeScanningManager::Start() {
+ pimpl_->start(GetHandler(), GetDependency<hci::HciLayer>(), GetDependency<hci::Controller>());
+}
+
+void LeScanningManager::Stop() {
+ pimpl_.reset();
+}
+
+std::string LeScanningManager::ToString() const {
+ return "Le Scanning Manager";
+}
+
+void LeScanningManager::StartScan(LeScanningManagerCallbacks* callbacks) {
+ GetHandler()->Post(common::Bind(&impl::start_scan, common::Unretained(pimpl_.get()), callbacks));
+}
+
+void LeScanningManager::StopScan(common::Callback<void()> on_stopped) {
+ GetHandler()->Post(common::Bind(&impl::stop_scan, common::Unretained(pimpl_.get()), on_stopped));
+}
+
+} // namespace hci
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/hci/le_scanning_manager.h b/gd/hci/le_scanning_manager.h
new file mode 100644
index 0000000..b8f30d9
--- /dev/null
+++ b/gd/hci/le_scanning_manager.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <memory>
+
+#include "common/callback.h"
+#include "hci/hci_packets.h"
+#include "hci/le_report.h"
+#include "module.h"
+
+namespace bluetooth {
+namespace hci {
+
+class LeScanningManagerCallbacks {
+ public:
+ virtual ~LeScanningManagerCallbacks() = default;
+ virtual void on_advertisements(std::vector<std::shared_ptr<LeReport>>) = 0;
+ virtual void on_timeout() = 0;
+ os::Handler* handler;
+};
+
+class LeScanningManager : public bluetooth::Module {
+ public:
+ LeScanningManager();
+
+ void StartScan(LeScanningManagerCallbacks* callbacks);
+
+ void StopScan(common::Callback<void()> on_stopped);
+
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override;
+
+ void Start() override;
+
+ void Stop() override;
+
+ std::string ToString() const override;
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+ DISALLOW_COPY_AND_ASSIGN(LeScanningManager);
+};
+
+} // namespace hci
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/hci/le_scanning_manager_test.cc b/gd/hci/le_scanning_manager_test.cc
new file mode 100644
index 0000000..e5e461e
--- /dev/null
+++ b/gd/hci/le_scanning_manager_test.cc
@@ -0,0 +1,336 @@
+/*
+ * Copyright 2019 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 "hci/le_scanning_manager.h"
+
+#include <algorithm>
+#include <chrono>
+#include <future>
+#include <map>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "common/bind.h"
+#include "hci/address.h"
+#include "hci/controller.h"
+#include "hci/hci_layer.h"
+#include "os/thread.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace hci {
+namespace {
+
+using packet::kLittleEndian;
+using packet::PacketView;
+using packet::RawBuilder;
+
+PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+ auto bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter i(*bytes);
+ bytes->reserve(packet->size());
+ packet->Serialize(i);
+ return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+class TestController : public Controller {
+ public:
+ bool IsSupported(OpCode op_code) const override {
+ return supported_opcodes_.count(op_code) == 1;
+ }
+
+ void AddSupported(OpCode op_code) {
+ supported_opcodes_.insert(op_code);
+ }
+
+ protected:
+ void Start() override {}
+ void Stop() override {}
+ void ListDependencies(ModuleList* list) override {}
+
+ private:
+ std::set<OpCode> supported_opcodes_{};
+};
+
+class TestHciLayer : public HciLayer {
+ public:
+ TestHciLayer() {
+ RegisterEventHandler(EventCode::COMMAND_COMPLETE,
+ base::Bind(&TestHciLayer::CommandCompleteCallback, common::Unretained(this)), nullptr);
+ RegisterEventHandler(EventCode::COMMAND_STATUS,
+ base::Bind(&TestHciLayer::CommandStatusCallback, common::Unretained(this)), nullptr);
+ }
+
+ void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+ common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) override {
+ command_queue_.push(std::move(command));
+ command_status_callbacks.push_front(std::move(on_status));
+ if (command_promise_ != nullptr) {
+ command_promise_->set_value();
+ command_promise_.reset();
+ }
+ }
+
+ void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+ common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) override {
+ command_queue_.push(std::move(command));
+ command_complete_callbacks.push_front(std::move(on_complete));
+ if (command_promise_ != nullptr) {
+ command_promise_->set_value();
+ command_promise_.reset();
+ }
+ }
+
+ std::future<void> GetCommandFuture() {
+ ASSERT_LOG(command_promise_ == nullptr, "Promises promises ... Only one at a time");
+ command_promise_ = std::make_unique<std::promise<void>>();
+ return command_promise_->get_future();
+ }
+
+ std::unique_ptr<CommandPacketBuilder> GetLastCommand() {
+ ASSERT(!command_queue_.empty());
+ auto last = std::move(command_queue_.front());
+ command_queue_.pop();
+ return last;
+ }
+
+ ConnectionManagementCommandView GetCommandPacket(OpCode op_code) {
+ auto packet_view = GetPacketView(GetLastCommand());
+ CommandPacketView command_packet_view = CommandPacketView::Create(packet_view);
+ ConnectionManagementCommandView command = ConnectionManagementCommandView::Create(command_packet_view);
+ ASSERT(command.IsValid());
+ EXPECT_EQ(command.GetOpCode(), op_code);
+
+ return command;
+ }
+
+ void RegisterEventHandler(EventCode event_code, common::Callback<void(EventPacketView)> event_handler,
+ os::Handler* handler) override {
+ registered_events_[event_code] = event_handler;
+ }
+
+ void RegisterLeEventHandler(SubeventCode subevent_code, common::Callback<void(LeMetaEventView)> event_handler,
+ os::Handler* handler) override {
+ registered_le_events_[subevent_code] = event_handler;
+ }
+
+ void IncomingEvent(std::unique_ptr<EventPacketBuilder> event_builder) {
+ auto packet = GetPacketView(std::move(event_builder));
+ EventPacketView event = EventPacketView::Create(packet);
+ ASSERT_TRUE(event.IsValid());
+ EventCode event_code = event.GetEventCode();
+ ASSERT_TRUE(registered_events_.find(event_code) != registered_events_.end()) << EventCodeText(event_code);
+ registered_events_[event_code].Run(event);
+ }
+
+ void IncomingLeMetaEvent(std::unique_ptr<LeMetaEventBuilder> event_builder) {
+ auto packet = GetPacketView(std::move(event_builder));
+ EventPacketView event = EventPacketView::Create(packet);
+ LeMetaEventView meta_event_view = LeMetaEventView::Create(event);
+ ASSERT_TRUE(meta_event_view.IsValid());
+ SubeventCode subevent_code = meta_event_view.GetSubeventCode();
+ ASSERT_TRUE(registered_le_events_.find(subevent_code) != registered_le_events_.end())
+ << SubeventCodeText(subevent_code);
+ registered_le_events_[subevent_code].Run(meta_event_view);
+ }
+
+ void CommandCompleteCallback(EventPacketView event) {
+ CommandCompleteView complete_view = CommandCompleteView::Create(event);
+ ASSERT(complete_view.IsValid());
+ std::move(command_complete_callbacks.front()).Run(complete_view);
+ command_complete_callbacks.pop_front();
+ }
+
+ void CommandStatusCallback(EventPacketView event) {
+ CommandStatusView status_view = CommandStatusView::Create(event);
+ ASSERT(status_view.IsValid());
+ std::move(command_status_callbacks.front()).Run(status_view);
+ command_status_callbacks.pop_front();
+ }
+
+ void ListDependencies(ModuleList* list) override {}
+ void Start() override {}
+ void Stop() override {}
+
+ private:
+ std::map<EventCode, common::Callback<void(EventPacketView)>> registered_events_;
+ std::map<SubeventCode, common::Callback<void(LeMetaEventView)>> registered_le_events_;
+ std::list<base::OnceCallback<void(CommandCompleteView)>> command_complete_callbacks;
+ std::list<base::OnceCallback<void(CommandStatusView)>> command_status_callbacks;
+
+ std::queue<std::unique_ptr<CommandPacketBuilder>> command_queue_;
+ mutable std::mutex mutex_;
+ std::unique_ptr<std::promise<void>> command_promise_{};
+};
+
+class LeScanningManagerTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ test_hci_layer_ = new TestHciLayer; // Ownership is transferred to registry
+ test_controller_ = new TestController;
+ test_controller_->AddSupported(param_opcode_);
+ fake_registry_.InjectTestModule(&HciLayer::Factory, test_hci_layer_);
+ fake_registry_.InjectTestModule(&Controller::Factory, test_controller_);
+ client_handler_ = fake_registry_.GetTestModuleHandler(&HciLayer::Factory);
+ ASSERT_NE(client_handler_, nullptr);
+ mock_callbacks_.handler = client_handler_;
+ std::future<void> config_future = test_hci_layer_->GetCommandFuture();
+ fake_registry_.Start<LeScanningManager>(&thread_);
+ le_scanning_manager =
+ static_cast<LeScanningManager*>(fake_registry_.GetModuleUnderTest(&LeScanningManager::Factory));
+ config_future.wait_for(std::chrono::duration(std::chrono::milliseconds(1000)));
+ HandleConfiguration();
+ }
+
+ void TearDown() override {
+ fake_registry_.SynchronizeModuleHandler(&LeScanningManager::Factory, std::chrono::milliseconds(20));
+ fake_registry_.StopAll();
+ }
+
+ virtual void HandleConfiguration() {
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_SET_SCAN_PARAMETERS);
+ test_hci_layer_->IncomingEvent(LeSetScanParametersCompleteBuilder::Create(1, ErrorCode::SUCCESS));
+ }
+
+ TestModuleRegistry fake_registry_;
+ TestHciLayer* test_hci_layer_ = nullptr;
+ TestController* test_controller_ = nullptr;
+ os::Thread& thread_ = fake_registry_.GetTestThread();
+ LeScanningManager* le_scanning_manager = nullptr;
+ os::Handler* client_handler_ = nullptr;
+
+ class MockLeScanningManagerCallbacks : public LeScanningManagerCallbacks {
+ public:
+ MOCK_METHOD(void, on_advertisements, (std::vector<std::shared_ptr<LeReport>>), (override));
+ MOCK_METHOD(void, on_timeout, (), (override));
+ } mock_callbacks_;
+
+ OpCode param_opcode_{OpCode::LE_SET_ADVERTISING_PARAMETERS};
+};
+
+class LeAndroidHciScanningManagerTest : public LeScanningManagerTest {
+ protected:
+ void SetUp() override {
+ param_opcode_ = OpCode::LE_EXTENDED_SCAN_PARAMS;
+ LeScanningManagerTest::SetUp();
+ }
+
+ void HandleConfiguration() override {
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_EXTENDED_SCAN_PARAMS);
+ test_hci_layer_->IncomingEvent(LeExtendedScanParamsCompleteBuilder::Create(1, ErrorCode::SUCCESS));
+ }
+};
+
+class LeExtendedScanningManagerTest : public LeScanningManagerTest {
+ protected:
+ void SetUp() override {
+ param_opcode_ = OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS;
+ LeScanningManagerTest::SetUp();
+ }
+
+ void HandleConfiguration() override {
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_SET_EXTENDED_SCAN_PARAMETERS);
+ test_hci_layer_->IncomingEvent(LeSetExtendedScanParametersCompleteBuilder::Create(1, ErrorCode::SUCCESS));
+ }
+};
+
+TEST_F(LeScanningManagerTest, startup_teardown) {}
+
+TEST_F(LeScanningManagerTest, start_scan_test) {
+ auto next_command_future = test_hci_layer_->GetCommandFuture();
+ le_scanning_manager->StartScan(&mock_callbacks_);
+
+ next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100)));
+ test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
+
+ LeAdvertisingReport report{};
+ report.event_type_ = AdvertisingEventType::ADV_IND;
+ report.address_type_ = AddressType::PUBLIC_DEVICE_ADDRESS;
+ Address::FromString("12:34:56:78:9a:bc", report.address_);
+ std::vector<GapData> gap_data{};
+ GapData data_item{};
+ data_item.data_type_ = GapDataType::FLAGS;
+ data_item.data_ = {0x34};
+ gap_data.push_back(data_item);
+ data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
+ data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
+ gap_data.push_back(data_item);
+ report.advertising_data_ = gap_data;
+
+ EXPECT_CALL(mock_callbacks_, on_advertisements);
+
+ test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({report}));
+}
+
+TEST_F(LeAndroidHciScanningManagerTest, start_scan_test) {
+ auto next_command_future = test_hci_layer_->GetCommandFuture();
+ le_scanning_manager->StartScan(&mock_callbacks_);
+
+ next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100)));
+ test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
+
+ LeAdvertisingReport report{};
+ report.event_type_ = AdvertisingEventType::ADV_IND;
+ report.address_type_ = AddressType::PUBLIC_DEVICE_ADDRESS;
+ Address::FromString("12:34:56:78:9a:bc", report.address_);
+ std::vector<GapData> gap_data{};
+ GapData data_item{};
+ data_item.data_type_ = GapDataType::FLAGS;
+ data_item.data_ = {0x34};
+ gap_data.push_back(data_item);
+ data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
+ data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
+ gap_data.push_back(data_item);
+ report.advertising_data_ = gap_data;
+
+ EXPECT_CALL(mock_callbacks_, on_advertisements);
+
+ test_hci_layer_->IncomingLeMetaEvent(LeAdvertisingReportBuilder::Create({report}));
+}
+
+TEST_F(LeExtendedScanningManagerTest, start_scan_test) {
+ auto next_command_future = test_hci_layer_->GetCommandFuture();
+ le_scanning_manager->StartScan(&mock_callbacks_);
+
+ next_command_future.wait_for(std::chrono::duration(std::chrono::milliseconds(100)));
+ auto packet = test_hci_layer_->GetCommandPacket(OpCode::LE_SET_EXTENDED_SCAN_ENABLE);
+
+ test_hci_layer_->IncomingEvent(LeSetScanEnableCompleteBuilder::Create(uint8_t{1}, ErrorCode::SUCCESS));
+
+ LeExtendedAdvertisingReport report{};
+ report.connectable_ = 1;
+ report.scannable_ = 1;
+ report.address_type_ = DirectAdvertisingAddressType::PUBLIC_DEVICE_ADDRESS;
+ Address::FromString("12:34:56:78:9a:bc", report.address_);
+ std::vector<GapData> gap_data{};
+ GapData data_item{};
+ data_item.data_type_ = GapDataType::FLAGS;
+ data_item.data_ = {0x34};
+ gap_data.push_back(data_item);
+ data_item.data_type_ = GapDataType::COMPLETE_LOCAL_NAME;
+ data_item.data_ = {'r', 'a', 'n', 'd', 'o', 'm', ' ', 'd', 'e', 'v', 'i', 'c', 'e'};
+ gap_data.push_back(data_item);
+ report.advertising_data_ = gap_data;
+
+ EXPECT_CALL(mock_callbacks_, on_advertisements);
+
+ test_hci_layer_->IncomingLeMetaEvent(LeExtendedAdvertisingReportBuilder::Create({report}));
+}
+
+} // namespace
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/le_security_interface.h b/gd/hci/le_security_interface.h
new file mode 100644
index 0000000..13c3ef3
--- /dev/null
+++ b/gd/hci/le_security_interface.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "common/callback.h"
+#include "hci/hci_packets.h"
+#include "os/handler.h"
+#include "os/utils.h"
+
+namespace bluetooth {
+namespace hci {
+
+class LeSecurityInterface {
+ public:
+ LeSecurityInterface() = default;
+ virtual ~LeSecurityInterface() = default;
+ DISALLOW_COPY_AND_ASSIGN(LeSecurityInterface);
+
+ virtual void EnqueueCommand(std::unique_ptr<LeSecurityCommandBuilder> command,
+ common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) = 0;
+
+ virtual void EnqueueCommand(std::unique_ptr<LeSecurityCommandBuilder> command,
+ common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) = 0;
+
+ static constexpr hci::SubeventCode LeSecurityEvents[] = {
+ hci::SubeventCode::LONG_TERM_KEY_REQUEST,
+ hci::SubeventCode::READ_LOCAL_P256_PUBLIC_KEY_COMPLETE,
+ hci::SubeventCode::GENERATE_DHKEY_COMPLETE,
+ };
+};
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/hci/security_interface.h b/gd/hci/security_interface.h
new file mode 100644
index 0000000..ea15aa0
--- /dev/null
+++ b/gd/hci/security_interface.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "common/callback.h"
+#include "hci/hci_packets.h"
+#include "os/utils.h"
+
+namespace bluetooth {
+namespace hci {
+
+class SecurityInterface {
+ public:
+ SecurityInterface() = default;
+ virtual ~SecurityInterface() = default;
+ DISALLOW_COPY_AND_ASSIGN(SecurityInterface);
+
+ virtual void EnqueueCommand(std::unique_ptr<SecurityCommandBuilder> command,
+ common::OnceCallback<void(CommandCompleteView)> on_complete, os::Handler* handler) = 0;
+
+ virtual void EnqueueCommand(std::unique_ptr<SecurityCommandBuilder> command,
+ common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) = 0;
+
+ static constexpr hci::EventCode SecurityEvents[] = {
+ hci::EventCode::ENCRYPTION_CHANGE, hci::EventCode::CHANGE_CONNECTION_LINK_KEY_COMPLETE,
+ hci::EventCode::MASTER_LINK_KEY_COMPLETE, hci::EventCode::RETURN_LINK_KEYS,
+ hci::EventCode::PIN_CODE_REQUEST, hci::EventCode::LINK_KEY_REQUEST,
+ hci::EventCode::LINK_KEY_NOTIFICATION, hci::EventCode::ENCRYPTION_KEY_REFRESH_COMPLETE,
+ hci::EventCode::IO_CAPABILITY_REQUEST, hci::EventCode::IO_CAPABILITY_RESPONSE,
+ hci::EventCode::REMOTE_OOB_DATA_REQUEST, hci::EventCode::SIMPLE_PAIRING_COMPLETE,
+ hci::EventCode::USER_PASSKEY_NOTIFICATION, hci::EventCode::KEYPRESS_NOTIFICATION,
+ hci::EventCode::USER_CONFIRMATION_REQUEST, hci::EventCode::USER_PASSKEY_REQUEST,
+ };
+};
+} // namespace hci
+} // namespace bluetooth
diff --git a/gd/l2cap/Android.bp b/gd/l2cap/Android.bp
new file mode 100644
index 0000000..51258b4
--- /dev/null
+++ b/gd/l2cap/Android.bp
@@ -0,0 +1,82 @@
+filegroup {
+ name: "BluetoothL2capSources",
+ srcs: [
+ "fcs.cc",
+ "classic/dynamic_channel.cc",
+ "classic/dynamic_channel_manager.cc",
+ "classic/dynamic_channel_service.cc",
+ "classic/fixed_channel.cc",
+ "classic/fixed_channel_manager.cc",
+ "classic/fixed_channel_service.cc",
+ "classic/internal/dynamic_channel_allocator.cc",
+ "classic/internal/dynamic_channel_impl.cc",
+ "classic/internal/dynamic_channel_service_manager_impl.cc",
+ "classic/internal/fixed_channel_impl.cc",
+ "classic/internal/fixed_channel_service_manager_impl.cc",
+ "classic/internal/link.cc",
+ "classic/internal/link_manager.cc",
+ "classic/internal/signalling_manager.cc",
+ "classic/l2cap_classic_module.cc",
+ "internal/basic_mode_channel_data_controller.cc",
+ "internal/data_pipeline_manager.cc",
+ "internal/enhanced_retransmission_mode_channel_data_controller.cc",
+ "internal/le_credit_based_channel_data_controller.cc",
+ "internal/receiver.cc",
+ "internal/scheduler_fifo.cc",
+ "internal/sender.cc",
+ "le/internal/fixed_channel_impl.cc",
+ "le/internal/fixed_channel_service_manager_impl.cc",
+ "le/internal/link_manager.cc",
+ "le/fixed_channel.cc",
+ "le/fixed_channel_manager.cc",
+ "le/fixed_channel_service.cc",
+ "le/l2cap_le_module.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothL2capTestSources",
+ srcs: [
+ "classic/internal/dynamic_channel_allocator_test.cc",
+ "classic/internal/dynamic_channel_impl_test.cc",
+ "classic/internal/dynamic_channel_service_manager_test.cc",
+ "classic/internal/fixed_channel_impl_test.cc",
+ "classic/internal/fixed_channel_service_manager_test.cc",
+ "classic/internal/link_manager_test.cc",
+ "classic/internal/signalling_manager_test.cc",
+ "internal/basic_mode_channel_data_controller_test.cc",
+ "internal/enhanced_retransmission_mode_channel_data_controller_test.cc",
+ "internal/fixed_channel_allocator_test.cc",
+ "internal/le_credit_based_channel_data_controller_test.cc",
+ "internal/receiver_test.cc",
+ "internal/scheduler_fifo_test.cc",
+ "internal/sender_test.cc",
+ "l2cap_packet_test.cc",
+ "le/internal/fixed_channel_impl_test.cc",
+ "le/internal/fixed_channel_service_manager_test.cc",
+ "le/internal/link_manager_test.cc",
+ "signal_id_test.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothFacade_l2cap_layer",
+ srcs: [
+ "classic/facade.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothCertSource_l2cap_layer",
+ srcs: [
+ "classic/cert/cert.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothL2capFuzzTestSources",
+ srcs: [
+ "classic/internal/dynamic_channel_allocator_fuzz_test.cc",
+ "l2cap_packet_fuzz_test.cc",
+ ],
+}
diff --git a/gd/l2cap/cid.h b/gd/l2cap/cid.h
new file mode 100644
index 0000000..729272c
--- /dev/null
+++ b/gd/l2cap/cid.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+namespace bluetooth {
+namespace l2cap {
+
+using Cid = uint16_t;
+
+constexpr Cid kInvalidCid = 0;
+constexpr Cid kFirstFixedChannel = 1;
+constexpr Cid kLastFixedChannel = 63;
+constexpr Cid kFirstDynamicChannel = kLastFixedChannel + 1;
+constexpr Cid kLastDynamicChannel = (uint16_t)(0xffff);
+
+constexpr Cid kClassicSignallingCid = 1;
+constexpr Cid kConnectionlessCid = 2;
+constexpr Cid kLeAttributeCid = 4;
+constexpr Cid kLeSignallingCid = 5;
+constexpr Cid kSmpCid = 6;
+constexpr Cid kSmpBrCid = 7;
+
+constexpr Cid kClassicPairingTriggerCid = kLastFixedChannel - 1;
+
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/cert/api.proto b/gd/l2cap/classic/cert/api.proto
new file mode 100644
index 0000000..a80e648
--- /dev/null
+++ b/gd/l2cap/classic/cert/api.proto
@@ -0,0 +1,206 @@
+syntax = "proto3";
+
+package bluetooth.l2cap.classic.cert;
+
+import "google/protobuf/empty.proto";
+import "facade/common.proto";
+
+service L2capClassicModuleCert {
+ rpc SendL2capPacket(L2capPacket) returns (google.protobuf.Empty) {}
+ rpc SendIFrame(IFrame) returns (SendIFrameResult) {}
+ rpc SendSFrame(SFrame) returns (SendSFrameResult) {}
+
+ rpc SetupLink(SetupLinkRequest) returns (SetupLinkResponse) {}
+ rpc DisconnectLink(DisconnectLinkRequest) returns (google.protobuf.Empty) {}
+
+ rpc SendConnectionRequest(ConnectionRequest) returns (google.protobuf.Empty) {}
+ rpc SendConnectionResponse(ConnectionResponse) returns (SendConnectionResponseResult) {}
+
+ rpc SendConfigurationRequest(ConfigurationRequest) returns (SendConfigurationRequestResult) {}
+ rpc SendConfigurationResponse(ConfigurationResponse) returns (SendConfigurationResponseResult) {}
+
+ rpc SendDisconnectionRequest(DisconnectionRequest) returns (google.protobuf.Empty) {}
+ rpc SendDisconnectionResponse(DisconnectionResponse) returns (SendDisconnectionResponseResult) {}
+
+ rpc SendInformationRequest(InformationRequest) returns (SendInformationRequestResult) {}
+ rpc SendInformationResponse(InformationResponse) returns (SendInformationResponseResult) {}
+
+ rpc FetchL2capLog(FetchL2capLogRequest) returns (stream FetchL2capLogResponse) {}
+ rpc StopFetchingL2capLog(StopFetchingL2capLogRequest) returns (StopFetchingL2capLogResponse) {}
+}
+
+message L2capPacket {
+ facade.BluetoothAddress remote = 1;
+ uint32 channel = 2;
+ bytes payload = 3;
+}
+
+message IFrame {
+ facade.BluetoothAddress remote = 1;
+ uint32 channel = 2;
+ uint32 sar = 3;
+ uint32 tx_seq = 4;
+ uint32 req_seq = 5;
+ uint32 f = 6;
+ uint32 sdu_size = 7;
+ bytes information = 8;
+}
+
+message SendIFrameResult {}
+
+message SFrame {
+ facade.BluetoothAddress remote = 1;
+ uint32 channel = 2;
+ uint32 req_seq = 3;
+ uint32 f = 4;
+ uint32 p = 5;
+ uint32 s = 6;
+}
+
+message SendSFrameResult {}
+
+message DisconnectLinkRequest {
+ facade.BluetoothAddress remote = 1;
+}
+
+message SetupLinkRequest {
+ facade.BluetoothAddress remote = 1;
+}
+
+message SetupLinkResponse {}
+
+message ConnectionRequest {
+ facade.BluetoothAddress remote = 1;
+ uint32 psm = 2;
+ uint32 scid = 3;
+ uint32 signal_id = 4;
+}
+
+message ConnectionResponse {
+ facade.BluetoothAddress remote = 1;
+ uint32 dcid = 2;
+ uint32 scid = 3;
+ uint32 signal_id = 4;
+}
+
+message SendConnectionResponseResult {}
+
+enum ChannelRetransmissionFlowControlMode {
+ BASIC = 0;
+ ERTM = 3;
+ STREAM = 4;
+}
+
+message ChannelRetransmissionFlowControlConfig {
+ ChannelRetransmissionFlowControlMode mode = 1;
+ uint32 tx_window = 2;
+ uint32 max_transmit = 3;
+ uint32 retransmit_timeout = 4;
+ uint32 monitor_timeout = 5;
+ uint32 mps = 6;
+}
+
+message ConfigurationRequest {
+ uint32 dcid = 1;
+ uint32 signal_id = 2;
+ uint32 mtu = 3;
+ ChannelRetransmissionFlowControlConfig retransmission_config = 4;
+ bool fcs = 5;
+}
+
+message SendConfigurationRequestResult {}
+
+message ConfigurationResponse {
+ uint32 scid = 1;
+ uint32 signal_id = 2;
+ uint32 mtu = 3;
+ ChannelRetransmissionFlowControlConfig retransmission_config = 4;
+ bool fcs = 5;
+}
+
+message SendConfigurationResponseResult {}
+
+message DisconnectionRequest {
+ facade.BluetoothAddress remote = 1;
+ uint32 dcid = 2;
+ uint32 scid = 3;
+ uint32 signal_id = 4;
+}
+
+message DisconnectionResponse {
+ facade.BluetoothAddress remote = 1;
+ uint32 dcid = 2;
+ uint32 scid = 3;
+ uint32 signal_id = 4;
+}
+
+message SendDisconnectionResponseResult {}
+
+enum InformationRequestType {
+ CONNECTIONLESS_MTU = 0;
+ EXTENDED_FEATURES = 1;
+ FIXED_CHANNELS = 2;
+}
+
+message InformationRequest {
+ InformationRequestType type = 1;
+ uint32 signal_id = 4;
+}
+
+message SendInformationRequestResult {}
+
+message InformationResponse {
+ InformationRequestType type = 1;
+ uint32 data = 2;
+ uint32 signal_id = 3;
+ uint32 information_value = 4;
+}
+
+message SendInformationResponseResult {}
+
+message FetchL2capLogRequest {}
+
+message CommandReject {
+ uint32 signal_id = 1;
+ uint32 reason = 2;
+}
+
+message EchoRequest {
+ uint32 signal_id = 1;
+ string data = 2;
+}
+message EchoResponse {
+ uint32 signal_id = 1;
+ string data = 2;
+}
+
+message LinkUp {
+ facade.BluetoothAddress remote = 1;
+}
+
+message LinkDown {
+ facade.BluetoothAddress remote = 1;
+}
+
+message FetchL2capLogResponse {
+ oneof response {
+ L2capPacket data_packet = 1;
+ CommandReject command_reject = 2;
+ ConnectionRequest connection_request = 3;
+ ConnectionResponse connection_response = 4;
+ ConfigurationRequest configuration_request = 5;
+ ConfigurationResponse configuration_response = 6;
+ DisconnectionRequest disconnection_request = 7;
+ DisconnectionResponse disconnection_response = 8;
+ EchoRequest echo_request = 9;
+ EchoResponse echo_response = 10;
+ InformationRequest information_request = 11;
+ InformationResponse information_response = 12;
+ LinkUp link_up = 20;
+ LinkDown link_down = 21;
+ }
+}
+
+message StopFetchingL2capLogRequest {}
+
+message StopFetchingL2capLogResponse {}
diff --git a/gd/l2cap/classic/cert/cert.cc b/gd/l2cap/classic/cert/cert.cc
new file mode 100644
index 0000000..abb3561
--- /dev/null
+++ b/gd/l2cap/classic/cert/cert.cc
@@ -0,0 +1,562 @@
+/*
+ * Copyright 2019 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 <condition_variable>
+#include <cstdint>
+#include <memory>
+#include <mutex>
+#include <queue>
+#include <unordered_map>
+
+#include "common/blocking_queue.h"
+#include "grpc/grpc_event_stream.h"
+#include "hci/acl_manager.h"
+#include "hci/cert/cert.h"
+#include "hci/hci_packets.h"
+#include "l2cap/classic/cert/api.grpc.pb.h"
+#include "l2cap/classic/cert/cert.h"
+#include "l2cap/classic/l2cap_classic_module.h"
+#include "l2cap/l2cap_packets.h"
+#include "os/log.h"
+#include "packet/raw_builder.h"
+
+using ::grpc::ServerAsyncResponseWriter;
+using ::grpc::ServerAsyncWriter;
+using ::grpc::ServerContext;
+
+using ::bluetooth::facade::EventStreamRequest;
+using ::bluetooth::packet::RawBuilder;
+
+using ::bluetooth::l2cap::classic::cert::L2capPacket;
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace cert {
+
+using namespace facade;
+
+constexpr auto kEventTimeout = std::chrono::seconds(1);
+
+class L2capClassicModuleCertService : public L2capClassicModuleCert::Service {
+ public:
+ L2capClassicModuleCertService(hci::AclManager* acl_manager, os::Handler* facade_handler)
+ : handler_(facade_handler), acl_manager_(acl_manager) {
+ ASSERT(handler_ != nullptr);
+ acl_manager_->RegisterCallbacks(&acl_callbacks, handler_);
+ }
+
+ ::grpc::Status SetupLink(::grpc::ServerContext* context,
+ const ::bluetooth::l2cap::classic::cert::SetupLinkRequest* request,
+ ::bluetooth::l2cap::classic::cert::SetupLinkResponse* response) override {
+ hci::Address address;
+ hci::Address::FromString(request->remote().address(), address);
+ LOG_INFO("%s", address.ToString().c_str());
+ acl_manager_->CreateConnection(address);
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendL2capPacket(::grpc::ServerContext* context, const L2capPacket* request,
+ ::google::protobuf::Empty* response) override {
+ std::unique_ptr<RawBuilder> packet = std::make_unique<RawBuilder>();
+ auto req_string = request->payload();
+ packet->AddOctets(std::vector<uint8_t>(req_string.begin(), req_string.end()));
+ std::unique_ptr<BasicFrameBuilder> l2cap_builder = BasicFrameBuilder::Create(request->channel(), std::move(packet));
+ outgoing_packet_queue_.push(std::move(l2cap_builder));
+ send_packet_from_queue();
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendIFrame(::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::IFrame* request,
+ ::bluetooth::l2cap::classic::cert::SendIFrameResult* response) override {
+ std::unique_ptr<RawBuilder> packet = std::make_unique<RawBuilder>();
+ auto req_string = request->information();
+ packet->AddOctets(std::vector<uint8_t>(req_string.begin(), req_string.end()));
+ std::unique_ptr<BasePacketBuilder> l2cap_builder;
+ auto f = static_cast<Final>(request->f());
+ if (request->sar() == static_cast<int>(SegmentationAndReassembly::START)) {
+ l2cap_builder = EnhancedInformationStartFrameBuilder::Create(
+ request->channel(), request->tx_seq(), f, request->req_seq(), request->sdu_size(), std::move(packet));
+ } else {
+ l2cap_builder = EnhancedInformationFrameBuilder::Create(
+ request->channel(), request->tx_seq(), f, request->req_seq(),
+ static_cast<SegmentationAndReassembly>(request->sar()), std::move(packet));
+ }
+ outgoing_packet_queue_.push(std::move(l2cap_builder));
+ send_packet_from_queue();
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendSFrame(::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::SFrame* request,
+ ::bluetooth::l2cap::classic::cert::SendSFrameResult* response) override {
+ auto f = static_cast<Final>(request->f());
+ auto p = static_cast<Poll>(request->p());
+ auto s = static_cast<SupervisoryFunction>(request->s());
+ auto builder = EnhancedSupervisoryFrameBuilder::Create(request->channel(), s, p, f, request->req_seq());
+ outgoing_packet_queue_.push(std::move(builder));
+ send_packet_from_queue();
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendConnectionRequest(::grpc::ServerContext* context, const cert::ConnectionRequest* request,
+ ::google::protobuf::Empty* response) override {
+ auto builder = ConnectionRequestBuilder::Create(request->signal_id(), request->psm(), request->scid());
+ auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+ outgoing_packet_queue_.push(std::move(l2cap_builder));
+ send_packet_from_queue();
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendConnectionResponse(
+ ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::ConnectionResponse* request,
+ ::bluetooth::l2cap::classic::cert::SendConnectionResponseResult* response) override {
+ auto builder = ConnectionResponseBuilder::Create(request->signal_id(), request->dcid(), request->scid(),
+ ConnectionResponseResult::SUCCESS,
+ ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
+ auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+ outgoing_packet_queue_.push(std::move(l2cap_builder));
+ send_packet_from_queue();
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendConfigurationRequest(
+ ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::ConfigurationRequest* request,
+ ::bluetooth::l2cap::classic::cert::SendConfigurationRequestResult* response) override {
+ std::vector<std::unique_ptr<ConfigurationOption>> config;
+ if (request->retransmission_config().mode() == ChannelRetransmissionFlowControlMode::ERTM) {
+ auto option = std::make_unique<RetransmissionAndFlowControlConfigurationOption>();
+ option->mode_ = RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION;
+ option->tx_window_size_ = 10;
+ option->max_transmit_ = 20;
+ option->retransmission_time_out_ = 2000;
+ option->monitor_time_out_ = 12000;
+ option->maximum_pdu_size_ = 1010;
+ config.push_back(std::move(option));
+ auto no_fcs = std::make_unique<FrameCheckSequenceOption>();
+ no_fcs->fcs_type_ = FcsType::NO_FCS;
+ config.push_back(std::move(no_fcs));
+ }
+ auto builder = ConfigurationRequestBuilder::Create(request->signal_id(), request->dcid(), Continuation::END,
+ std::move(config));
+ auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+ outgoing_packet_queue_.push(std::move(l2cap_builder));
+ send_packet_from_queue();
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendConfigurationResponse(
+ ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::ConfigurationResponse* request,
+ ::bluetooth::l2cap::classic::cert::SendConfigurationResponseResult* response) override {
+ std::vector<std::unique_ptr<ConfigurationOption>> config;
+ if (request->retransmission_config().mode() == ChannelRetransmissionFlowControlMode::ERTM) {
+ auto option = std::make_unique<RetransmissionAndFlowControlConfigurationOption>();
+ option->mode_ = RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION;
+ option->tx_window_size_ = 10;
+ option->max_transmit_ = 20;
+ option->retransmission_time_out_ = 2000;
+ option->monitor_time_out_ = 12000;
+ option->maximum_pdu_size_ = 1010;
+ config.push_back(std::move(option));
+ }
+ auto builder = ConfigurationResponseBuilder::Create(request->signal_id(), request->scid(), Continuation::END,
+ ConfigurationResponseResult::SUCCESS, std::move(config));
+ auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+ outgoing_packet_queue_.push(std::move(l2cap_builder));
+ send_packet_from_queue();
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendDisconnectionRequest(::grpc::ServerContext* context, const cert::DisconnectionRequest* request,
+ ::google::protobuf::Empty* response) override {
+ auto builder = DisconnectionRequestBuilder::Create(request->signal_id(), request->dcid(), request->scid());
+ auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+ outgoing_packet_queue_.push(std::move(l2cap_builder));
+ send_packet_from_queue();
+
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendDisconnectionResponse(
+ ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::DisconnectionResponse* request,
+ ::bluetooth::l2cap::classic::cert::SendDisconnectionResponseResult* response) override {
+ auto builder = DisconnectionResponseBuilder::Create(request->signal_id(), request->dcid(), request->scid());
+ auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+ outgoing_packet_queue_.push(std::move(l2cap_builder));
+ send_packet_from_queue();
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendInformationRequest(
+ ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::InformationRequest* request,
+ ::bluetooth::l2cap::classic::cert::SendInformationRequestResult* response) override {
+ switch (request->type()) {
+ case InformationRequestType::CONNECTIONLESS_MTU: {
+ auto builder =
+ InformationRequestBuilder::Create(request->signal_id(), InformationRequestInfoType::CONNECTIONLESS_MTU);
+ auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+ outgoing_packet_queue_.push(std::move(l2cap_builder));
+ send_packet_from_queue();
+ break;
+ }
+ case InformationRequestType::EXTENDED_FEATURES: {
+ auto builder = InformationRequestBuilder::Create(request->signal_id(),
+ InformationRequestInfoType::EXTENDED_FEATURES_SUPPORTED);
+ auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+ outgoing_packet_queue_.push(std::move(l2cap_builder));
+ send_packet_from_queue();
+ break;
+ }
+ case InformationRequestType::FIXED_CHANNELS: {
+ auto builder = InformationRequestBuilder::Create(request->signal_id(),
+ InformationRequestInfoType::FIXED_CHANNELS_SUPPORTED);
+ auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+ outgoing_packet_queue_.push(std::move(l2cap_builder));
+ send_packet_from_queue();
+ break;
+ }
+ default:
+ break;
+ }
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendInformationResponse(
+ ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::InformationResponse* request,
+ ::bluetooth::l2cap::classic::cert::SendInformationResponseResult* response) override {
+ switch (request->type()) {
+ case InformationRequestType::CONNECTIONLESS_MTU: {
+ auto builder = InformationResponseConnectionlessMtuBuilder::Create(request->signal_id(),
+ InformationRequestResult::SUCCESS, 100);
+ auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+ outgoing_packet_queue_.push(std::move(l2cap_builder));
+ send_packet_from_queue();
+ break;
+ }
+ case InformationRequestType::EXTENDED_FEATURES: {
+ auto builder = InformationResponseExtendedFeaturesBuilder::Create(
+ request->signal_id(), InformationRequestResult::SUCCESS, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);
+ auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+ outgoing_packet_queue_.push(std::move(l2cap_builder));
+ send_packet_from_queue();
+ break;
+ }
+ case InformationRequestType::FIXED_CHANNELS: {
+ constexpr uint64_t kSignallingChannelMask = 0x02;
+ auto builder = InformationResponseFixedChannelsBuilder::Create(
+ request->signal_id(), InformationRequestResult::SUCCESS, kSignallingChannelMask);
+ auto l2cap_builder = BasicFrameBuilder::Create(kClassicSignallingCid, std::move(builder));
+ outgoing_packet_queue_.push(std::move(l2cap_builder));
+ send_packet_from_queue();
+ break;
+ }
+ default:
+ break;
+ }
+
+ return ::grpc::Status::OK;
+ }
+
+ std::unique_ptr<packet::BasePacketBuilder> enqueue_packet_to_acl() {
+ auto basic_frame_builder = std::move(outgoing_packet_queue_.front());
+ outgoing_packet_queue_.pop();
+ if (outgoing_packet_queue_.size() == 0) {
+ acl_connection_->GetAclQueueEnd()->UnregisterEnqueue();
+ }
+ return basic_frame_builder;
+ }
+
+ ::grpc::Status FetchL2capLog(::grpc::ServerContext* context, const FetchL2capLogRequest* request,
+ ::grpc::ServerWriter<FetchL2capLogResponse>* writer) override {
+ fetching_l2cap_log_ = true;
+ while (!context->IsCancelled() && fetching_l2cap_log_) {
+ if (!l2cap_log_.empty()) {
+ auto& response = l2cap_log_.front();
+ writer->Write(response);
+ l2cap_log_.pop();
+ } else {
+ std::unique_lock<std::mutex> lock(l2cap_log_mutex_);
+ // TODO(hsz): Rather than hardcode 1 second wait time, we can add another RPC to allow client to inform the
+ // server to return the RPC early
+ auto status = l2cap_log_cv_.wait_for(lock, kEventTimeout);
+ if (status == std::cv_status::timeout) {
+ break;
+ }
+ }
+ }
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status StopFetchingL2capLog(
+ ::grpc::ServerContext* context, const ::bluetooth::l2cap::classic::cert::StopFetchingL2capLogRequest* request,
+ ::bluetooth::l2cap::classic::cert::StopFetchingL2capLogResponse* response) override {
+ fetching_l2cap_log_ = false;
+ l2cap_log_cv_.notify_one();
+ return ::grpc::Status::OK;
+ }
+
+ bool fetching_l2cap_log_ = false;
+ std::mutex l2cap_log_mutex_;
+ std::queue<FetchL2capLogResponse> l2cap_log_;
+ std::condition_variable l2cap_log_cv_;
+
+ class L2capStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<L2capPacket, L2capPacket> {
+ public:
+ void OnWriteResponse(L2capPacket* response, const L2capPacket& event) override {
+ response->CopyFrom(event);
+ }
+
+ } l2cap_stream_callback_;
+ ::bluetooth::grpc::GrpcEventStream<L2capPacket, L2capPacket> l2cap_stream_{&l2cap_stream_callback_};
+
+ void LogEvent(const FetchL2capLogResponse& response) {
+ l2cap_log_.push(response);
+ if (l2cap_log_.size() == 1) {
+ l2cap_log_cv_.notify_one();
+ }
+ }
+
+ void on_incoming_packet() {
+ auto packet = acl_connection_->GetAclQueueEnd()->TryDequeue();
+ BasicFrameView basic_frame_view = BasicFrameView::Create(*packet);
+ ASSERT(basic_frame_view.IsValid());
+ L2capPacket l2cap_packet;
+ auto payload = basic_frame_view.GetPayload();
+ std::string data = std::string(payload.begin(), payload.end());
+ l2cap_packet.set_payload(data);
+ l2cap_packet.set_channel(basic_frame_view.GetChannelId());
+ l2cap_stream_.OnIncomingEvent(l2cap_packet);
+ if (basic_frame_view.GetChannelId() == kClassicSignallingCid) {
+ ControlView control_view = ControlView::Create(basic_frame_view.GetPayload());
+ ASSERT(control_view.IsValid());
+ handle_signalling_packet(control_view);
+ } else {
+ FetchL2capLogResponse response;
+ response.mutable_data_packet()->set_channel(basic_frame_view.GetChannelId());
+ response.mutable_data_packet()->set_payload(data);
+ LogEvent(response);
+ }
+ }
+
+ void send_packet_from_queue() {
+ if (outgoing_packet_queue_.size() == 1) {
+ acl_connection_->GetAclQueueEnd()->RegisterEnqueue(
+ handler_, common::Bind(&L2capClassicModuleCertService::enqueue_packet_to_acl, common::Unretained(this)));
+ }
+ }
+
+ void handle_signalling_packet(ControlView control_view) {
+ auto code = control_view.GetCode();
+ switch (code) {
+ case CommandCode::COMMAND_REJECT: {
+ CommandRejectView view = CommandRejectView::Create(control_view);
+ ASSERT(view.IsValid());
+ FetchL2capLogResponse response;
+ response.mutable_command_reject()->set_signal_id(control_view.GetIdentifier());
+ LogEvent(response);
+ break;
+ }
+ case CommandCode::CONNECTION_REQUEST: {
+ ConnectionRequestView view = ConnectionRequestView::Create(control_view);
+ ASSERT(view.IsValid());
+ FetchL2capLogResponse response;
+ response.mutable_connection_request()->set_signal_id(control_view.GetIdentifier());
+ response.mutable_connection_request()->set_scid(view.GetSourceCid());
+ response.mutable_connection_request()->set_psm(view.GetPsm());
+ LogEvent(response);
+ break;
+ }
+ case CommandCode::CONNECTION_RESPONSE: {
+ ConnectionResponseView view = ConnectionResponseView::Create(control_view);
+ ASSERT(view.IsValid());
+ FetchL2capLogResponse response;
+ response.mutable_connection_response()->set_signal_id(control_view.GetIdentifier());
+ response.mutable_connection_response()->set_scid(view.GetSourceCid());
+ response.mutable_connection_response()->set_dcid(view.GetDestinationCid());
+ LogEvent(response);
+ break;
+ }
+
+ case CommandCode::CONFIGURATION_REQUEST: {
+ ConfigurationRequestView view = ConfigurationRequestView::Create(control_view);
+ ASSERT(view.IsValid());
+ FetchL2capLogResponse response;
+ response.mutable_configuration_request()->set_signal_id(control_view.GetIdentifier());
+ response.mutable_configuration_request()->set_dcid(view.GetDestinationCid());
+ LogEvent(response);
+ break;
+ }
+ case CommandCode::CONFIGURATION_RESPONSE: {
+ ConfigurationResponseView view = ConfigurationResponseView::Create(control_view);
+ ASSERT(view.IsValid());
+ FetchL2capLogResponse response;
+ response.mutable_configuration_response()->set_signal_id(control_view.GetIdentifier());
+ response.mutable_configuration_response()->set_scid(view.GetSourceCid());
+ LogEvent(response);
+ break;
+ }
+ case CommandCode::DISCONNECTION_RESPONSE: {
+ DisconnectionResponseView view = DisconnectionResponseView::Create(control_view);
+ ASSERT(view.IsValid());
+ FetchL2capLogResponse response;
+ response.mutable_disconnection_response()->set_signal_id(control_view.GetIdentifier());
+ response.mutable_disconnection_response()->set_dcid(view.GetDestinationCid());
+ response.mutable_disconnection_response()->set_scid(view.GetSourceCid());
+ LogEvent(response);
+ break;
+ }
+ case CommandCode::ECHO_RESPONSE: {
+ EchoResponseView view = EchoResponseView::Create(control_view);
+ ASSERT(view.IsValid());
+ FetchL2capLogResponse response;
+ response.mutable_echo_response()->set_signal_id(control_view.GetIdentifier());
+ LogEvent(response);
+ break;
+ }
+ case CommandCode::INFORMATION_REQUEST: {
+ InformationRequestView information_request_view = InformationRequestView::Create(control_view);
+ if (!information_request_view.IsValid()) {
+ return;
+ }
+ FetchL2capLogResponse log_response;
+ log_response.mutable_information_request()->set_signal_id(control_view.GetIdentifier());
+ auto type = information_request_view.GetInfoType();
+ switch (type) {
+ case InformationRequestInfoType::CONNECTIONLESS_MTU: {
+ log_response.mutable_information_request()->set_type(InformationRequestType::CONNECTIONLESS_MTU);
+ break;
+ }
+ case InformationRequestInfoType::EXTENDED_FEATURES_SUPPORTED: {
+ log_response.mutable_information_request()->set_type(InformationRequestType::EXTENDED_FEATURES);
+ break;
+ }
+ case InformationRequestInfoType::FIXED_CHANNELS_SUPPORTED: {
+ log_response.mutable_information_request()->set_type(InformationRequestType::FIXED_CHANNELS);
+ break;
+ }
+ }
+ LogEvent(log_response);
+ break;
+ }
+ case CommandCode::INFORMATION_RESPONSE: {
+ InformationResponseView information_response_view = InformationResponseView::Create(control_view);
+ if (!information_response_view.IsValid()) {
+ return;
+ }
+ FetchL2capLogResponse log_response;
+ log_response.mutable_information_response()->set_signal_id(control_view.GetIdentifier());
+ auto type = information_response_view.GetInfoType();
+ switch (type) {
+ case InformationRequestInfoType::CONNECTIONLESS_MTU: {
+ auto view = InformationResponseConnectionlessMtuView::Create(information_response_view);
+ if (!view.IsValid()) {
+ return;
+ }
+ log_response.mutable_information_response()->set_type(InformationRequestType::CONNECTIONLESS_MTU);
+ log_response.mutable_information_response()->set_information_value(view.GetConnectionlessMtu());
+ break;
+ }
+ case InformationRequestInfoType::EXTENDED_FEATURES_SUPPORTED: {
+ auto view = InformationResponseExtendedFeaturesView::Create(information_response_view);
+ if (!view.IsValid()) {
+ return;
+ }
+ log_response.mutable_information_response()->set_type(InformationRequestType::EXTENDED_FEATURES);
+ int mask = view.GetEnhancedRetransmissionMode() << 3 | view.GetFcsOption() << 5;
+ log_response.mutable_information_response()->set_information_value(mask);
+ break;
+ }
+ case InformationRequestInfoType::FIXED_CHANNELS_SUPPORTED: {
+ auto view = InformationResponseFixedChannelsView::Create(information_response_view);
+ if (!view.IsValid()) {
+ return;
+ }
+ log_response.mutable_information_response()->set_type(InformationRequestType::FIXED_CHANNELS);
+ log_response.mutable_information_response()->set_information_value(view.GetFixedChannels());
+ break;
+ }
+ }
+ LogEvent(log_response);
+ break;
+ }
+ default:
+ return;
+ }
+ }
+
+ std::queue<std::unique_ptr<BasePacketBuilder>> outgoing_packet_queue_;
+ ::bluetooth::os::Handler* handler_;
+ hci::AclManager* acl_manager_;
+ std::unique_ptr<hci::AclConnection> acl_connection_;
+
+ class AclCallbacks : public hci::ConnectionCallbacks {
+ public:
+ AclCallbacks(L2capClassicModuleCertService* module) : module_(module) {}
+ void OnConnectSuccess(std::unique_ptr<hci::AclConnection> connection) override {
+ module_->acl_connection_ = std::move(connection);
+ module_->acl_connection_->RegisterDisconnectCallback(common::BindOnce([](hci::ErrorCode) {}), module_->handler_);
+ module_->acl_connection_->GetAclQueueEnd()->RegisterDequeue(
+ module_->handler_,
+ common::Bind(&L2capClassicModuleCertService::on_incoming_packet, common::Unretained(module_)));
+ dequeue_registered_ = true;
+ FetchL2capLogResponse response;
+ response.mutable_link_up()->mutable_remote()->set_address(module_->acl_connection_->GetAddress().ToString());
+ module_->LogEvent(response);
+ }
+ void OnConnectFail(hci::Address address, hci::ErrorCode reason) override {}
+
+ ~AclCallbacks() {
+ if (dequeue_registered_) {
+ module_->acl_connection_->GetAclQueueEnd()->UnregisterDequeue();
+ }
+ }
+
+ bool dequeue_registered_ = false;
+
+ L2capClassicModuleCertService* module_;
+ } acl_callbacks{this};
+
+ std::mutex mutex_;
+};
+
+void L2capClassicModuleCertModule::ListDependencies(ModuleList* list) {
+ ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
+ list->add<hci::AclManager>();
+ list->add<hci::HciLayer>();
+}
+
+void L2capClassicModuleCertModule::Start() {
+ ::bluetooth::grpc::GrpcFacadeModule::Start();
+ GetDependency<hci::HciLayer>()->EnqueueCommand(hci::WriteScanEnableBuilder::Create(hci::ScanEnable::PAGE_SCAN_ONLY),
+ common::BindOnce([](hci::CommandCompleteView) {}), GetHandler());
+ service_ = new L2capClassicModuleCertService(GetDependency<hci::AclManager>(), GetHandler());
+}
+
+void L2capClassicModuleCertModule::Stop() {
+ delete service_;
+ ::bluetooth::grpc::GrpcFacadeModule::Stop();
+}
+
+::grpc::Service* L2capClassicModuleCertModule::GetService() const {
+ return service_;
+}
+
+const ModuleFactory L2capClassicModuleCertModule::Factory =
+ ::bluetooth::ModuleFactory([]() { return new L2capClassicModuleCertModule(); });
+
+} // namespace cert
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/cert/cert.h b/gd/l2cap/classic/cert/cert.h
new file mode 100644
index 0000000..d3108cd
--- /dev/null
+++ b/gd/l2cap/classic/cert/cert.h
@@ -0,0 +1,31 @@
+#pragma once
+
+#include <grpc++/grpc++.h>
+
+#include "grpc/grpc_module.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace cert {
+
+class L2capClassicModuleCertService;
+
+class L2capClassicModuleCertModule : public ::bluetooth::grpc::GrpcFacadeModule {
+ public:
+ static const ModuleFactory Factory;
+
+ void ListDependencies(ModuleList* list) override;
+ void Start() override;
+ void Stop() override;
+
+ ::grpc::Service* GetService() const override;
+
+ private:
+ L2capClassicModuleCertService* service_;
+};
+
+} // namespace cert
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/cert/simple_l2cap_test.py b/gd/l2cap/classic/cert/simple_l2cap_test.py
new file mode 100644
index 0000000..607cfb2
--- /dev/null
+++ b/gd/l2cap/classic/cert/simple_l2cap_test.py
@@ -0,0 +1,406 @@
+#!/usr/bin/env python3
+#
+# Copyright 2019 - 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.
+from __future__ import print_function
+
+import os
+import sys
+sys.path.append(os.environ['ANDROID_BUILD_TOP'] + '/system/bt/gd')
+
+from cert.gd_base_test import GdBaseTestClass
+from cert import rootservice_pb2 as cert_rootservice_pb2
+from facade import common_pb2
+from facade import rootservice_pb2 as facade_rootservice_pb2
+from google.protobuf import empty_pb2
+from l2cap.classic import facade_pb2 as l2cap_facade_pb2
+from l2cap.classic.cert import api_pb2 as l2cap_cert_pb2
+
+import time
+
+ASYNC_OP_TIME_SECONDS = 1 # TODO: Use events to synchronize events instead
+
+class EventHandler:
+ def __init__(self):
+ self._handler_map = {}
+
+ def on(self, matcher, func):
+ self._handler_map[matcher] = func
+
+ def execute(self, grpc_stream):
+ for result in grpc_stream:
+ for matcher, func in self._handler_map.items():
+ if matcher(result):
+ func(result)
+
+def is_connection_request(log):
+ return log.HasField("connection_request")
+
+def is_connection_response(log):
+ return log.HasField("connection_response")
+
+def is_configuration_request(log):
+ return log.HasField("configuration_request")
+
+def is_configuration_response(log):
+ return log.HasField("configuration_response")
+
+def is_disconnection_request(log):
+ return log.HasField("disconnection_request")
+
+def is_disconnection_response(log):
+ return log.HasField("disconnection_response")
+
+def is_echo_response(log):
+ return log.HasField("echo_response")
+
+def is_information_request(log):
+ return log.HasField("information_request")
+
+def is_information_response(log):
+ return log.HasField("information_response")
+
+def is_command_reject(log):
+ return log.HasField("command_reject")
+
+def basic_frame_to_enhanced_information_frame(information_payload):
+ return information_payload[2:]
+
+class SimpleL2capTest(GdBaseTestClass):
+ def setup_test(self):
+ self.device_under_test = self.gd_devices[0]
+ self.cert_device = self.gd_cert_devices[0]
+ self.device_under_test.rootservice.StartStack(
+ facade_rootservice_pb2.StartStackRequest(
+ module_under_test=facade_rootservice_pb2.BluetoothModule.Value('L2CAP'),
+ )
+ )
+ self.cert_device.rootservice.StartStack(
+ cert_rootservice_pb2.StartStackRequest(
+ module_to_test=cert_rootservice_pb2.BluetoothModule.Value('L2CAP'),
+ )
+ )
+
+ self.device_under_test.wait_channel_ready()
+ self.cert_device.wait_channel_ready()
+
+ dut_address = self.device_under_test.controller_read_only_property.ReadLocalAddress(empty_pb2.Empty()).address
+ self.device_under_test.address = dut_address
+ cert_address = self.cert_device.controller_read_only_property.ReadLocalAddress(empty_pb2.Empty()).address
+ self.cert_device.address = cert_address
+
+ self.dut_address = common_pb2.BluetoothAddress(
+ address=self.device_under_test.address)
+ self.cert_address = common_pb2.BluetoothAddress(
+ address=self.cert_device.address)
+
+ log_event_handler = EventHandler()
+ self.next_scid = 0x40
+ self.scid_dcid_map = {}
+ self.retransmission_mode = l2cap_cert_pb2.ChannelRetransmissionFlowControlMode.BASIC
+ def handle_connection_request(log):
+ log = log.connection_request
+ self.cert_device.l2cap.SendConnectionResponse(l2cap_cert_pb2.ConnectionResponse(dcid=self.next_scid,scid=log.scid,
+ signal_id=log.signal_id))
+ self.scid_dcid_map[self.next_scid] = log.scid
+ self.next_scid += 1
+ self.cert_device.l2cap.SendConfigurationRequest(l2cap_cert_pb2.ConfigurationRequest(
+ dcid=log.scid,
+ signal_id=log.signal_id+1,
+ retransmission_config=l2cap_cert_pb2.ChannelRetransmissionFlowControlConfig(
+ mode=self.retransmission_mode
+ )))
+ log_event_handler.on(is_connection_request, handle_connection_request)
+
+ def handle_connection_response(log):
+ log = log.connection_response
+ self.scid_dcid_map[log.scid] = log.dcid
+ self.cert_device.l2cap.SendConfigurationRequest(l2cap_cert_pb2.ConfigurationRequest(
+ dcid=log.dcid,
+ signal_id=log.signal_id+1,
+ retransmission_config=l2cap_cert_pb2.ChannelRetransmissionFlowControlConfig(
+ mode=self.retransmission_mode
+ )))
+ log_event_handler.on(is_connection_response, handle_connection_response)
+
+ def handle_configuration_request(log):
+ log = log.configuration_request
+ if log.dcid not in self.scid_dcid_map:
+ return
+ dcid = self.scid_dcid_map[log.dcid]
+ self.cert_device.l2cap.SendConfigurationResponse(l2cap_cert_pb2.ConfigurationResponse(
+ scid=dcid,
+ signal_id=log.signal_id,
+ ))
+ log_event_handler.on(is_configuration_request, handle_configuration_request)
+
+ def handle_disconnection_request(log):
+ log = log.disconnection_request
+ self.cert_device.l2cap.SendDisconnectionResponse(l2cap_cert_pb2.DisconnectionResponse(dcid=log.dcid,scid=log.scid,
+ signal_id=log.signal_id))
+ log_event_handler.on(is_disconnection_request, handle_disconnection_request)
+
+ def handle_information_request(log):
+ log = log.information_request
+ self.cert_device.l2cap.SendInformationResponse(l2cap_cert_pb2.InformationResponse(type=log.type,
+ signal_id=log.signal_id))
+ log_event_handler.on(is_information_request, handle_information_request)
+
+ self.event_dump = []
+ def dump_log(log):
+ self.event_dump.append(log)
+ log_event_handler.on(lambda _: True, dump_log)
+ self.event_handler = log_event_handler
+
+ def teardown_test(self):
+ self.device_under_test.rootservice.StopStack(
+ facade_rootservice_pb2.StopStackRequest()
+ )
+ self.cert_device.rootservice.StopStack(
+ cert_rootservice_pb2.StopStackRequest()
+ )
+
+ def _setup_link(self):
+ self.cert_device.l2cap.SetupLink(l2cap_cert_pb2.SetupLinkRequest(remote=self.dut_address))
+ link_up_handled = []
+ def handle_link_up(log):
+ log = log.link_up
+ link_up_handled.append(log.remote)
+ self.event_handler.on(lambda log : log.HasField("link_up"), handle_link_up)
+ logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+ self.event_handler.execute(logs)
+ assert self.dut_address in link_up_handled
+
+ def _open_channel(self, scid=0x0101, psm=0x33):
+ self.device_under_test.l2cap.SetDynamicChannel(l2cap_facade_pb2.SetEnableDynamicChannelRequest(psm=psm))
+
+ configuration_response_handled = []
+ def handle_configuration_response(log):
+ log = log.configuration_response
+ configuration_response_handled.append(log.scid)
+ self.event_handler.on(is_configuration_response, handle_configuration_response)
+ self.cert_device.l2cap.SendConnectionRequest(l2cap_cert_pb2.ConnectionRequest(scid=scid, psm=psm))
+ logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+ self.event_handler.execute(logs)
+ assert scid in configuration_response_handled
+
+ def test_connect(self):
+ self._setup_link()
+ self._open_channel(scid=0x0101)
+ self.cert_device.l2cap.StopFetchingL2capLog(l2cap_cert_pb2.StopFetchingL2capLogRequest())
+
+ def test_connect_and_send_data_ertm_no_segmentation(self):
+ self.retransmission_mode = l2cap_cert_pb2.ChannelRetransmissionFlowControlMode.ERTM
+ self.device_under_test.l2cap.RegisterChannel(l2cap_facade_pb2.RegisterChannelRequest(channel=2))
+ self.device_under_test.l2cap.SetDynamicChannel(l2cap_facade_pb2.SetEnableDynamicChannelRequest(psm=0x33, retransmission_mode=l2cap_facade_pb2.RetransmissionFlowControlMode.ERTM))
+ self._setup_link()
+ scid = 0x0101
+ self._open_channel(scid=scid)
+ self.device_under_test.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=2, payload=b"123"))
+
+ data_received = []
+ event_handler = EventHandler()
+ def on_data_received(log):
+ log = log.data_packet
+ if (log.channel == scid):
+ log.payload = basic_frame_to_enhanced_information_frame(log.payload)
+ self.cert_device.l2cap.SendSFrame(l2cap_cert_pb2.SFrame(channel=self.scid_dcid_map[scid], req_seq=1, s=0))
+ data_received.append((log.channel, log.payload))
+ event_handler.on(lambda log : log.HasField("data_packet"), on_data_received)
+ logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+ event_handler.execute(logs)
+ assert (2, b"123") in data_received
+
+ self.device_under_test.l2cap.SendDynamicChannelPacket(l2cap_facade_pb2.DynamicChannelPacket(psm=0x33, payload=b'abc'*34))
+
+ self.cert_device.l2cap.SendIFrame(l2cap_cert_pb2.IFrame(channel=self.scid_dcid_map[scid], req_seq=1, tx_seq=0, sar=0, information=b"abcd"))
+
+ logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+ event_handler.execute(logs)
+ assert (scid, b"abc"*34) in data_received
+
+ def test_connect_and_send_data(self):
+ self.device_under_test.l2cap.RegisterChannel(l2cap_facade_pb2.RegisterChannelRequest(channel=2))
+ self.device_under_test.l2cap.SetDynamicChannel(l2cap_facade_pb2.SetEnableDynamicChannelRequest(psm=0x33))
+ self._setup_link()
+ scid = 0x0101
+ self._open_channel(scid=scid)
+ self.device_under_test.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=2, payload=b"123"))
+
+ data_received = []
+ event_handler = EventHandler()
+ def on_data_received(log):
+ log = log.data_packet
+ data_received.append((log.channel, log.payload))
+ event_handler.on(lambda log : log.HasField("data_packet"), on_data_received)
+ logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+ event_handler.execute(logs)
+ assert (2, b"123") in data_received
+
+ self.device_under_test.l2cap.SendDynamicChannelPacket(l2cap_facade_pb2.DynamicChannelPacket(psm=0x33, payload=b'abc'))
+ logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+ event_handler.execute(logs)
+ assert (scid, b"abc") in data_received
+ self.cert_device.l2cap.StopFetchingL2capLog(l2cap_cert_pb2.StopFetchingL2capLogRequest())
+
+ def test_open_two_channels(self):
+ self._setup_link()
+ self._open_channel(scid=0x0101, psm=0x1)
+ self._open_channel(scid=0x0102, psm=0x3)
+ self.cert_device.l2cap.StopFetchingL2capLog(l2cap_cert_pb2.StopFetchingL2capLogRequest())
+
+ def test_accept_disconnect(self):
+ """
+ L2CAP/COS/CED/BV-07-C
+ """
+ self._setup_link()
+ scid=0x0101
+ self._open_channel(scid=scid, psm=0x1)
+ dcid = self.scid_dcid_map[scid]
+ disconnection_response_handled = []
+ def handle_disconnection_response(log):
+ log = log.disconnection_response
+ disconnection_response_handled.append((log.scid, log.dcid))
+ self.cert_device.l2cap.StopFetchingL2capLog(l2cap_cert_pb2.StopFetchingL2capLogRequest())
+ self.event_handler.on(is_disconnection_response, handle_disconnection_response)
+ self.cert_device.l2cap.SendDisconnectionRequest(l2cap_cert_pb2.DisconnectionRequest(scid=scid, dcid=dcid, signal_id=2))
+ logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+ self.event_handler.execute(logs)
+ assert (scid, dcid) in disconnection_response_handled
+
+ def test_disconnect_on_timeout(self):
+ """
+ L2CAP/COS/CED/BV-08-C
+ """
+ self._setup_link()
+ scid = 0x0101
+ psm = 1
+ self._open_channel(scid=0x0101, psm=0x1)
+
+ self.device_under_test.l2cap.SetDynamicChannel(l2cap_facade_pb2.SetEnableDynamicChannelRequest(psm=psm))
+
+ # Don't send configuration response back
+ self.event_handler.on(is_configuration_request, lambda _: True)
+ self.cert_device.l2cap.SendConnectionRequest(l2cap_cert_pb2.ConnectionRequest(scid=scid, psm=psm))
+ logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+ self.event_handler.execute(logs)
+ time.sleep(3)
+ def handle_configuration_response(log):
+ # DUT should not send configuration response due to timeout
+ assert False
+ self.event_handler.on(is_configuration_response, handle_configuration_response)
+ logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+ self.event_handler.execute(logs)
+
+ def test_basic_operation_request_connection(self):
+ """
+ L2CAP/COS/CED/BV-01-C [Request Connection]
+ Verify that the IUT is able to request the connection establishment for an L2CAP data channel and
+ initiate the configuration procedure.
+ """
+ psm = 1
+ # TODO: Use another test case
+ self.device_under_test.l2cap.OpenChannel(l2cap_facade_pb2.OpenChannelRequest(remote=self.cert_address, psm=psm))
+ connection_request = []
+ def handle_connection_request(log):
+ log = log.connection_request
+ connection_request.append(log.psm)
+ self.cert_device.l2cap.StopFetchingL2capLog(l2cap_cert_pb2.StopFetchingL2capLogRequest())
+ self.event_handler.on(is_connection_request, handle_connection_request)
+ logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+ self.event_handler.execute(logs)
+ assert psm in connection_request
+
+ def test_respond_to_echo_request(self):
+ """
+ L2CAP/COS/ECH/BV-01-C [Respond to Echo Request]
+ Verify that the IUT responds to an echo request.
+ """
+ self._setup_link()
+ # TODO: Replace with constructed packets when PDL is available
+ echo_request_packet = b"\x08\x01\x00\x00"
+ self.cert_device.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=1, payload=echo_request_packet))
+ echo_response = []
+ def handle_echo_response(log):
+ log = log.echo_response
+ echo_response.append(log.signal_id)
+ self.cert_device.l2cap.StopFetchingL2capLog(l2cap_cert_pb2.StopFetchingL2capLogRequest())
+ self.event_handler.on(is_echo_response, handle_echo_response)
+ logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+ self.event_handler.execute(logs)
+ assert 0x01 in echo_response
+
+ def test_reject_unknown_command(self):
+ """
+ L2CAP/COS/CED/BI-01-C
+ """
+ self._setup_link()
+ # TODO: Replace with constructed packets when PDL is available
+ invalid_command_packet = b"\xff\x01\x00\x00"
+ self.cert_device.l2cap.SendL2capPacket(l2cap_facade_pb2.L2capPacket(channel=1, payload=invalid_command_packet))
+ command_reject_packet = b"\x01\x01\x02\x00\x00\x00"
+ command_reject = []
+ def handle_command_reject(log):
+ log = log.command_reject
+ command_reject.append(log.signal_id)
+ self.cert_device.l2cap.StopFetchingL2capLog(l2cap_cert_pb2.StopFetchingL2capLogRequest())
+ self.event_handler.on(is_command_reject, handle_command_reject)
+ logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+ self.event_handler.execute(logs)
+ assert 0x01 in command_reject
+
+ def test_query_for_1_2_features(self):
+ """
+ L2CAP/COS/IEX/BV-01-C [Query for 1.2 Features]
+ """
+ self._setup_link()
+ signal_id = 3
+ self.cert_device.l2cap.SendInformationRequest(
+ l2cap_cert_pb2.InformationRequest(
+ type=l2cap_cert_pb2.InformationRequestType.FIXED_CHANNELS, signal_id=signal_id))
+ info_response = []
+ def handle_info_response(log):
+ log = log.information_response
+ info_response.append((log.signal_id, log.type))
+ self.cert_device.l2cap.StopFetchingL2capLog(l2cap_cert_pb2.StopFetchingL2capLogRequest())
+ self.event_handler.on(is_information_response, handle_info_response)
+ logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+ self.event_handler.execute(logs)
+ assert (signal_id, l2cap_cert_pb2.InformationRequestType.FIXED_CHANNELS) in info_response
+
+
+ def test_extended_feature_info_response_ertm(self):
+ """
+ L2CAP/EXF/BV-01-C [Extended Features Information Response for Enhanced
+ Retransmission Mode]
+ """
+ self._setup_link()
+ signal_id = 3
+ self.cert_device.l2cap.SendInformationRequest(
+ l2cap_cert_pb2.InformationRequest(
+ type=l2cap_cert_pb2.InformationRequestType.EXTENDED_FEATURES, signal_id=signal_id))
+ info_response = []
+ def handle_info_response(log):
+ log = log.information_response
+ info_response.append((log.signal_id, log.type, log.information_value))
+ self.cert_device.l2cap.StopFetchingL2capLog(l2cap_cert_pb2.StopFetchingL2capLogRequest())
+ self.event_handler.on(is_information_response, handle_info_response)
+ logs = self.cert_device.l2cap.FetchL2capLog(l2cap_cert_pb2.FetchL2capLogRequest())
+ self.event_handler.execute(logs)
+ expected_log_type = l2cap_cert_pb2.InformationRequestType.EXTENDED_FEATURES
+ expected_mask = 1 << 3
+ assert len(info_response) == 1
+ assert info_response[0][0] == signal_id
+ assert info_response[0][1] == expected_log_type
+ assert info_response[0][2] | expected_mask == expected_mask
diff --git a/gd/l2cap/classic/dynamic_channel.cc b/gd/l2cap/classic/dynamic_channel.cc
new file mode 100644
index 0000000..b888b91
--- /dev/null
+++ b/gd/l2cap/classic/dynamic_channel.cc
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 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 "l2cap/classic/dynamic_channel.h"
+#include "common/bind.h"
+#include "l2cap/classic/internal/dynamic_channel_impl.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+hci::Address DynamicChannel::GetDevice() const {
+ return impl_->GetDevice();
+}
+
+void DynamicChannel::RegisterOnCloseCallback(os::Handler* user_handler,
+ DynamicChannel::OnCloseCallback on_close_callback) {
+ l2cap_handler_->Post(common::BindOnce(&internal::DynamicChannelImpl::RegisterOnCloseCallback, impl_, user_handler,
+ std::move(on_close_callback)));
+}
+
+void DynamicChannel::Close() {
+ l2cap_handler_->Post(common::BindOnce(&internal::DynamicChannelImpl::Close, impl_));
+}
+
+common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>*
+DynamicChannel::GetQueueUpEnd() const {
+ return impl_->GetQueueUpEnd();
+}
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/dynamic_channel.h b/gd/l2cap/classic/dynamic_channel.h
new file mode 100644
index 0000000..eb52c16
--- /dev/null
+++ b/gd/l2cap/classic/dynamic_channel.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include "common/bidi_queue.h"
+#include "common/callback.h"
+#include "hci/acl_manager.h"
+#include "os/handler.h"
+#include "packet/base_packet_builder.h"
+#include "packet/packet_view.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+namespace internal {
+class DynamicChannelImpl;
+} // namespace internal
+
+/**
+ * L2CAP Dynamic channel object. User needs to call Close() when user no longer wants to use it. Otherwise the link
+ * won't be disconnected.
+ */
+class DynamicChannel {
+ public:
+ // Should only be constructed by modules that have access to LinkManager
+ DynamicChannel(std::shared_ptr<internal::DynamicChannelImpl> impl, os::Handler* l2cap_handler)
+ : impl_(std::move(impl)), l2cap_handler_(l2cap_handler) {
+ ASSERT(impl_ != nullptr);
+ ASSERT(l2cap_handler_ != nullptr);
+ }
+
+ hci::Address GetDevice() const;
+
+ /**
+ * Register close callback. If close callback is registered, when a channel is closed, the channel's resource will
+ * only be freed after on_close callback is invoked. Otherwise, if no on_close callback is registered, the channel's
+ * resource will be freed immediately after closing.
+ *
+ * @param user_handler The handler used to invoke the callback on
+ * @param on_close_callback The callback invoked upon channel closing.
+ */
+ using OnCloseCallback = common::OnceCallback<void(hci::ErrorCode)>;
+ void RegisterOnCloseCallback(os::Handler* user_handler, OnCloseCallback on_close_callback);
+
+ /**
+ * Indicate that this Dynamic Channel should be closed. OnCloseCallback will be invoked when channel close is done.
+ * L2cay layer may terminate this ACL connection to free the resource after channel is closed.
+ */
+ void Close();
+
+ /**
+ * This method will retrieve the data channel queue to send and receive packets.
+ *
+ * {@see BidiQueueEnd}
+ *
+ * @return The upper end of a bi-directional queue.
+ */
+ common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>* GetQueueUpEnd() const;
+
+ private:
+ std::shared_ptr<internal::DynamicChannelImpl> impl_;
+ os::Handler* l2cap_handler_;
+};
+
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/dynamic_channel_configuration_option.h b/gd/l2cap/classic/dynamic_channel_configuration_option.h
new file mode 100644
index 0000000..3f3cc02
--- /dev/null
+++ b/gd/l2cap/classic/dynamic_channel_configuration_option.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "l2cap/mtu.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+/**
+ * Configuration Option specified by L2CAP Channel user on a dynamic channel. L2CAP module will configure the channel
+ * based on user provided option.
+ */
+struct DynamicChannelConfigurationOption {
+ enum class RetransmissionAndFlowControlMode {
+ L2CAP_BASIC,
+ ENHANCED_RETRANSMISSION,
+ };
+ /**
+ * Retransmission and flow control mode. Currently L2CAP_BASIC and ENHANCED_RETRANSMISSION.
+ * If the remote doesn't support a mode, it might fall back to basic, as this is a negotiable option.
+ */
+ RetransmissionAndFlowControlMode channel_mode = RetransmissionAndFlowControlMode::L2CAP_BASIC;
+
+ /**
+ * Maximum SDU size that the L2CAP Channel user is able to process.
+ */
+ Mtu incoming_mtu = kDefaultClassicMtu;
+};
+
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/dynamic_channel_manager.cc b/gd/l2cap/classic/dynamic_channel_manager.cc
new file mode 100644
index 0000000..123fdd4
--- /dev/null
+++ b/gd/l2cap/classic/dynamic_channel_manager.cc
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 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 "l2cap/classic/dynamic_channel_manager.h"
+#include "l2cap/classic/internal/dynamic_channel_service_impl.h"
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
+#include "l2cap/classic/internal/link.h"
+#include "l2cap/classic/internal/link_manager.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+bool DynamicChannelManager::ConnectChannel(hci::Address device, DynamicChannelConfigurationOption configuration_option,
+ Psm psm, OnConnectionOpenCallback on_connection_open,
+ OnConnectionFailureCallback on_fail_callback, os::Handler* handler) {
+ internal::Link::PendingDynamicChannelConnection pending_dynamic_channel_connection{
+ .handler_ = handler,
+ .on_open_callback_ = std::move(on_connection_open),
+ .on_fail_callback_ = std::move(on_fail_callback),
+ .configuration_ = configuration_option,
+ };
+ l2cap_layer_handler_->Post(common::BindOnce(&internal::LinkManager::ConnectDynamicChannelServices,
+ common::Unretained(link_manager_), device,
+ std::move(pending_dynamic_channel_connection), psm));
+
+ return true;
+}
+
+bool DynamicChannelManager::RegisterService(Psm psm, DynamicChannelConfigurationOption configuration_option,
+ const SecurityPolicy& security_policy,
+ OnRegistrationCompleteCallback on_registration_complete,
+ OnConnectionOpenCallback on_connection_open, os::Handler* handler) {
+ internal::DynamicChannelServiceImpl::PendingRegistration pending_registration{
+ .user_handler_ = handler,
+ .on_registration_complete_callback_ = std::move(on_registration_complete),
+ .on_connection_open_callback_ = std::move(on_connection_open),
+ .configuration_ = configuration_option,
+ };
+ l2cap_layer_handler_->Post(common::BindOnce(&internal::DynamicChannelServiceManagerImpl::Register,
+ common::Unretained(service_manager_), psm,
+ std::move(pending_registration)));
+
+ return true;
+}
+
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/dynamic_channel_manager.h b/gd/l2cap/classic/dynamic_channel_manager.h
new file mode 100644
index 0000000..340d68d
--- /dev/null
+++ b/gd/l2cap/classic/dynamic_channel_manager.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <string>
+
+#include "hci/acl_manager.h"
+#include "hci/address.h"
+#include "l2cap/classic/dynamic_channel.h"
+#include "l2cap/classic/dynamic_channel_configuration_option.h"
+#include "l2cap/classic/dynamic_channel_service.h"
+#include "l2cap/l2cap_packets.h"
+#include "l2cap/psm.h"
+#include "l2cap/security_policy.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+class L2capClassicModule;
+
+namespace internal {
+class LinkManager;
+class DynamicChannelServiceManagerImpl;
+} // namespace internal
+
+class DynamicChannelManager {
+ public:
+ enum class ConnectionResultCode {
+ SUCCESS = 0,
+ FAIL_NO_SERVICE_REGISTERED = 1, // No service is registered
+ FAIL_HCI_ERROR = 2, // See hci_error
+ FAIL_L2CAP_ERROR = 3, // See l2cap_connection_response_result
+ };
+
+ struct ConnectionResult {
+ ConnectionResultCode connection_result_code = ConnectionResultCode::SUCCESS;
+ hci::ErrorCode hci_error = hci::ErrorCode::SUCCESS;
+ ConnectionResponseResult l2cap_connection_response_result = ConnectionResponseResult::SUCCESS;
+ };
+ /**
+ * OnConnectionFailureCallback(std::string failure_reason);
+ */
+ using OnConnectionFailureCallback = common::OnceCallback<void(ConnectionResult result)>;
+
+ /**
+ * OnConnectionOpenCallback(DynamicChannel channel);
+ */
+ using OnConnectionOpenCallback = common::Callback<void(std::unique_ptr<DynamicChannel>)>;
+
+ enum class RegistrationResult {
+ SUCCESS = 0,
+ FAIL_DUPLICATE_SERVICE = 1, // Duplicate service registration for the same PSM
+ FAIL_INVALID_SERVICE = 2, // Invalid PSM
+ };
+
+ /**
+ * OnRegistrationFailureCallback(RegistrationResult result, DynamicChannelService service);
+ */
+ using OnRegistrationCompleteCallback =
+ common::OnceCallback<void(RegistrationResult, std::unique_ptr<DynamicChannelService>)>;
+
+ /**
+ * Connect to a Dynamic channel on a remote device
+ *
+ * - This method is asynchronous
+ * - When false is returned, the connection fails immediately
+ * - When true is returned, method caller should wait for on_fail_callback or on_open_callback
+ * - If an ACL connection does not exist, this method will create an ACL connection
+ * - If HCI connection failed, on_fail_callback will be triggered with FAIL_HCI_ERROR
+ * - If Dynamic channel on a remote device is already reported as connected via on_open_callback, it won't be
+ * reported again
+ *
+ * @param device: Remote device to make this connection.
+ * @param psm: Service PSM to connect. PSM is defined in Core spec Vol 3 Part A 4.2.
+ * @param on_open_callback: A callback to indicate success of a connection initiated from a remote device.
+ * @param on_fail_callback: A callback to indicate connection failure along with a status code.
+ * @param handler: The handler context in which to execute the @callback parameters.
+ * @param configuration_option: The configuration options for this channel
+ *
+ * Returns: true if connection was able to be initiated, false otherwise.
+ */
+ bool ConnectChannel(hci::Address device, DynamicChannelConfigurationOption configuration_option, Psm psm,
+ OnConnectionOpenCallback on_connection_open, OnConnectionFailureCallback on_fail_callback,
+ os::Handler* handler);
+
+ /**
+ * Register a service to receive incoming connections bound to a specific channel.
+ *
+ * - This method is asynchronous.
+ * - When false is returned, the registration fails immediately.
+ * - When true is returned, method caller should wait for on_service_registered callback that contains a
+ * DynamicChannelService object. The registered service can be managed from that object.
+ * - If a PSM is already registered or some other error happens, on_registration_complete will be triggered with a
+ * non-SUCCESS value
+ * - After a service is registered, a DynamicChannel is delivered through on_open_callback when the remote
+ * initiates a channel open and channel is opened successfully
+ * - on_open_callback, will only be triggered after on_service_registered callback
+ *
+ * @param security_policy: The security policy used for the connection.
+ * @param psm: Service PSM to register. PSM is defined in Core spec Vol 3 Part A 4.2.
+ * @param on_registration_complete: A callback to indicate the service setup has completed. If the return status is
+ * not SUCCESS, it means service is not registered due to reasons like PSM already take
+ * @param on_open_callback: A callback to indicate success of a connection initiated from a remote device.
+ * @param handler: The handler context in which to execute the @callback parameter.
+ * @param configuration_option: The configuration options for this channel
+ */
+ bool RegisterService(Psm psm, DynamicChannelConfigurationOption configuration_option,
+ const SecurityPolicy& security_policy, OnRegistrationCompleteCallback on_registration_complete,
+ OnConnectionOpenCallback on_connection_open, os::Handler* handler);
+
+ friend class L2capClassicModule;
+
+ private:
+ // The constructor is not to be used by user code
+ DynamicChannelManager(internal::DynamicChannelServiceManagerImpl* service_manager,
+ internal::LinkManager* link_manager, os::Handler* l2cap_layer_handler)
+ : service_manager_(service_manager), link_manager_(link_manager), l2cap_layer_handler_(l2cap_layer_handler) {
+ ASSERT(service_manager_ != nullptr);
+ ASSERT(link_manager_ != nullptr);
+ ASSERT(l2cap_layer_handler_ != nullptr);
+ }
+ internal::DynamicChannelServiceManagerImpl* service_manager_ = nullptr;
+ internal::LinkManager* link_manager_ = nullptr;
+ os::Handler* l2cap_layer_handler_ = nullptr;
+ DISALLOW_COPY_AND_ASSIGN(DynamicChannelManager);
+};
+
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/dynamic_channel_service.cc b/gd/l2cap/classic/dynamic_channel_service.cc
new file mode 100644
index 0000000..ee97d37
--- /dev/null
+++ b/gd/l2cap/classic/dynamic_channel_service.cc
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2019 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 "l2cap/classic/dynamic_channel_service.h"
+#include "common/bind.h"
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+void DynamicChannelService::Unregister(OnUnregisteredCallback on_unregistered, os::Handler* on_unregistered_handler) {
+ ASSERT_LOG(manager_ != nullptr, "this service is invalid");
+ l2cap_layer_handler_->Post(common::BindOnce(&internal::DynamicChannelServiceManagerImpl::Unregister,
+ common::Unretained(manager_), psm_, std::move(on_unregistered),
+ on_unregistered_handler));
+}
+
+Psm DynamicChannelService::GetPsm() const {
+ return psm_;
+}
+
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/dynamic_channel_service.h b/gd/l2cap/classic/dynamic_channel_service.h
new file mode 100644
index 0000000..cd24b61
--- /dev/null
+++ b/gd/l2cap/classic/dynamic_channel_service.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "common/callback.h"
+#include "l2cap/psm.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+namespace internal {
+class DynamicChannelServiceManagerImpl;
+}
+
+class DynamicChannelService {
+ public:
+ DynamicChannelService() = default;
+
+ using OnUnregisteredCallback = common::OnceCallback<void()>;
+
+ /**
+ * Unregister a service from L2CAP module. This operation cannot fail.
+ * All channels opened for this service will be closed.
+ *
+ * @param on_unregistered will be triggered when unregistration is complete
+ */
+ void Unregister(OnUnregisteredCallback on_unregistered, os::Handler* on_unregistered_handler);
+
+ friend internal::DynamicChannelServiceManagerImpl;
+
+ Psm GetPsm() const;
+
+ private:
+ DynamicChannelService(Psm psm, internal::DynamicChannelServiceManagerImpl* manager, os::Handler* handler)
+ : psm_(psm), manager_(manager), l2cap_layer_handler_(handler) {
+ ASSERT(IsPsmValid(psm));
+ ASSERT(manager_ != nullptr);
+ ASSERT(l2cap_layer_handler_ != nullptr);
+ }
+ Psm psm_ = kDefaultPsm;
+ internal::DynamicChannelServiceManagerImpl* manager_ = nullptr;
+ os::Handler* l2cap_layer_handler_;
+ DISALLOW_COPY_AND_ASSIGN(DynamicChannelService);
+};
+
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/facade.cc b/gd/l2cap/classic/facade.cc
new file mode 100644
index 0000000..64f3810
--- /dev/null
+++ b/gd/l2cap/classic/facade.cc
@@ -0,0 +1,369 @@
+/*
+ * Copyright 2019 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 <cstdint>
+#include <unordered_map>
+
+#include "common/bidi_queue.h"
+#include "common/bind.h"
+#include "grpc/grpc_event_stream.h"
+#include "hci/address.h"
+#include "hci/facade.h"
+#include "l2cap/classic/facade.grpc.pb.h"
+#include "l2cap/classic/facade.h"
+#include "l2cap/classic/l2cap_classic_module.h"
+#include "l2cap/l2cap_packets.h"
+#include "os/log.h"
+#include "packet/raw_builder.h"
+
+using ::grpc::ServerAsyncResponseWriter;
+using ::grpc::ServerAsyncWriter;
+using ::grpc::ServerContext;
+
+using ::bluetooth::facade::EventStreamRequest;
+using ::bluetooth::packet::RawBuilder;
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+class L2capClassicModuleFacadeService : public L2capClassicModuleFacade::Service {
+ public:
+ L2capClassicModuleFacadeService(L2capClassicModule* l2cap_layer, os::Handler* facade_handler)
+ : l2cap_layer_(l2cap_layer), facade_handler_(facade_handler) {
+ ASSERT(l2cap_layer_ != nullptr);
+ ASSERT(facade_handler_ != nullptr);
+ }
+
+ class ConnectionCompleteCallback
+ : public grpc::GrpcEventStreamCallback<ConnectionCompleteEvent, ConnectionCompleteEvent> {
+ public:
+ void OnWriteResponse(ConnectionCompleteEvent* response, const ConnectionCompleteEvent& event) override {
+ response->CopyFrom(event);
+ }
+
+ } connection_complete_callback_;
+ ::bluetooth::grpc::GrpcEventStream<ConnectionCompleteEvent, ConnectionCompleteEvent> connection_complete_stream_{
+ &connection_complete_callback_};
+
+ ::grpc::Status FetchConnectionComplete(::grpc::ServerContext* context,
+ const ::bluetooth::facade::EventStreamRequest* request,
+ ::grpc::ServerWriter<classic::ConnectionCompleteEvent>* writer) override {
+ return connection_complete_stream_.HandleRequest(context, request, writer);
+ }
+
+ ::grpc::Status Connect(::grpc::ServerContext* context, const facade::BluetoothAddress* request,
+ ::google::protobuf::Empty* response) override {
+ auto fixed_channel_manager = l2cap_layer_->GetFixedChannelManager();
+ hci::Address peer;
+ ASSERT(hci::Address::FromString(request->address(), peer));
+ fixed_channel_manager->ConnectServices(peer, common::BindOnce([](FixedChannelManager::ConnectionResult) {}),
+ facade_handler_);
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendL2capPacket(::grpc::ServerContext* context, const classic::L2capPacket* request,
+ SendL2capPacketResult* response) override {
+ if (fixed_channel_helper_map_.find(request->channel()) == fixed_channel_helper_map_.end()) {
+ return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Channel not registered");
+ }
+ std::vector<uint8_t> packet(request->payload().begin(), request->payload().end());
+ fixed_channel_helper_map_[request->channel()]->SendPacket(packet);
+ response->set_result_type(SendL2capPacketResultType::OK);
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status SendDynamicChannelPacket(::grpc::ServerContext* context, const DynamicChannelPacket* request,
+ ::google::protobuf::Empty* response) override {
+ if (dynamic_channel_helper_map_.find(request->psm()) == dynamic_channel_helper_map_.end()) {
+ return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Psm not registered");
+ }
+ std::vector<uint8_t> packet(request->payload().begin(), request->payload().end());
+ dynamic_channel_helper_map_[request->psm()]->SendPacket(packet);
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status OpenChannel(::grpc::ServerContext* context,
+ const ::bluetooth::l2cap::classic::OpenChannelRequest* request,
+ ::google::protobuf::Empty* response) override {
+ auto psm = request->psm();
+ auto mode = request->mode();
+ dynamic_channel_helper_map_.emplace(
+ psm, std::make_unique<L2capDynamicChannelHelper>(this, l2cap_layer_, facade_handler_, psm, mode));
+ hci::Address peer;
+ ASSERT(hci::Address::FromString(request->remote().address(), peer));
+ dynamic_channel_helper_map_[psm]->Connect(peer);
+ return ::grpc::Status::OK;
+ }
+
+ ::grpc::Status FetchL2capData(::grpc::ServerContext* context, const ::bluetooth::facade::EventStreamRequest* request,
+ ::grpc::ServerWriter<classic::L2capPacket>* writer) override {
+ return l2cap_stream_.HandleRequest(context, request, writer);
+ }
+
+ ::grpc::Status RegisterChannel(::grpc::ServerContext* context, const classic::RegisterChannelRequest* request,
+ ::google::protobuf::Empty* response) override {
+ if (fixed_channel_helper_map_.find(request->channel()) != fixed_channel_helper_map_.end()) {
+ return ::grpc::Status(::grpc::StatusCode::FAILED_PRECONDITION, "Already registered");
+ }
+ fixed_channel_helper_map_.emplace(request->channel(), std::make_unique<L2capFixedChannelHelper>(
+ this, l2cap_layer_, facade_handler_, request->channel()));
+
+ return ::grpc::Status::OK;
+ }
+
+ class L2capFixedChannelHelper {
+ public:
+ L2capFixedChannelHelper(L2capClassicModuleFacadeService* service, L2capClassicModule* l2cap_layer,
+ os::Handler* handler, Cid cid)
+ : facade_service_(service), l2cap_layer_(l2cap_layer), handler_(handler), cid_(cid) {
+ fixed_channel_manager_ = l2cap_layer_->GetFixedChannelManager();
+ fixed_channel_manager_->RegisterService(
+ cid, {},
+ common::BindOnce(&L2capFixedChannelHelper::on_l2cap_service_registration_complete, common::Unretained(this)),
+ common::Bind(&L2capFixedChannelHelper::on_connection_open, common::Unretained(this)), handler_);
+ }
+
+ void on_l2cap_service_registration_complete(FixedChannelManager::RegistrationResult registration_result,
+ std::unique_ptr<FixedChannelService> service) {
+ service_ = std::move(service);
+ }
+
+ void on_connection_open(std::unique_ptr<FixedChannel> channel) {
+ ConnectionCompleteEvent event;
+ event.mutable_remote()->set_address(channel->GetDevice().ToString());
+ facade_service_->connection_complete_stream_.OnIncomingEvent(event);
+ channel_ = std::move(channel);
+ }
+
+ void SendPacket(std::vector<uint8_t> packet) {
+ if (channel_ == nullptr) {
+ LOG_WARN("Channel is not open");
+ return;
+ }
+ channel_->GetQueueUpEnd()->RegisterEnqueue(
+ handler_, common::Bind(&L2capFixedChannelHelper::enqueue_callback, common::Unretained(this), packet));
+ }
+
+ void on_incoming_packet() {
+ auto packet = channel_->GetQueueUpEnd()->TryDequeue();
+ std::string data = std::string(packet->begin(), packet->end());
+ L2capPacket l2cap_data;
+ l2cap_data.set_channel(cid_);
+ l2cap_data.set_payload(data);
+ facade_service_->l2cap_stream_.OnIncomingEvent(l2cap_data);
+ }
+
+ std::unique_ptr<packet::BasePacketBuilder> enqueue_callback(std::vector<uint8_t> packet) {
+ auto packet_one = std::make_unique<packet::RawBuilder>();
+ packet_one->AddOctets(packet);
+ channel_->GetQueueUpEnd()->UnregisterEnqueue();
+ return packet_one;
+ };
+
+ L2capClassicModuleFacadeService* facade_service_;
+ L2capClassicModule* l2cap_layer_;
+ os::Handler* handler_;
+ std::unique_ptr<FixedChannelManager> fixed_channel_manager_;
+ std::unique_ptr<FixedChannelService> service_;
+ std::unique_ptr<FixedChannel> channel_ = nullptr;
+ Cid cid_;
+ };
+
+ ::grpc::Status SetDynamicChannel(::grpc::ServerContext* context, const SetEnableDynamicChannelRequest* request,
+ google::protobuf::Empty* response) override {
+ dynamic_channel_helper_map_.emplace(
+ request->psm(), std::make_unique<L2capDynamicChannelHelper>(this, l2cap_layer_, facade_handler_, request->psm(),
+ request->retransmission_mode()));
+ return ::grpc::Status::OK;
+ }
+
+ class L2capDynamicChannelHelper {
+ public:
+ L2capDynamicChannelHelper(L2capClassicModuleFacadeService* service, L2capClassicModule* l2cap_layer,
+ os::Handler* handler, Psm psm, RetransmissionFlowControlMode mode)
+ : facade_service_(service), l2cap_layer_(l2cap_layer), handler_(handler), psm_(psm) {
+ dynamic_channel_manager_ = l2cap_layer_->GetDynamicChannelManager();
+ DynamicChannelConfigurationOption configuration_option;
+ if (mode == RetransmissionFlowControlMode::BASIC) {
+ configuration_option.channel_mode =
+ DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC;
+ } else if (mode == RetransmissionFlowControlMode::ERTM) {
+ configuration_option.channel_mode =
+ DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::ENHANCED_RETRANSMISSION;
+ }
+ dynamic_channel_manager_->RegisterService(
+ psm, configuration_option, {},
+ common::BindOnce(&L2capDynamicChannelHelper::on_l2cap_service_registration_complete,
+ common::Unretained(this)),
+ common::Bind(&L2capDynamicChannelHelper::on_connection_open, common::Unretained(this)), handler_);
+ }
+
+ void Connect(hci::Address address) {
+ // TODO: specify channel mode
+ dynamic_channel_manager_->ConnectChannel(
+ address, {}, psm_, common::Bind(&L2capDynamicChannelHelper::on_connection_open, common::Unretained(this)),
+ common::Bind(&L2capDynamicChannelHelper::on_connect_fail, common::Unretained(this)), handler_);
+ }
+
+ void on_l2cap_service_registration_complete(DynamicChannelManager::RegistrationResult registration_result,
+ std::unique_ptr<DynamicChannelService> service) {}
+
+ void on_connection_open(std::unique_ptr<DynamicChannel> channel) {
+ ConnectionCompleteEvent event;
+ event.mutable_remote()->set_address(channel->GetDevice().ToString());
+ facade_service_->connection_complete_stream_.OnIncomingEvent(event);
+ channel_ = std::move(channel);
+ }
+
+ void on_connect_fail(DynamicChannelManager::ConnectionResult result) {}
+
+ void on_incoming_packet() {
+ auto packet = channel_->GetQueueUpEnd()->TryDequeue();
+ std::string data = std::string(packet->begin(), packet->end());
+ L2capPacket l2cap_data;
+ // l2cap_data.set_channel(cid_);
+ l2cap_data.set_payload(data);
+ facade_service_->l2cap_stream_.OnIncomingEvent(l2cap_data);
+ }
+
+ void SendPacket(std::vector<uint8_t> packet) {
+ if (channel_ == nullptr) {
+ LOG_WARN("Channel is not open");
+ return;
+ }
+ channel_->GetQueueUpEnd()->RegisterEnqueue(
+ handler_, common::Bind(&L2capDynamicChannelHelper::enqueue_callback, common::Unretained(this), packet));
+ }
+
+ std::unique_ptr<packet::BasePacketBuilder> enqueue_callback(std::vector<uint8_t> packet) {
+ auto packet_one = std::make_unique<packet::RawBuilder>(2000);
+ packet_one->AddOctets(packet);
+ channel_->GetQueueUpEnd()->UnregisterEnqueue();
+ return packet_one;
+ };
+
+ L2capClassicModuleFacadeService* facade_service_;
+ L2capClassicModule* l2cap_layer_;
+ os::Handler* handler_;
+ std::unique_ptr<DynamicChannelManager> dynamic_channel_manager_;
+ std::unique_ptr<DynamicChannelService> service_;
+ std::unique_ptr<DynamicChannel> channel_ = nullptr;
+ Psm psm_;
+ };
+
+ L2capClassicModule* l2cap_layer_;
+ ::bluetooth::os::Handler* facade_handler_;
+ std::map<Cid, std::unique_ptr<L2capFixedChannelHelper>> fixed_channel_helper_map_;
+ std::map<Psm, std::unique_ptr<L2capDynamicChannelHelper>> dynamic_channel_helper_map_;
+
+ class L2capStreamCallback : public ::bluetooth::grpc::GrpcEventStreamCallback<L2capPacket, L2capPacket> {
+ public:
+ L2capStreamCallback(L2capClassicModuleFacadeService* service) : service_(service) {}
+
+ ~L2capStreamCallback() {
+ for (const auto& connection : service_->fixed_channel_helper_map_) {
+ if (subscribed_fixed_channel_[connection.first] && connection.second->channel_ != nullptr) {
+ connection.second->channel_->GetQueueUpEnd()->UnregisterDequeue();
+ subscribed_fixed_channel_[connection.first] = false;
+ }
+ }
+
+ for (const auto& connection : service_->dynamic_channel_helper_map_) {
+ if (subscribed_dynamic_channel_[connection.first] && connection.second->channel_ != nullptr) {
+ connection.second->channel_->GetQueueUpEnd()->UnregisterDequeue();
+ subscribed_dynamic_channel_[connection.first] = false;
+ }
+ }
+ }
+
+ void OnSubscribe() override {
+ for (auto& connection : service_->fixed_channel_helper_map_) {
+ if (!subscribed_fixed_channel_[connection.first] && connection.second->channel_ != nullptr) {
+ connection.second->channel_->GetQueueUpEnd()->RegisterDequeue(
+ service_->facade_handler_,
+ common::Bind(&L2capFixedChannelHelper::on_incoming_packet, common::Unretained(connection.second.get())));
+ subscribed_fixed_channel_[connection.first] = true;
+ }
+ }
+
+ for (auto& connection : service_->dynamic_channel_helper_map_) {
+ if (!subscribed_dynamic_channel_[connection.first] && connection.second->channel_ != nullptr) {
+ connection.second->channel_->GetQueueUpEnd()->RegisterDequeue(
+ service_->facade_handler_, common::Bind(&L2capDynamicChannelHelper::on_incoming_packet,
+ common::Unretained(connection.second.get())));
+ subscribed_dynamic_channel_[connection.first] = true;
+ }
+ }
+ }
+
+ void OnUnsubscribe() override {
+ for (const auto& connection : service_->fixed_channel_helper_map_) {
+ if (subscribed_fixed_channel_[connection.first] && connection.second->channel_ != nullptr) {
+ connection.second->channel_->GetQueueUpEnd()->UnregisterDequeue();
+ subscribed_fixed_channel_[connection.first] = false;
+ }
+ }
+
+ for (const auto& connection : service_->dynamic_channel_helper_map_) {
+ if (subscribed_dynamic_channel_[connection.first] && connection.second->channel_ != nullptr) {
+ connection.second->channel_->GetQueueUpEnd()->UnregisterDequeue();
+ subscribed_dynamic_channel_[connection.first] = false;
+ }
+ }
+ }
+
+ void OnWriteResponse(L2capPacket* response, const L2capPacket& event) override {
+ response->CopyFrom(event);
+ }
+
+ L2capClassicModuleFacadeService* service_;
+ std::map<Cid, bool> subscribed_fixed_channel_;
+ std::map<Psm, bool> subscribed_dynamic_channel_;
+
+ } l2cap_stream_callback_{this};
+ ::bluetooth::grpc::GrpcEventStream<L2capPacket, L2capPacket> l2cap_stream_{&l2cap_stream_callback_};
+
+ std::mutex mutex_;
+};
+
+void L2capClassicModuleFacadeModule::ListDependencies(ModuleList* list) {
+ ::bluetooth::grpc::GrpcFacadeModule::ListDependencies(list);
+ list->add<l2cap::classic::L2capClassicModule>();
+ list->add<hci::HciLayer>();
+}
+
+void L2capClassicModuleFacadeModule::Start() {
+ ::bluetooth::grpc::GrpcFacadeModule::Start();
+ GetDependency<hci::HciLayer>()->EnqueueCommand(hci::WriteScanEnableBuilder::Create(hci::ScanEnable::PAGE_SCAN_ONLY),
+ common::BindOnce([](hci::CommandCompleteView) {}), GetHandler());
+ service_ = new L2capClassicModuleFacadeService(GetDependency<l2cap::classic::L2capClassicModule>(), GetHandler());
+}
+
+void L2capClassicModuleFacadeModule::Stop() {
+ delete service_;
+ ::bluetooth::grpc::GrpcFacadeModule::Stop();
+}
+
+::grpc::Service* L2capClassicModuleFacadeModule::GetService() const {
+ return service_;
+}
+
+const ModuleFactory L2capClassicModuleFacadeModule::Factory =
+ ::bluetooth::ModuleFactory([]() { return new L2capClassicModuleFacadeModule(); });
+
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/facade.h b/gd/l2cap/classic/facade.h
new file mode 100644
index 0000000..ebaee0d
--- /dev/null
+++ b/gd/l2cap/classic/facade.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <grpc++/grpc++.h>
+
+#include "grpc/grpc_module.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+class L2capClassicModuleFacadeService;
+
+class L2capClassicModuleFacadeModule : public ::bluetooth::grpc::GrpcFacadeModule {
+ public:
+ static const ModuleFactory Factory;
+
+ void ListDependencies(ModuleList* list) override;
+ void Start() override;
+ void Stop() override;
+
+ ::grpc::Service* GetService() const override;
+
+ private:
+ L2capClassicModuleFacadeService* service_;
+};
+
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/facade.proto b/gd/l2cap/classic/facade.proto
new file mode 100644
index 0000000..ab2a911
--- /dev/null
+++ b/gd/l2cap/classic/facade.proto
@@ -0,0 +1,94 @@
+syntax = "proto3";
+
+package bluetooth.l2cap.classic;
+
+import "google/protobuf/empty.proto";
+import "facade/common.proto";
+
+service L2capClassicModuleFacade {
+ rpc RegisterChannel(RegisterChannelRequest) returns (google.protobuf.Empty) {
+ // Testing Android Bluetooth stack only. Optional for other stack.
+ }
+ rpc FetchConnectionComplete(facade.EventStreamRequest) returns (stream ConnectionCompleteEvent) {
+ // Testing Android Bluetooth stack only. Optional for other stack.
+ }
+ rpc Connect(facade.BluetoothAddress) returns (google.protobuf.Empty) {}
+ rpc OpenChannel(OpenChannelRequest) returns (google.protobuf.Empty) {}
+ rpc ConfigureChannel(ConfigureChannelRequest) returns (google.protobuf.Empty) {}
+ rpc SendL2capPacket(L2capPacket) returns (SendL2capPacketResult) {}
+ rpc FetchL2capData(facade.EventStreamRequest) returns (stream L2capPacket) {}
+ rpc RegisterDynamicChannel(RegisterDynamicChannelRequest) returns (google.protobuf.Empty) {}
+ rpc SetDynamicChannel(SetEnableDynamicChannelRequest) returns (google.protobuf.Empty) {}
+ rpc SendDynamicChannelPacket(DynamicChannelPacket) returns (google.protobuf.Empty) {}
+}
+
+message RegisterChannelRequest {
+ uint32 channel = 1;
+}
+
+message ConnectionCompleteEvent {
+ facade.BluetoothAddress remote = 1;
+}
+
+enum RetransmissionFlowControlMode {
+ BASIC = 0;
+ ERTM = 3;
+}
+
+message OpenChannelRequest {
+ facade.BluetoothAddress remote = 1;
+ uint32 psm = 2;
+ RetransmissionFlowControlMode mode = 3;
+}
+
+message ConfigureChannelRequest {
+ facade.BluetoothAddress remote = 1;
+ // Config
+}
+
+message CloseChannelRequest {
+ facade.BluetoothAddress remote = 1;
+ uint32 cid = 2;
+}
+
+enum ChannelSignalEventType {
+ OPEN = 0;
+ CLOSE = 1;
+ CONFIGURE = 2;
+}
+
+message ChannelSignalEvent {
+ uint32 cid = 1;
+ ChannelSignalEventType type = 2;
+}
+
+enum SendL2capPacketResultType {
+ OK = 0;
+ BAD_CID = 1;
+}
+
+message SendL2capPacketResult {
+ SendL2capPacketResultType result_type = 1;
+}
+
+message L2capPacket {
+ facade.BluetoothAddress remote = 1;
+ uint32 channel = 2;
+ bytes payload = 3;
+}
+
+message RegisterDynamicChannelRequest {
+ uint32 psm = 1;
+}
+
+message SetEnableDynamicChannelRequest {
+ uint32 psm = 1;
+ bool enable = 2;
+ RetransmissionFlowControlMode retransmission_mode = 3;
+}
+
+message DynamicChannelPacket {
+ facade.BluetoothAddress remote = 1;
+ uint32 psm = 2;
+ bytes payload = 3;
+}
diff --git a/gd/l2cap/classic/fixed_channel.cc b/gd/l2cap/classic/fixed_channel.cc
new file mode 100644
index 0000000..a90d119
--- /dev/null
+++ b/gd/l2cap/classic/fixed_channel.cc
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019 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 "l2cap/classic/fixed_channel.h"
+#include "common/bind.h"
+#include "l2cap/classic/internal/fixed_channel_impl.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+hci::Address FixedChannel::GetDevice() const {
+ return impl_->GetDevice();
+}
+
+void FixedChannel::RegisterOnCloseCallback(os::Handler* user_handler, FixedChannel::OnCloseCallback on_close_callback) {
+ l2cap_handler_->Post(common::BindOnce(&internal::FixedChannelImpl::RegisterOnCloseCallback, impl_, user_handler,
+ std::move(on_close_callback)));
+}
+
+void FixedChannel::Acquire() {
+ l2cap_handler_->Post(common::BindOnce(&internal::FixedChannelImpl::Acquire, impl_));
+}
+
+void FixedChannel::Release() {
+ l2cap_handler_->Post(common::BindOnce(&internal::FixedChannelImpl::Release, impl_));
+}
+
+common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>*
+FixedChannel::GetQueueUpEnd() const {
+ return impl_->GetQueueUpEnd();
+}
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/fixed_channel.h b/gd/l2cap/classic/fixed_channel.h
new file mode 100644
index 0000000..bf88e3d
--- /dev/null
+++ b/gd/l2cap/classic/fixed_channel.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include "common/bidi_queue.h"
+#include "common/callback.h"
+#include "hci/acl_manager.h"
+#include "l2cap/cid.h"
+#include "os/handler.h"
+#include "packet/base_packet_builder.h"
+#include "packet/packet_view.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+namespace internal {
+class FixedChannelImpl;
+} // namespace internal
+
+/**
+ * L2CAP fixed channel object. When a new object is created, it must be
+ * acquired through calling {@link FixedChannel#Acquire()} within X seconds.
+ * Otherwise, {@link FixedChannel#Release()} will be called automatically.
+ *
+ */
+class FixedChannel {
+ public:
+ // Should only be constructed by modules that have access to LinkManager
+ FixedChannel(std::shared_ptr<internal::FixedChannelImpl> impl, os::Handler* l2cap_handler)
+ : impl_(std::move(impl)), l2cap_handler_(l2cap_handler) {
+ ASSERT(impl_ != nullptr);
+ ASSERT(l2cap_handler_ != nullptr);
+ }
+
+ hci::Address GetDevice() const;
+
+ /**
+ * Register close callback. If close callback is registered, when a channel is closed, the channel's resource will
+ * only be freed after on_close callback is invoked. Otherwise, if no on_close callback is registered, the channel's
+ * resource will be freed immediately after closing.
+ *
+ * @param user_handler The handler used to invoke the callback on
+ * @param on_close_callback The callback invoked upon channel closing.
+ */
+ using OnCloseCallback = common::OnceCallback<void(hci::ErrorCode)>;
+ void RegisterOnCloseCallback(os::Handler* user_handler, OnCloseCallback on_close_callback);
+
+ /**
+ * Indicate that this Fixed Channel is being used. This will prevent ACL connection from being disconnected.
+ */
+ void Acquire();
+
+ /**
+ * Indicate that this Fixed Channel is no longer being used. ACL connection will be disconnected after
+ * kLinkIdleDisconnectTimeout if no other DynamicChannel is connected or no other Fixed Channel is using this
+ * ACL connection. However a module can still receive data on this channel as long as it remains open.
+ */
+ void Release();
+
+ /**
+ * This method will retrieve the data channel queue to send and receive packets.
+ *
+ * {@see BidiQueueEnd}
+ *
+ * @return The upper end of a bi-directional queue.
+ */
+ common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>* GetQueueUpEnd() const;
+
+ private:
+ std::shared_ptr<internal::FixedChannelImpl> impl_;
+ os::Handler* l2cap_handler_;
+};
+
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/fixed_channel_manager.cc b/gd/l2cap/classic/fixed_channel_manager.cc
new file mode 100644
index 0000000..0c3e5c7
--- /dev/null
+++ b/gd/l2cap/classic/fixed_channel_manager.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 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 "l2cap/classic/fixed_channel_manager.h"
+#include "l2cap/classic/internal/fixed_channel_service_impl.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
+#include "l2cap/classic/internal/link_manager.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+bool FixedChannelManager::ConnectServices(hci::Address device, OnConnectionFailureCallback on_fail_callback,
+ os::Handler* handler) {
+ internal::LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+ .handler_ = handler,
+ .on_fail_callback_ = std::move(on_fail_callback),
+ };
+ l2cap_layer_handler_->Post(common::BindOnce(&internal::LinkManager::ConnectFixedChannelServices,
+ common::Unretained(link_manager_), device,
+ std::move(pending_fixed_channel_connection)));
+ return true;
+}
+
+bool FixedChannelManager::RegisterService(Cid cid, const SecurityPolicy& security_policy,
+ OnRegistrationCompleteCallback on_registration_complete,
+ OnConnectionOpenCallback on_connection_open, os::Handler* handler) {
+ internal::FixedChannelServiceImpl::PendingRegistration pending_registration{
+ .user_handler_ = handler,
+ .on_registration_complete_callback_ = std::move(on_registration_complete),
+ .on_connection_open_callback_ = std::move(on_connection_open)};
+ l2cap_layer_handler_->Post(common::BindOnce(&internal::FixedChannelServiceManagerImpl::Register,
+ common::Unretained(service_manager_), cid,
+ std::move(pending_registration)));
+ return true;
+}
+
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/fixed_channel_manager.h b/gd/l2cap/classic/fixed_channel_manager.h
new file mode 100644
index 0000000..5e8f6ab
--- /dev/null
+++ b/gd/l2cap/classic/fixed_channel_manager.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <string>
+
+#include "hci/acl_manager.h"
+#include "hci/address.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic/fixed_channel.h"
+#include "l2cap/classic/fixed_channel_service.h"
+#include "l2cap/security_policy.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+class L2capClassicModule;
+
+namespace testing {
+class MockFixedChannelManager;
+}
+
+namespace internal {
+class LinkManager;
+class FixedChannelServiceManagerImpl;
+} // namespace internal
+
+class FixedChannelManager {
+ public:
+ enum class ConnectionResultCode {
+ SUCCESS = 0,
+ FAIL_NO_SERVICE_REGISTERED = 1, // No service is registered
+ FAIL_ALL_SERVICES_HAVE_CHANNEL = 2, // All registered services already have a channel
+ FAIL_HCI_ERROR = 3, // See hci_error
+ };
+
+ struct ConnectionResult {
+ ConnectionResultCode connection_result_code = ConnectionResultCode::SUCCESS;
+ hci::ErrorCode hci_error = hci::ErrorCode::SUCCESS;
+ };
+ /**
+ * OnConnectionFailureCallback(std::string failure_reason);
+ */
+ using OnConnectionFailureCallback = common::OnceCallback<void(ConnectionResult result)>;
+
+ /**
+ * OnConnectionOpenCallback(FixedChannel channel);
+ */
+ using OnConnectionOpenCallback = common::Callback<void(std::unique_ptr<FixedChannel>)>;
+
+ enum class RegistrationResult {
+ SUCCESS = 0,
+ FAIL_DUPLICATE_SERVICE = 1, // Duplicate service registration for the same CID
+ FAIL_INVALID_SERVICE = 2, // Invalid CID
+ };
+
+ /**
+ * OnRegistrationFailureCallback(RegistrationResult result, FixedChannelService service);
+ */
+ using OnRegistrationCompleteCallback =
+ common::OnceCallback<void(RegistrationResult, std::unique_ptr<FixedChannelService>)>;
+
+ /**
+ * Connect to ALL fixed channels on a remote device
+ *
+ * - This method is asynchronous
+ * - When false is returned, the connection fails immediately
+ * - When true is returned, method caller should wait for on_fail_callback or on_open_callback registered through
+ * RegisterService() API.
+ * - If an ACL connection does not exist, this method will create an ACL connection. As a result, on_open_callback
+ * supplied through RegisterService() will be triggered to provide the actual FixedChannel objects
+ * - If HCI connection failed, on_fail_callback will be triggered with FAIL_HCI_ERROR
+ * - If fixed channel on a remote device is already reported as connected via on_open_callback and has been acquired
+ * via FixedChannel#Acquire() API, it won't be reported again
+ * - If no service is registered, on_fail_callback will be triggered with FAIL_NO_SERVICE_REGISTERED
+ * - If there is an ACL connection and channels for each service is allocated, on_fail_callback will be triggered with
+ * FAIL_ALL_SERVICES_HAVE_CHANNEL
+ *
+ * NOTE:
+ * This call will initiate an effort to connect all fixed channel services on a remote device.
+ * Due to the connectionless nature of fixed channels, all fixed channels will be connected together.
+ * If a fixed channel service does not need a particular fixed channel. It should release the received
+ * channel immediately after receiving on_open_callback via FixedChannel#Release()
+ *
+ * A module calling ConnectServices() must have called RegisterService() before.
+ * The callback will come back from on_open_callback in the service that is registered
+ *
+ * @param device: Remote device to make this connection.
+ * @param on_fail_callback: A callback to indicate connection failure along with a status code.
+ * @param handler: The handler context in which to execute the @callback parameters.
+ *
+ * Returns: true if connection was able to be initiated, false otherwise.
+ */
+ virtual bool ConnectServices(hci::Address device, OnConnectionFailureCallback on_fail_callback, os::Handler* handler);
+
+ /**
+ * Register a service to receive incoming connections bound to a specific channel.
+ *
+ * - This method is asynchronous.
+ * - When false is returned, the registration fails immediately.
+ * - When true is returned, method caller should wait for on_service_registered callback that contains a
+ * FixedChannelService object. The registered service can be managed from that object.
+ * - If a CID is already registered or some other error happens, on_registration_complete will be triggered with a
+ * non-SUCCESS value
+ * - After a service is registered, any classic ACL connection will create a FixedChannel object that is
+ * delivered through on_open_callback
+ * - on_open_callback, will only be triggered after on_service_registered callback
+ *
+ * @param cid: cid used to receive incoming connections
+ * @param security_policy: The security policy used for the connection.
+ * @param on_registration_complete: A callback to indicate the service setup has completed. If the return status is
+ * not SUCCESS, it means service is not registered due to reasons like CID already take
+ * @param on_open_callback: A callback to indicate success of a connection initiated from a remote device.
+ * @param handler: The handler context in which to execute the @callback parameter.
+ */
+ virtual bool RegisterService(Cid cid, const SecurityPolicy& security_policy,
+ OnRegistrationCompleteCallback on_registration_complete,
+ OnConnectionOpenCallback on_connection_open, os::Handler* handler);
+
+ virtual ~FixedChannelManager() = default;
+
+ friend class L2capClassicModule;
+ friend class testing::MockFixedChannelManager;
+
+ private:
+ // The constructor is not to be used by user code
+ FixedChannelManager(internal::FixedChannelServiceManagerImpl* service_manager, internal::LinkManager* link_manager,
+ os::Handler* l2cap_layer_handler)
+ : service_manager_(service_manager), link_manager_(link_manager), l2cap_layer_handler_(l2cap_layer_handler) {}
+ internal::FixedChannelServiceManagerImpl* service_manager_ = nullptr;
+ internal::LinkManager* link_manager_ = nullptr;
+ os::Handler* l2cap_layer_handler_ = nullptr;
+ DISALLOW_COPY_AND_ASSIGN(FixedChannelManager);
+};
+
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/fixed_channel_manager_mock.h b/gd/l2cap/classic/fixed_channel_manager_mock.h
new file mode 100644
index 0000000..5ead957
--- /dev/null
+++ b/gd/l2cap/classic/fixed_channel_manager_mock.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include "l2cap/classic/fixed_channel_manager.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace testing {
+
+class MockFixedChannelManager : public FixedChannelManager {
+ public:
+ MockFixedChannelManager() : FixedChannelManager(nullptr, nullptr, nullptr){};
+ MOCK_METHOD(bool, ConnectServices,
+ (hci::Address device, OnConnectionFailureCallback on_fail_callback, os::Handler* handler), (override));
+ MOCK_METHOD(bool, RegisterService,
+ (Cid cid, const SecurityPolicy& security_policy, OnRegistrationCompleteCallback on_registration_complete,
+ OnConnectionOpenCallback on_connection_open, os::Handler* handler),
+ (override));
+};
+
+} // namespace testing
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/fixed_channel_service.cc b/gd/l2cap/classic/fixed_channel_service.cc
new file mode 100644
index 0000000..49a977d
--- /dev/null
+++ b/gd/l2cap/classic/fixed_channel_service.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019 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 "l2cap/classic/fixed_channel_service.h"
+#include "common/bind.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+void FixedChannelService::Unregister(OnUnregisteredCallback on_unregistered, os::Handler* on_unregistered_handler) {
+ ASSERT_LOG(manager_ != nullptr, "this service is invalid");
+ l2cap_layer_handler_->Post(common::BindOnce(&internal::FixedChannelServiceManagerImpl::Unregister,
+ common::Unretained(manager_), cid_, std::move(on_unregistered),
+ on_unregistered_handler));
+}
+
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/fixed_channel_service.h b/gd/l2cap/classic/fixed_channel_service.h
new file mode 100644
index 0000000..d5d213b
--- /dev/null
+++ b/gd/l2cap/classic/fixed_channel_service.h
@@ -0,0 +1,59 @@
+
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include "common/callback.h"
+#include "hci/address.h"
+#include "l2cap/cid.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+namespace internal {
+class FixedChannelServiceManagerImpl;
+} // namespace internal
+
+class FixedChannelService {
+ public:
+ FixedChannelService() = default;
+
+ using OnUnregisteredCallback = common::OnceCallback<void()>;
+
+ /**
+ * Unregister a service from L2CAP module. This operation cannot fail.
+ * All channels opened for this service will be invalidated.
+ *
+ * @param on_unregistered will be triggered when unregistration is complete
+ */
+ void Unregister(OnUnregisteredCallback on_unregistered, os::Handler* on_unregistered_handler);
+
+ friend internal::FixedChannelServiceManagerImpl;
+
+ private:
+ FixedChannelService(Cid cid, internal::FixedChannelServiceManagerImpl* manager, os::Handler* handler)
+ : cid_(cid), manager_(manager), l2cap_layer_handler_(handler) {}
+ Cid cid_ = kInvalidCid;
+ internal::FixedChannelServiceManagerImpl* manager_ = nullptr;
+ os::Handler* l2cap_layer_handler_;
+ DISALLOW_COPY_AND_ASSIGN(FixedChannelService);
+};
+
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_allocator.cc b/gd/l2cap/classic/internal/dynamic_channel_allocator.cc
new file mode 100644
index 0000000..95830e0
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_allocator.cc
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2019 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 <unordered_map>
+
+#include "l2cap/cid.h"
+#include "l2cap/classic/internal/dynamic_channel_allocator.h"
+#include "l2cap/classic/internal/link.h"
+#include "l2cap/security_policy.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::AllocateChannel(Psm psm, Cid remote_cid,
+ SecurityPolicy security_policy) {
+ ASSERT_LOG(!IsPsmUsed((psm)), "Psm 0x%x for device %s is already in use", psm, link_->GetDevice().ToString().c_str());
+ ASSERT_LOG(IsPsmValid(psm), "Psm 0x%x is invalid", psm);
+
+ if (used_remote_cid_.find(remote_cid) != used_remote_cid_.end()) {
+ LOG_INFO("Remote cid 0x%x is used", remote_cid);
+ return nullptr;
+ }
+ Cid cid = kFirstDynamicChannel;
+ for (; cid <= kLastDynamicChannel; cid++) {
+ if (used_cid_.find(cid) == used_cid_.end()) break;
+ }
+ if (cid > kLastDynamicChannel) {
+ LOG_WARN("All cid are used");
+ return nullptr;
+ }
+ auto elem =
+ channels_.try_emplace(cid, std::make_shared<DynamicChannelImpl>(psm, cid, remote_cid, link_, l2cap_handler_));
+ ASSERT_LOG(elem.second, "Failed to create channel for psm 0x%x device %s", psm,
+ link_->GetDevice().ToString().c_str());
+ ASSERT(elem.first->second != nullptr);
+ used_remote_cid_.insert(remote_cid);
+ used_cid_.insert(cid);
+ return elem.first->second;
+}
+
+std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::AllocateReservedChannel(Cid reserved_cid, Psm psm,
+ Cid remote_cid,
+ SecurityPolicy security_policy) {
+ ASSERT_LOG(!IsPsmUsed((psm)), "Psm 0x%x for device %s is already in use", psm, link_->GetDevice().ToString().c_str());
+ ASSERT_LOG(IsPsmValid(psm), "Psm 0x%x is invalid", psm);
+
+ if (used_remote_cid_.find(remote_cid) != used_remote_cid_.end()) {
+ LOG_INFO("Remote cid 0x%x is used", remote_cid);
+ return nullptr;
+ }
+ auto elem = channels_.try_emplace(
+ reserved_cid, std::make_shared<DynamicChannelImpl>(psm, reserved_cid, remote_cid, link_, l2cap_handler_));
+ ASSERT_LOG(elem.second, "Failed to create channel for psm 0x%x device %s", psm,
+ link_->GetDevice().ToString().c_str());
+ ASSERT(elem.first->second != nullptr);
+ used_remote_cid_.insert(remote_cid);
+ return elem.first->second;
+}
+
+Cid DynamicChannelAllocator::ReserveChannel() {
+ Cid cid = kFirstDynamicChannel;
+ for (; cid <= kLastDynamicChannel; cid++) {
+ if (used_cid_.find(cid) == used_cid_.end()) break;
+ }
+ if (cid > kLastDynamicChannel) {
+ LOG_WARN("All cid are used");
+ return kInvalidCid;
+ }
+ used_cid_.insert(cid);
+ return cid;
+}
+
+void DynamicChannelAllocator::FreeChannel(Cid cid) {
+ auto channel = FindChannelByCid(cid);
+ if (channel == nullptr) {
+ LOG_INFO("Channel is not in use: psm %d, device %s", cid, link_->GetDevice().ToString().c_str());
+ return;
+ }
+ used_remote_cid_.erase(channel->GetRemoteCid());
+ channels_.erase(cid);
+ used_cid_.erase(cid);
+}
+
+bool DynamicChannelAllocator::IsPsmUsed(Psm psm) const {
+ for (const auto& channel : channels_) {
+ if (channel.second->GetPsm() == psm) {
+ return true;
+ }
+ }
+ return false;
+}
+
+std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::FindChannelByCid(Cid cid) {
+ if (channels_.find(cid) == channels_.end()) {
+ LOG_WARN("Can't find cid %d", cid);
+ return nullptr;
+ }
+ return channels_.find(cid)->second;
+}
+
+std::shared_ptr<DynamicChannelImpl> DynamicChannelAllocator::FindChannelByRemoteCid(Cid remote_cid) {
+ for (auto& channel : channels_) {
+ if (channel.second->GetRemoteCid() == remote_cid) {
+ return channel.second;
+ }
+ }
+ return nullptr;
+}
+
+size_t DynamicChannelAllocator::NumberOfChannels() const {
+ return channels_.size();
+}
+
+void DynamicChannelAllocator::OnAclDisconnected(hci::ErrorCode reason) {
+ for (auto& elem : channels_) {
+ elem.second->OnClosed(reason);
+ }
+}
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_allocator.h b/gd/l2cap/classic/internal/dynamic_channel_allocator.h
new file mode 100644
index 0000000..57e0f90
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_allocator.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <unordered_map>
+#include <unordered_set>
+
+#include "l2cap/cid.h"
+#include "l2cap/classic/internal/dynamic_channel_impl.h"
+#include "l2cap/psm.h"
+#include "l2cap/security_policy.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+class Link;
+
+// Helper class for keeping channels in a Link. It allocates and frees Channel object, and supports querying whether a
+// channel is in use
+class DynamicChannelAllocator {
+ public:
+ DynamicChannelAllocator(Link* link, os::Handler* l2cap_handler) : link_(link), l2cap_handler_(l2cap_handler) {
+ ASSERT(link_ != nullptr);
+ ASSERT(l2cap_handler_ != nullptr);
+ }
+
+ // Allocates a channel. If psm is used, OR the remote cid already exists, return nullptr.
+ // NOTE: The returned DynamicChannelImpl object is still owned by the channel allocator, NOT the client.
+ std::shared_ptr<DynamicChannelImpl> AllocateChannel(Psm psm, Cid remote_cid, SecurityPolicy security_policy);
+
+ std::shared_ptr<DynamicChannelImpl> AllocateReservedChannel(Cid reserved_cid, Psm psm, Cid remote_cid,
+ SecurityPolicy security_policy);
+
+ // Gives an unused Cid to be used for opening a channel. If a channel is used, call AllocateReservedChannel. If no
+ // longer needed, use FreeChannel.
+ Cid ReserveChannel();
+
+ // Frees a channel. If psm doesn't exist, it will crash
+ void FreeChannel(Cid cid);
+
+ bool IsPsmUsed(Psm psm) const;
+
+ std::shared_ptr<DynamicChannelImpl> FindChannelByCid(Cid cid);
+ std::shared_ptr<DynamicChannelImpl> FindChannelByRemoteCid(Cid cid);
+
+ // Returns number of open, but not reserved channels
+ size_t NumberOfChannels() const;
+
+ void OnAclDisconnected(hci::ErrorCode hci_status);
+
+ private:
+ Link* link_;
+ os::Handler* l2cap_handler_;
+ std::unordered_set<Cid> used_cid_;
+ std::unordered_map<Cid, std::shared_ptr<DynamicChannelImpl>> channels_;
+ std::unordered_set<Cid> used_remote_cid_;
+};
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_allocator_fuzz_test.cc b/gd/l2cap/classic/internal/dynamic_channel_allocator_fuzz_test.cc
new file mode 100644
index 0000000..48d9121
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_allocator_fuzz_test.cc
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2019 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 "l2cap/classic/internal/dynamic_channel_allocator.h"
+#include "l2cap/classic/internal/link_mock.h"
+#include "l2cap/internal/parameter_provider_mock.h"
+
+#include <gmock/gmock.h>
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+using hci::testing::MockAclConnection;
+using l2cap::internal::testing::MockParameterProvider;
+using l2cap::internal::testing::MockScheduler;
+using testing::MockLink;
+using ::testing::NiceMock;
+using ::testing::Return;
+
+const hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+
+class L2capClassicDynamicChannelAllocatorFuzzTest {
+ public:
+ void RunTests(const uint8_t* data, size_t size) {
+ SetUp();
+ TestPrecondition(data, size);
+ TearDown();
+ }
+
+ private:
+ void SetUp() {
+ thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+ handler_ = new os::Handler(thread_);
+ mock_parameter_provider_ = new NiceMock<MockParameterProvider>();
+ mock_classic_link_ =
+ new NiceMock<MockLink>(handler_, mock_parameter_provider_, std::make_unique<NiceMock<MockAclConnection>>());
+ EXPECT_CALL(*mock_classic_link_, GetDevice()).WillRepeatedly(Return(device));
+ channel_allocator_ = std::make_unique<DynamicChannelAllocator>(mock_classic_link_, handler_);
+ }
+
+ void TearDown() {
+ channel_allocator_.reset();
+ delete mock_classic_link_;
+ delete mock_parameter_provider_;
+ handler_->Clear();
+ delete handler_;
+ delete thread_;
+ }
+
+ void TestPrecondition(const uint8_t* data, size_t size) {
+ if (size != 2) {
+ return;
+ }
+ Psm psm = *reinterpret_cast<const Psm*>(data);
+ EXPECT_FALSE(channel_allocator_->IsPsmUsed(psm));
+ }
+
+ os::Thread* thread_{nullptr};
+ os::Handler* handler_{nullptr};
+ NiceMock<MockParameterProvider>* mock_parameter_provider_{nullptr};
+ NiceMock<MockLink>* mock_classic_link_{nullptr};
+ std::unique_ptr<DynamicChannelAllocator> channel_allocator_;
+};
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
+
+void RunL2capClassicDynamicChannelAllocatorFuzzTest(const uint8_t* data, size_t size) {
+ bluetooth::l2cap::classic::internal::L2capClassicDynamicChannelAllocatorFuzzTest test;
+ test.RunTests(data, size);
+}
\ No newline at end of file
diff --git a/gd/l2cap/classic/internal/dynamic_channel_allocator_test.cc b/gd/l2cap/classic/internal/dynamic_channel_allocator_test.cc
new file mode 100644
index 0000000..8e3f66b
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_allocator_test.cc
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2019 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 "l2cap/classic/internal/dynamic_channel_allocator.h"
+#include "l2cap/classic/internal/link_mock.h"
+#include "l2cap/internal/parameter_provider_mock.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+using l2cap::internal::testing::MockParameterProvider;
+using testing::MockLink;
+using ::testing::Return;
+
+const hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+
+class L2capClassicDynamicChannelAllocatorTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+ handler_ = new os::Handler(thread_);
+ mock_parameter_provider_ = new MockParameterProvider();
+ mock_classic_link_ = new MockLink(handler_, mock_parameter_provider_);
+ EXPECT_CALL(*mock_classic_link_, GetDevice()).WillRepeatedly(Return(device));
+ channel_allocator_ = std::make_unique<DynamicChannelAllocator>(mock_classic_link_, handler_);
+ }
+
+ void TearDown() override {
+ channel_allocator_.reset();
+ delete mock_classic_link_;
+ delete mock_parameter_provider_;
+ handler_->Clear();
+ delete handler_;
+ delete thread_;
+ }
+
+ os::Thread* thread_{nullptr};
+ os::Handler* handler_{nullptr};
+ MockParameterProvider* mock_parameter_provider_{nullptr};
+ MockLink* mock_classic_link_{nullptr};
+ std::unique_ptr<DynamicChannelAllocator> channel_allocator_;
+};
+
+TEST_F(L2capClassicDynamicChannelAllocatorTest, precondition) {
+ Psm psm = 0x03;
+ EXPECT_FALSE(channel_allocator_->IsPsmUsed(psm));
+}
+
+TEST_F(L2capClassicDynamicChannelAllocatorTest, allocate_and_free_channel) {
+ Psm psm = 0x03;
+ Cid remote_cid = kFirstDynamicChannel;
+ auto channel = channel_allocator_->AllocateChannel(psm, remote_cid, {});
+ Cid local_cid = channel->GetCid();
+ EXPECT_TRUE(channel_allocator_->IsPsmUsed(psm));
+ EXPECT_EQ(channel, channel_allocator_->FindChannelByCid(local_cid));
+ ASSERT_NO_FATAL_FAILURE(channel_allocator_->FreeChannel(local_cid));
+ EXPECT_FALSE(channel_allocator_->IsPsmUsed(psm));
+}
+
+TEST_F(L2capClassicDynamicChannelAllocatorTest, reserve_channel) {
+ Psm psm = 0x03;
+ Cid remote_cid = kFirstDynamicChannel;
+ Cid reserved = channel_allocator_->ReserveChannel();
+ auto channel = channel_allocator_->AllocateReservedChannel(reserved, psm, remote_cid, {});
+ Cid local_cid = channel->GetCid();
+ EXPECT_EQ(local_cid, reserved);
+ EXPECT_TRUE(channel_allocator_->IsPsmUsed(psm));
+ EXPECT_EQ(channel, channel_allocator_->FindChannelByCid(local_cid));
+ ASSERT_NO_FATAL_FAILURE(channel_allocator_->FreeChannel(local_cid));
+ EXPECT_FALSE(channel_allocator_->IsPsmUsed(psm));
+}
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_impl.cc b/gd/l2cap/classic/internal/dynamic_channel_impl.cc
new file mode 100644
index 0000000..c0614f9
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_impl.cc
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2019 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 <unordered_map>
+
+#include "l2cap/cid.h"
+#include "l2cap/classic/internal/dynamic_channel_impl.h"
+#include "l2cap/classic/internal/link.h"
+#include "l2cap/internal/sender.h"
+#include "l2cap/psm.h"
+#include "l2cap/security_policy.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+DynamicChannelImpl::DynamicChannelImpl(Psm psm, Cid cid, Cid remote_cid, Link* link, os::Handler* l2cap_handler)
+ : psm_(psm), cid_(cid), remote_cid_(remote_cid), link_(link), l2cap_handler_(l2cap_handler),
+ device_(link->GetDevice()) {
+ ASSERT(IsPsmValid(psm_));
+ ASSERT(cid_ > 0);
+ ASSERT(remote_cid_ > 0);
+ ASSERT(link_ != nullptr);
+ ASSERT(l2cap_handler_ != nullptr);
+}
+
+hci::Address DynamicChannelImpl::GetDevice() const {
+ return device_;
+}
+
+void DynamicChannelImpl::RegisterOnCloseCallback(os::Handler* user_handler,
+ DynamicChannel::OnCloseCallback on_close_callback) {
+ ASSERT_LOG(user_handler_ == nullptr, "OnCloseCallback can only be registered once");
+ // If channel is already closed, call the callback immediately without saving it
+ if (closed_) {
+ user_handler->Post(common::BindOnce(std::move(on_close_callback), close_reason_));
+ return;
+ }
+ user_handler_ = user_handler;
+ on_close_callback_ = std::move(on_close_callback);
+}
+
+void DynamicChannelImpl::Close() {
+ link_->SendDisconnectionRequest(cid_, remote_cid_);
+}
+
+void DynamicChannelImpl::OnClosed(hci::ErrorCode status) {
+ ASSERT_LOG(!closed_, "Device %s Cid 0x%x closed twice, old status 0x%x, new status 0x%x", device_.ToString().c_str(),
+ cid_, static_cast<int>(close_reason_), static_cast<int>(status));
+ closed_ = true;
+ close_reason_ = status;
+ link_ = nullptr;
+ l2cap_handler_ = nullptr;
+ if (user_handler_ == nullptr) {
+ return;
+ }
+ // On close callback can only be called once
+ user_handler_->Post(common::BindOnce(std::move(on_close_callback_), status));
+ user_handler_ = nullptr;
+ on_close_callback_.Reset();
+}
+
+std::string DynamicChannelImpl::ToString() {
+ std::ostringstream ss;
+ ss << "Device " << device_ << "Psm 0x" << std::hex << psm_ << " Cid 0x" << std::hex << cid_;
+ return ss.str();
+}
+
+DynamicChannelImpl::ConfigurationStatus DynamicChannelImpl::GetOutgoingConfigurationStatus() const {
+ return outgoing_configuration_status_;
+}
+
+void DynamicChannelImpl::SetOutgoingConfigurationStatus(ConfigurationStatus status) {
+ outgoing_configuration_status_ = status;
+}
+
+DynamicChannelImpl::ConfigurationStatus DynamicChannelImpl::GetIncomingConfigurationStatus() const {
+ return incoming_configuration_status_;
+}
+
+void DynamicChannelImpl::SetIncomingConfigurationStatus(ConfigurationStatus status) {
+ incoming_configuration_status_ = status;
+}
+
+void DynamicChannelImpl::SetSender(l2cap::internal::Sender* sender) {
+ sender_ = sender;
+}
+
+void DynamicChannelImpl::SetIncomingMtu(Mtu mtu) {
+ sender_->SetIncomingMtu(mtu);
+}
+
+void DynamicChannelImpl::SetRetransmissionFlowControlConfig(
+ const RetransmissionAndFlowControlConfigurationOption& option) {
+ sender_->SetChannelRetransmissionFlowControlMode(option);
+}
+
+void DynamicChannelImpl::SetFcsType(FcsType fcs_type) {
+ sender_->SetFcsType(fcs_type);
+}
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_impl.h b/gd/l2cap/classic/internal/dynamic_channel_impl.h
new file mode 100644
index 0000000..95be5c7
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_impl.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "common/bidi_queue.h"
+#include "hci/address.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic/dynamic_channel.h"
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/l2cap_packets.h"
+#include "l2cap/mtu.h"
+#include "l2cap/psm.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+class Link;
+
+class DynamicChannelImpl : public l2cap::internal::ChannelImpl {
+ public:
+ DynamicChannelImpl(Psm psm, Cid cid, Cid remote_cid, Link* link, os::Handler* l2cap_handler);
+
+ virtual ~DynamicChannelImpl() = default;
+
+ hci::Address GetDevice() const;
+
+ virtual void RegisterOnCloseCallback(os::Handler* user_handler, DynamicChannel::OnCloseCallback on_close_callback);
+
+ virtual void Close();
+ virtual void OnClosed(hci::ErrorCode status);
+ virtual std::string ToString();
+
+ common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>* GetQueueUpEnd() {
+ return channel_queue_.GetUpEnd();
+ }
+
+ common::BidiQueueEnd<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>* GetQueueDownEnd() {
+ return channel_queue_.GetDownEnd();
+ }
+
+ virtual Cid GetCid() const {
+ return cid_;
+ }
+
+ virtual Cid GetRemoteCid() const {
+ return remote_cid_;
+ }
+
+ virtual Psm GetPsm() const {
+ return psm_;
+ }
+
+ enum class ConfigurationStatus { NOT_CONFIGURED, CONFIGURED };
+
+ virtual ConfigurationStatus GetOutgoingConfigurationStatus() const;
+ virtual void SetOutgoingConfigurationStatus(ConfigurationStatus status);
+
+ virtual ConfigurationStatus GetIncomingConfigurationStatus() const;
+ virtual void SetIncomingConfigurationStatus(ConfigurationStatus status);
+
+ /**
+ * Callback from the Scheduler to notify the Sender for this channel. On config update, channel might notify the
+ * configuration to Sender
+ */
+ void SetSender(l2cap::internal::Sender* sender) override;
+
+ virtual void SetIncomingMtu(Mtu mtu);
+
+ virtual void SetRetransmissionFlowControlConfig(const RetransmissionAndFlowControlConfigurationOption& mode);
+
+ virtual void SetFcsType(FcsType fcs_type);
+
+ // TODO(cmanton) Do something a little bit better than this
+ bool local_initiated_{false};
+
+ private:
+ const Psm psm_;
+ const Cid cid_;
+ const Cid remote_cid_;
+ Link* link_;
+ os::Handler* l2cap_handler_;
+ const hci::Address device_;
+
+ // User supported states
+ os::Handler* user_handler_ = nullptr;
+ DynamicChannel::OnCloseCallback on_close_callback_{};
+
+ // Internal states
+ bool closed_ = false;
+ hci::ErrorCode close_reason_ = hci::ErrorCode::SUCCESS;
+ static constexpr size_t kChannelQueueSize = 10;
+ common::BidiQueue<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder> channel_queue_{
+ kChannelQueueSize};
+ ConfigurationStatus outgoing_configuration_status_ = ConfigurationStatus::NOT_CONFIGURED;
+ ConfigurationStatus incoming_configuration_status_ = ConfigurationStatus::NOT_CONFIGURED;
+
+ l2cap::internal::Sender* sender_ = nullptr;
+
+ DISALLOW_COPY_AND_ASSIGN(DynamicChannelImpl);
+};
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_impl_test.cc b/gd/l2cap/classic/internal/dynamic_channel_impl_test.cc
new file mode 100644
index 0000000..2f6c649e
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_impl_test.cc
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2019 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 "l2cap/classic/internal/dynamic_channel_impl.h"
+
+#include "common/testing/bind_test_util.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic/internal/link_mock.h"
+#include "l2cap/internal/parameter_provider_mock.h"
+#include "os/handler.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+using l2cap::internal::testing::MockParameterProvider;
+using testing::MockLink;
+using ::testing::Return;
+
+class L2capClassicDynamicChannelImplTest : public ::testing::Test {
+ public:
+ static void SyncHandler(os::Handler* handler) {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+ future.wait_for(std::chrono::milliseconds(3));
+ }
+
+ protected:
+ void SetUp() override {
+ thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+ l2cap_handler_ = new os::Handler(thread_);
+ }
+
+ void TearDown() override {
+ l2cap_handler_->Clear();
+ delete l2cap_handler_;
+ delete thread_;
+ }
+
+ os::Thread* thread_ = nullptr;
+ os::Handler* l2cap_handler_ = nullptr;
+};
+
+TEST_F(L2capClassicDynamicChannelImplTest, get_device) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+ hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+ DynamicChannelImpl dynamic_channel_impl(0x01, kFirstDynamicChannel, kFirstDynamicChannel, &mock_classic_link,
+ l2cap_handler_);
+ EXPECT_EQ(device, dynamic_channel_impl.GetDevice());
+}
+
+TEST_F(L2capClassicDynamicChannelImplTest, close_triggers_callback) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+ hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+ DynamicChannelImpl dynamic_channel_impl(0x01, kFirstDynamicChannel, kFirstDynamicChannel, &mock_classic_link,
+ l2cap_handler_);
+
+ // Register on close callback
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+ hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+ dynamic_channel_impl.RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+ // Channel closure should trigger such callback
+ dynamic_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+ user_handler->Clear();
+}
+
+TEST_F(L2capClassicDynamicChannelImplTest, register_callback_after_close_should_call_immediately) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+ hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+ DynamicChannelImpl dynamic_channel_impl(0x01, kFirstDynamicChannel, kFirstDynamicChannel, &mock_classic_link,
+ l2cap_handler_);
+
+ // Channel closure should do nothing
+ dynamic_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+
+ // Register on close callback should trigger callback immediately
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+ hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+ dynamic_channel_impl.RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+ user_handler->Clear();
+}
+
+TEST_F(L2capClassicDynamicChannelImplTest, close_twice_should_fail) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+ hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+ DynamicChannelImpl dynamic_channel_impl(0x01, kFirstDynamicChannel, kFirstDynamicChannel, &mock_classic_link,
+ l2cap_handler_);
+
+ // Register on close callback
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+ hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+ dynamic_channel_impl.RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+ // Channel closure should trigger such callback
+ dynamic_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+ // 2nd OnClose() callback should fail
+ EXPECT_DEATH(dynamic_channel_impl.OnClosed(hci::ErrorCode::PAGE_TIMEOUT), ".*OnClosed.*");
+
+ user_handler->Clear();
+}
+
+TEST_F(L2capClassicDynamicChannelImplTest, multiple_registeration_should_fail) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+ hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+ DynamicChannelImpl dynamic_channel_impl(0x01, kFirstDynamicChannel, kFirstDynamicChannel, &mock_classic_link,
+ l2cap_handler_);
+
+ // Register on close callback
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+ hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+ dynamic_channel_impl.RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+ EXPECT_DEATH(dynamic_channel_impl.RegisterOnCloseCallback(user_handler.get(),
+ common::BindOnce([](hci::ErrorCode status) { FAIL(); })),
+ ".*RegisterOnCloseCallback.*");
+
+ user_handler->Clear();
+}
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_service_impl.h b/gd/l2cap/classic/internal/dynamic_channel_service_impl.h
new file mode 100644
index 0000000..2fcf3fc
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_service_impl.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "common/bind.h"
+
+#include "l2cap/classic/dynamic_channel.h"
+#include "l2cap/classic/dynamic_channel_configuration_option.h"
+#include "l2cap/classic/dynamic_channel_manager.h"
+#include "l2cap/classic/dynamic_channel_service.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+class DynamicChannelServiceImpl {
+ public:
+ virtual ~DynamicChannelServiceImpl() = default;
+
+ struct PendingRegistration {
+ os::Handler* user_handler_ = nullptr;
+ DynamicChannelManager::OnRegistrationCompleteCallback on_registration_complete_callback_;
+ DynamicChannelManager::OnConnectionOpenCallback on_connection_open_callback_;
+ DynamicChannelConfigurationOption configuration_;
+ };
+
+ virtual void NotifyChannelCreation(std::unique_ptr<DynamicChannel> channel) {
+ user_handler_->Post(common::BindOnce(on_connection_open_callback_, std::move(channel)));
+ }
+
+ DynamicChannelConfigurationOption GetConfigOption() const {
+ return config_option_;
+ }
+
+ friend class DynamicChannelServiceManagerImpl;
+
+ protected:
+ // protected access for mocking
+ DynamicChannelServiceImpl(os::Handler* user_handler,
+ DynamicChannelManager::OnConnectionOpenCallback on_connection_open_callback,
+ DynamicChannelConfigurationOption config_option)
+ : user_handler_(user_handler), on_connection_open_callback_(std::move(on_connection_open_callback)),
+ config_option_(config_option) {}
+
+ private:
+ os::Handler* user_handler_ = nullptr;
+ DynamicChannelManager::OnConnectionOpenCallback on_connection_open_callback_;
+ DynamicChannelConfigurationOption config_option_;
+};
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl.cc b/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl.cc
new file mode 100644
index 0000000..a44a72e
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl.cc
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2019 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 "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
+#include "common/bind.h"
+#include "l2cap/classic/internal/dynamic_channel_service_impl.h"
+#include "l2cap/psm.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+void DynamicChannelServiceManagerImpl::Register(Psm psm,
+ DynamicChannelServiceImpl::PendingRegistration pending_registration) {
+ if (!IsPsmValid(psm)) {
+ std::unique_ptr<DynamicChannelService> invalid_service(new DynamicChannelService());
+ pending_registration.user_handler_->Post(
+ common::BindOnce(std::move(pending_registration.on_registration_complete_callback_),
+ DynamicChannelManager::RegistrationResult::FAIL_INVALID_SERVICE, std::move(invalid_service)));
+ } else if (IsServiceRegistered(psm)) {
+ std::unique_ptr<DynamicChannelService> invalid_service(new DynamicChannelService());
+ pending_registration.user_handler_->Post(common::BindOnce(
+ std::move(pending_registration.on_registration_complete_callback_),
+ DynamicChannelManager::RegistrationResult::FAIL_DUPLICATE_SERVICE, std::move(invalid_service)));
+ } else {
+ service_map_.try_emplace(psm,
+ DynamicChannelServiceImpl(pending_registration.user_handler_,
+ std::move(pending_registration.on_connection_open_callback_),
+ pending_registration.configuration_));
+ std::unique_ptr<DynamicChannelService> user_service(new DynamicChannelService(psm, this, l2cap_layer_handler_));
+ pending_registration.user_handler_->Post(
+ common::BindOnce(std::move(pending_registration.on_registration_complete_callback_),
+ DynamicChannelManager::RegistrationResult::SUCCESS, std::move(user_service)));
+ }
+}
+
+void DynamicChannelServiceManagerImpl::Unregister(Psm psm, DynamicChannelService::OnUnregisteredCallback callback,
+ os::Handler* handler) {
+ if (IsServiceRegistered(psm)) {
+ service_map_.erase(psm);
+ handler->Post(std::move(callback));
+ } else {
+ LOG_ERROR("service not registered psm:%d", psm);
+ }
+}
+
+bool DynamicChannelServiceManagerImpl::IsServiceRegistered(Psm psm) const {
+ return service_map_.find(psm) != service_map_.end();
+}
+
+DynamicChannelServiceImpl* DynamicChannelServiceManagerImpl::GetService(Psm psm) {
+ ASSERT(IsServiceRegistered(psm));
+ return &service_map_.find(psm)->second;
+}
+
+std::vector<std::pair<Psm, DynamicChannelServiceImpl*>> DynamicChannelServiceManagerImpl::GetRegisteredServices() {
+ std::vector<std::pair<Psm, DynamicChannelServiceImpl*>> results;
+ for (auto& elem : service_map_) {
+ results.emplace_back(elem.first, &elem.second);
+ }
+ return results;
+}
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl.h b/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl.h
new file mode 100644
index 0000000..c980639
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <unordered_map>
+
+#include "l2cap/classic/dynamic_channel_service.h"
+#include "l2cap/classic/internal/dynamic_channel_service_impl.h"
+#include "l2cap/psm.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+class DynamicChannelServiceManagerImpl {
+ public:
+ explicit DynamicChannelServiceManagerImpl(os::Handler* l2cap_layer_handler)
+ : l2cap_layer_handler_(l2cap_layer_handler) {}
+
+ virtual ~DynamicChannelServiceManagerImpl() = default;
+ //
+ // All APIs must be invoked in L2CAP layer handler
+ //
+ virtual void Register(Psm psm, DynamicChannelServiceImpl::PendingRegistration pending_registration);
+ virtual void Unregister(Psm psm, DynamicChannelService::OnUnregisteredCallback callback, os::Handler* handler);
+ virtual bool IsServiceRegistered(Psm psm) const;
+ virtual DynamicChannelServiceImpl* GetService(Psm psm);
+
+ virtual std::vector<std::pair<Psm, DynamicChannelServiceImpl*>> GetRegisteredServices();
+ private:
+ os::Handler* l2cap_layer_handler_ = nullptr;
+ std::unordered_map<Psm, DynamicChannelServiceImpl> service_map_;
+};
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl_mock.h b/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl_mock.h
new file mode 100644
index 0000000..34363f1
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_service_manager_impl_mock.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include "l2cap/classic/internal/dynamic_channel_impl.h"
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+namespace testing {
+
+class MockDynamicChannelServiceManagerImpl : public DynamicChannelServiceManagerImpl {
+ public:
+ MockDynamicChannelServiceManagerImpl() : DynamicChannelServiceManagerImpl(nullptr) {}
+ MOCK_METHOD(void, Register, (Psm psm, DynamicChannelServiceImpl::PendingRegistration pending_registration),
+ (override));
+ MOCK_METHOD(void, Unregister, (Psm psm, DynamicChannelService::OnUnregisteredCallback callback, os::Handler* handler),
+ (override));
+ MOCK_METHOD(bool, IsServiceRegistered, (Psm psm), (const, override));
+ MOCK_METHOD(DynamicChannelServiceImpl*, GetService, (Psm psm), (override));
+ MOCK_METHOD((std::vector<std::pair<Psm, DynamicChannelServiceImpl*>>), GetRegisteredServices, (), (override));
+};
+
+} // namespace testing
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/internal/dynamic_channel_service_manager_test.cc b/gd/l2cap/classic/internal/dynamic_channel_service_manager_test.cc
new file mode 100644
index 0000000..f59dcb6
--- /dev/null
+++ b/gd/l2cap/classic/internal/dynamic_channel_service_manager_test.cc
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2018 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 <future>
+
+#include <gtest/gtest.h>
+
+#include "common/bind.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic/dynamic_channel_manager.h"
+#include "l2cap/classic/dynamic_channel_service.h"
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
+#include "os/handler.h"
+#include "os/thread.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+class L2capDynamicServiceManagerTest : public ::testing::Test {
+ public:
+ ~L2capDynamicServiceManagerTest() override = default;
+
+ void OnServiceRegistered(bool expect_success, DynamicChannelManager::RegistrationResult result,
+ std::unique_ptr<DynamicChannelService> user_service) {
+ EXPECT_EQ(result == DynamicChannelManager::RegistrationResult::SUCCESS, expect_success);
+ service_registered_ = expect_success;
+ }
+
+ protected:
+ void SetUp() override {
+ thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+ user_handler_ = new os::Handler(thread_);
+ l2cap_handler_ = new os::Handler(thread_);
+ manager_ = new DynamicChannelServiceManagerImpl{l2cap_handler_};
+ }
+
+ void TearDown() override {
+ delete manager_;
+ l2cap_handler_->Clear();
+ delete l2cap_handler_;
+ user_handler_->Clear();
+ delete user_handler_;
+ delete thread_;
+ }
+
+ void sync_user_handler() {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ user_handler_->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+ future.wait_for(std::chrono::milliseconds(3));
+ }
+
+ DynamicChannelServiceManagerImpl* manager_ = nullptr;
+ os::Thread* thread_ = nullptr;
+ os::Handler* user_handler_ = nullptr;
+ os::Handler* l2cap_handler_ = nullptr;
+
+ bool service_registered_ = false;
+};
+
+TEST_F(L2capDynamicServiceManagerTest, register_and_unregister_classic_dynamic_channel) {
+ DynamicChannelServiceImpl::PendingRegistration pending_registration{
+ .user_handler_ = user_handler_,
+ .on_registration_complete_callback_ =
+ common::BindOnce(&L2capDynamicServiceManagerTest::OnServiceRegistered, common::Unretained(this), true)};
+ Cid cid = kSmpBrCid;
+ EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+ manager_->Register(cid, std::move(pending_registration));
+ EXPECT_TRUE(manager_->IsServiceRegistered(cid));
+ sync_user_handler();
+ EXPECT_TRUE(service_registered_);
+ manager_->Unregister(cid, common::BindOnce([] {}), user_handler_);
+ EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+}
+
+TEST_F(L2capDynamicServiceManagerTest, register_classic_dynamic_channel_bad_cid) {
+ DynamicChannelServiceImpl::PendingRegistration pending_registration{
+ .user_handler_ = user_handler_,
+ .on_registration_complete_callback_ =
+ common::BindOnce(&L2capDynamicServiceManagerTest::OnServiceRegistered, common::Unretained(this), false)};
+ Cid cid = 0x1000;
+ EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+ manager_->Register(cid, std::move(pending_registration));
+ EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+ sync_user_handler();
+ EXPECT_FALSE(service_registered_);
+}
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/fixed_channel_impl.cc b/gd/l2cap/classic/internal/fixed_channel_impl.cc
new file mode 100644
index 0000000..8ac6c94
--- /dev/null
+++ b/gd/l2cap/classic/internal/fixed_channel_impl.cc
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2019 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 <unordered_map>
+
+#include "l2cap/cid.h"
+#include "l2cap/classic/internal/fixed_channel_impl.h"
+#include "l2cap/classic/internal/link.h"
+#include "l2cap/security_policy.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+FixedChannelImpl::FixedChannelImpl(Cid cid, Link* link, os::Handler* l2cap_handler)
+ : cid_(cid), device_(link->GetDevice()), link_(link), l2cap_handler_(l2cap_handler) {
+ ASSERT_LOG(cid_ >= kFirstFixedChannel && cid_ <= kLastFixedChannel, "Invalid cid: %d", cid_);
+ ASSERT(link_ != nullptr);
+ ASSERT(l2cap_handler_ != nullptr);
+}
+
+void FixedChannelImpl::RegisterOnCloseCallback(os::Handler* user_handler,
+ FixedChannel::OnCloseCallback on_close_callback) {
+ ASSERT_LOG(user_handler_ == nullptr, "OnCloseCallback can only be registered once");
+ // If channel is already closed, call the callback immediately without saving it
+ if (closed_) {
+ user_handler->Post(common::BindOnce(std::move(on_close_callback), close_reason_));
+ return;
+ }
+ user_handler_ = user_handler;
+ on_close_callback_ = std::move(on_close_callback);
+}
+
+void FixedChannelImpl::OnClosed(hci::ErrorCode status) {
+ ASSERT_LOG(!closed_, "Device %s Cid 0x%x closed twice, old status 0x%x, new status 0x%x", device_.ToString().c_str(),
+ cid_, static_cast<int>(close_reason_), static_cast<int>(status));
+ closed_ = true;
+ close_reason_ = status;
+ acquired_ = false;
+ link_ = nullptr;
+ l2cap_handler_ = nullptr;
+ if (user_handler_ == nullptr) {
+ return;
+ }
+ // On close callback can only be called once
+ user_handler_->Post(common::BindOnce(std::move(on_close_callback_), status));
+ user_handler_ = nullptr;
+ on_close_callback_.Reset();
+}
+
+void FixedChannelImpl::Acquire() {
+ ASSERT_LOG(user_handler_ != nullptr, "Must register OnCloseCallback before calling any methods");
+ if (closed_) {
+ LOG_WARN("%s is already closed", ToString().c_str());
+ ASSERT(!acquired_);
+ return;
+ }
+ if (acquired_) {
+ LOG_DEBUG("%s was already acquired", ToString().c_str());
+ return;
+ }
+ acquired_ = true;
+ link_->RefreshRefCount();
+}
+
+void FixedChannelImpl::Release() {
+ ASSERT_LOG(user_handler_ != nullptr, "Must register OnCloseCallback before calling any methods");
+ if (closed_) {
+ LOG_WARN("%s is already closed", ToString().c_str());
+ ASSERT(!acquired_);
+ return;
+ }
+ if (!acquired_) {
+ LOG_DEBUG("%s was already released", ToString().c_str());
+ return;
+ }
+ acquired_ = false;
+ link_->RefreshRefCount();
+}
+
+void FixedChannelImpl::SetSender(l2cap::internal::Sender* sender) {}
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/fixed_channel_impl.h b/gd/l2cap/classic/internal/fixed_channel_impl.h
new file mode 100644
index 0000000..6fde5c6
--- /dev/null
+++ b/gd/l2cap/classic/internal/fixed_channel_impl.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "common/bidi_queue.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic/fixed_channel.h"
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/l2cap_packets.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+class Link;
+
+class FixedChannelImpl : public l2cap::internal::ChannelImpl {
+ public:
+ FixedChannelImpl(Cid cid, Link* link, os::Handler* l2cap_handler);
+
+ virtual ~FixedChannelImpl() = default;
+
+ hci::Address GetDevice() const {
+ return device_;
+ }
+
+ virtual void RegisterOnCloseCallback(os::Handler* user_handler, FixedChannel::OnCloseCallback on_close_callback);
+
+ virtual void Acquire();
+
+ virtual void Release();
+
+ virtual bool IsAcquired() const {
+ return acquired_;
+ }
+
+ virtual void OnClosed(hci::ErrorCode status);
+
+ virtual std::string ToString() {
+ std::ostringstream ss;
+ ss << "Device " << device_ << " Cid 0x" << std::hex << cid_;
+ return ss.str();
+ }
+
+ common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>* GetQueueUpEnd() {
+ return channel_queue_.GetUpEnd();
+ }
+
+ common::BidiQueueEnd<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>* GetQueueDownEnd() {
+ return channel_queue_.GetDownEnd();
+ }
+
+ Cid GetCid() const {
+ return cid_;
+ }
+
+ Cid GetRemoteCid() const {
+ return cid_;
+ }
+ void SetSender(l2cap::internal::Sender* sender) override;
+
+ private:
+ // Constructor states
+ // For logging purpose only
+ const Cid cid_;
+ // For logging purpose only
+ const hci::Address device_;
+ // Needed to handle Acquire() and Release()
+ Link* link_;
+ os::Handler* l2cap_handler_;
+
+ // User supported states
+ os::Handler* user_handler_ = nullptr;
+ FixedChannel::OnCloseCallback on_close_callback_{};
+
+ // Internal states
+ bool acquired_ = false;
+ bool closed_ = false;
+ hci::ErrorCode close_reason_ = hci::ErrorCode::SUCCESS;
+ static constexpr size_t kChannelQueueSize = 10;
+ common::BidiQueue<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder> channel_queue_{
+ kChannelQueueSize};
+
+ DISALLOW_COPY_AND_ASSIGN(FixedChannelImpl);
+};
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/fixed_channel_impl_mock.h b/gd/l2cap/classic/internal/fixed_channel_impl_mock.h
new file mode 100644
index 0000000..680bf51
--- /dev/null
+++ b/gd/l2cap/classic/internal/fixed_channel_impl_mock.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include "l2cap/classic/internal/fixed_channel_impl.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+namespace testing {
+
+class MockFixedChannelImpl : public FixedChannelImpl {
+ public:
+ MockFixedChannelImpl(Cid cid, Link* link, os::Handler* l2cap_handler) : FixedChannelImpl(cid, link, l2cap_handler) {}
+ MOCK_METHOD(void, RegisterOnCloseCallback,
+ (os::Handler * user_handler, FixedChannel::OnCloseCallback on_close_callback), (override));
+ MOCK_METHOD(void, Acquire, (), (override));
+ MOCK_METHOD(void, Release, (), (override));
+ MOCK_METHOD(bool, IsAcquired, (), (override, const));
+ MOCK_METHOD(void, OnClosed, (hci::ErrorCode status), (override));
+};
+
+} // namespace testing
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/internal/fixed_channel_impl_test.cc b/gd/l2cap/classic/internal/fixed_channel_impl_test.cc
new file mode 100644
index 0000000..750473d
--- /dev/null
+++ b/gd/l2cap/classic/internal/fixed_channel_impl_test.cc
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2019 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 "l2cap/classic/internal/fixed_channel_impl.h"
+
+#include "common/testing/bind_test_util.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic/internal/link_mock.h"
+#include "l2cap/internal/parameter_provider_mock.h"
+#include "os/handler.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+using l2cap::internal::testing::MockParameterProvider;
+using testing::MockLink;
+using ::testing::Return;
+
+class L2capClassicFixedChannelImplTest : public ::testing::Test {
+ public:
+ static void SyncHandler(os::Handler* handler) {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+ future.wait_for(std::chrono::milliseconds(3));
+ }
+
+ protected:
+ void SetUp() override {
+ thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+ l2cap_handler_ = new os::Handler(thread_);
+ }
+
+ void TearDown() override {
+ l2cap_handler_->Clear();
+ delete l2cap_handler_;
+ delete thread_;
+ }
+
+ os::Thread* thread_ = nullptr;
+ os::Handler* l2cap_handler_ = nullptr;
+};
+
+TEST_F(L2capClassicFixedChannelImplTest, get_device) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+ hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+ FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
+ EXPECT_EQ(device, fixed_channel_impl.GetDevice());
+}
+
+TEST_F(L2capClassicFixedChannelImplTest, close_triggers_callback) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+ hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+ FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
+
+ // Register on close callback
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+ hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+ fixed_channel_impl.RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+ // Channel closure should trigger such callback
+ fixed_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+ user_handler->Clear();
+}
+
+TEST_F(L2capClassicFixedChannelImplTest, register_callback_after_close_should_call_immediately) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+ hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+ FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
+
+ // Channel closure should do nothing
+ fixed_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+
+ // Register on close callback should trigger callback immediately
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+ hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+ fixed_channel_impl.RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+ user_handler->Clear();
+}
+
+TEST_F(L2capClassicFixedChannelImplTest, close_twice_should_fail) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+ hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+ FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
+
+ // Register on close callback
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+ hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+ fixed_channel_impl.RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+ // Channel closure should trigger such callback
+ fixed_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+ // 2nd OnClose() callback should fail
+ EXPECT_DEATH(fixed_channel_impl.OnClosed(hci::ErrorCode::PAGE_TIMEOUT), ".*OnClosed.*");
+
+ user_handler->Clear();
+}
+
+TEST_F(L2capClassicFixedChannelImplTest, multiple_registeration_should_fail) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+ hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+ FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
+
+ // Register on close callback
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+ hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+ fixed_channel_impl.RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+ EXPECT_DEATH(fixed_channel_impl.RegisterOnCloseCallback(user_handler.get(),
+ common::BindOnce([](hci::ErrorCode status) { FAIL(); })),
+ ".*RegisterOnCloseCallback.*");
+
+ user_handler->Clear();
+}
+
+TEST_F(L2capClassicFixedChannelImplTest, call_acquire_before_registeration_should_fail) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+ hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+ FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
+ EXPECT_DEATH(fixed_channel_impl.Acquire(), ".*Acquire.*");
+}
+
+TEST_F(L2capClassicFixedChannelImplTest, call_release_before_registeration_should_fail) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+ hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+ FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
+ EXPECT_DEATH(fixed_channel_impl.Release(), ".*Release.*");
+}
+
+TEST_F(L2capClassicFixedChannelImplTest, test_acquire_release_channel) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+ hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+ FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
+
+ // Register on close callback
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+ hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+ fixed_channel_impl.RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+ // Default should be false
+ EXPECT_FALSE(fixed_channel_impl.IsAcquired());
+
+ // Should be called 2 times after Acquire() and Release()
+ EXPECT_CALL(mock_classic_link, RefreshRefCount()).Times(2);
+
+ fixed_channel_impl.Acquire();
+ EXPECT_TRUE(fixed_channel_impl.IsAcquired());
+
+ fixed_channel_impl.Release();
+ EXPECT_FALSE(fixed_channel_impl.IsAcquired());
+
+ user_handler->Clear();
+}
+
+TEST_F(L2capClassicFixedChannelImplTest, test_acquire_after_close) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_classic_link(l2cap_handler_, &mock_parameter_provider);
+ hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ EXPECT_CALL(mock_classic_link, GetDevice()).WillRepeatedly(Return(device));
+ FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_classic_link, l2cap_handler_);
+
+ // Register on close callback
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+ hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+ fixed_channel_impl.RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+ // Channel closure should trigger such callback
+ fixed_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+ // Release or Acquire after closing should crash
+ EXPECT_CALL(mock_classic_link, RefreshRefCount()).Times(0);
+ EXPECT_FALSE(fixed_channel_impl.IsAcquired());
+ EXPECT_DEATH(fixed_channel_impl.Acquire(), ".*Acquire.*");
+
+ user_handler->Clear();
+}
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/fixed_channel_service_impl.h b/gd/l2cap/classic/internal/fixed_channel_service_impl.h
new file mode 100644
index 0000000..b06983f
--- /dev/null
+++ b/gd/l2cap/classic/internal/fixed_channel_service_impl.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "l2cap/classic/fixed_channel.h"
+#include "l2cap/classic/fixed_channel_manager.h"
+#include "l2cap/classic/fixed_channel_service.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+class FixedChannelServiceImpl {
+ public:
+ virtual ~FixedChannelServiceImpl() = default;
+
+ struct PendingRegistration {
+ os::Handler* user_handler_ = nullptr;
+ FixedChannelManager::OnRegistrationCompleteCallback on_registration_complete_callback_;
+ FixedChannelManager::OnConnectionOpenCallback on_connection_open_callback_;
+ };
+
+ virtual void NotifyChannelCreation(std::unique_ptr<FixedChannel> channel) {
+ user_handler_->Post(common::BindOnce(on_connection_open_callback_, std::move(channel)));
+ }
+
+ friend class FixedChannelServiceManagerImpl;
+
+ protected:
+ // protected access for mocking
+ FixedChannelServiceImpl(os::Handler* user_handler,
+ FixedChannelManager::OnConnectionOpenCallback on_connection_open_callback)
+ : user_handler_(user_handler), on_connection_open_callback_(std::move(on_connection_open_callback)) {}
+
+ private:
+ os::Handler* user_handler_ = nullptr;
+ FixedChannelManager::OnConnectionOpenCallback on_connection_open_callback_;
+};
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/fixed_channel_service_impl_mock.h b/gd/l2cap/classic/internal/fixed_channel_service_impl_mock.h
new file mode 100644
index 0000000..7aeb094
--- /dev/null
+++ b/gd/l2cap/classic/internal/fixed_channel_service_impl_mock.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include "l2cap/classic/internal/fixed_channel_impl.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+namespace testing {
+
+class MockFixedChannelServiceImpl : public FixedChannelServiceImpl {
+ public:
+ MockFixedChannelServiceImpl() : FixedChannelServiceImpl(nullptr, FixedChannelManager::OnConnectionOpenCallback()) {}
+ MOCK_METHOD(void, NotifyChannelCreation, (std::unique_ptr<FixedChannel> channel), (override));
+};
+
+} // namespace testing
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/internal/fixed_channel_service_manager_impl.cc b/gd/l2cap/classic/internal/fixed_channel_service_manager_impl.cc
new file mode 100644
index 0000000..b557970
--- /dev/null
+++ b/gd/l2cap/classic/internal/fixed_channel_service_manager_impl.cc
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2019 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 "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
+
+#include "common/bind.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic/internal/fixed_channel_service_impl.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+void FixedChannelServiceManagerImpl::Register(Cid cid,
+ FixedChannelServiceImpl::PendingRegistration pending_registration) {
+ if (cid < kFirstFixedChannel || cid > kLastFixedChannel || cid == kClassicSignallingCid) {
+ std::unique_ptr<FixedChannelService> invalid_service(new FixedChannelService());
+ pending_registration.user_handler_->Post(
+ common::BindOnce(std::move(pending_registration.on_registration_complete_callback_),
+ FixedChannelManager::RegistrationResult::FAIL_INVALID_SERVICE, std::move(invalid_service)));
+ } else if (IsServiceRegistered(cid)) {
+ std::unique_ptr<FixedChannelService> invalid_service(new FixedChannelService());
+ pending_registration.user_handler_->Post(
+ common::BindOnce(std::move(pending_registration.on_registration_complete_callback_),
+ FixedChannelManager::RegistrationResult::FAIL_DUPLICATE_SERVICE, std::move(invalid_service)));
+ } else {
+ service_map_.try_emplace(cid,
+ FixedChannelServiceImpl(pending_registration.user_handler_,
+ std::move(pending_registration.on_connection_open_callback_)));
+ std::unique_ptr<FixedChannelService> user_service(new FixedChannelService(cid, this, l2cap_layer_handler_));
+ pending_registration.user_handler_->Post(
+ common::BindOnce(std::move(pending_registration.on_registration_complete_callback_),
+ FixedChannelManager::RegistrationResult::SUCCESS, std::move(user_service)));
+ }
+}
+
+void FixedChannelServiceManagerImpl::Unregister(Cid cid, FixedChannelService::OnUnregisteredCallback callback,
+ os::Handler* handler) {
+ if (IsServiceRegistered(cid)) {
+ service_map_.erase(cid);
+ handler->Post(std::move(callback));
+ } else {
+ LOG_ERROR("service not registered cid:%d", cid);
+ }
+}
+
+bool FixedChannelServiceManagerImpl::IsServiceRegistered(Cid cid) const {
+ return service_map_.find(cid) != service_map_.end();
+}
+
+FixedChannelServiceImpl* FixedChannelServiceManagerImpl::GetService(Cid cid) {
+ ASSERT(IsServiceRegistered(cid));
+ return &service_map_.find(cid)->second;
+}
+
+std::vector<std::pair<Cid, FixedChannelServiceImpl*>> FixedChannelServiceManagerImpl::GetRegisteredServices() {
+ std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+ for (auto& elem : service_map_) {
+ results.emplace_back(elem.first, &elem.second);
+ }
+ return results;
+}
+
+namespace {
+constexpr uint64_t kSignallingChannelMask = 0x02;
+constexpr uint64_t kConnectionlessReceptionMask = 0x04;
+constexpr uint64_t kBrEdrSecurityManager = 0x80;
+} // namespace
+
+uint64_t FixedChannelServiceManagerImpl::GetSupportedFixedChannelMask() {
+ uint64_t result = 0;
+ result |= kSignallingChannelMask; // Signalling channel is mandatory
+ for (const auto& elem : service_map_) {
+ Cid cid = elem.first;
+ switch (cid) {
+ case kConnectionlessCid:
+ result |= kConnectionlessReceptionMask;
+ continue;
+ case kSmpBrCid:
+ result |= kBrEdrSecurityManager;
+ continue;
+ default:
+ LOG_WARN("Unknown fixed channel is registered: 0x%x", cid);
+ continue;
+ }
+ }
+ return result;
+}
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/fixed_channel_service_manager_impl.h b/gd/l2cap/classic/internal/fixed_channel_service_manager_impl.h
new file mode 100644
index 0000000..1e1d21d
--- /dev/null
+++ b/gd/l2cap/classic/internal/fixed_channel_service_manager_impl.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <unordered_map>
+
+#include "l2cap/cid.h"
+#include "l2cap/classic/fixed_channel_service.h"
+#include "l2cap/classic/internal/fixed_channel_service_impl.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+class FixedChannelServiceManagerImpl {
+ public:
+ explicit FixedChannelServiceManagerImpl(os::Handler* l2cap_layer_handler)
+ : l2cap_layer_handler_(l2cap_layer_handler) {}
+ virtual ~FixedChannelServiceManagerImpl() = default;
+
+ // All APIs must be invoked in L2CAP layer handler
+
+ virtual void Register(Cid cid, FixedChannelServiceImpl::PendingRegistration pending_registration);
+ virtual void Unregister(Cid cid, FixedChannelService::OnUnregisteredCallback callback, os::Handler* handler);
+ virtual bool IsServiceRegistered(Cid cid) const;
+ virtual FixedChannelServiceImpl* GetService(Cid cid);
+ virtual std::vector<std::pair<Cid, FixedChannelServiceImpl*>> GetRegisteredServices();
+ virtual uint64_t GetSupportedFixedChannelMask();
+
+ private:
+ os::Handler* l2cap_layer_handler_ = nullptr;
+ std::unordered_map<Cid, FixedChannelServiceImpl> service_map_;
+};
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/fixed_channel_service_manager_impl_mock.h b/gd/l2cap/classic/internal/fixed_channel_service_manager_impl_mock.h
new file mode 100644
index 0000000..55aa4cf
--- /dev/null
+++ b/gd/l2cap/classic/internal/fixed_channel_service_manager_impl_mock.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include "l2cap/classic/internal/fixed_channel_impl.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+namespace testing {
+
+class MockFixedChannelServiceManagerImpl : public FixedChannelServiceManagerImpl {
+ public:
+ MockFixedChannelServiceManagerImpl() : FixedChannelServiceManagerImpl(nullptr) {}
+ MOCK_METHOD(void, Register, (Cid cid, FixedChannelServiceImpl::PendingRegistration pending_registration), (override));
+ MOCK_METHOD(void, Unregister, (Cid cid, FixedChannelService::OnUnregisteredCallback callback, os::Handler* handler),
+ (override));
+ MOCK_METHOD(bool, IsServiceRegistered, (Cid cid), (const, override));
+ MOCK_METHOD(FixedChannelServiceImpl*, GetService, (Cid cid), (override));
+ MOCK_METHOD((std::vector<std::pair<Cid, FixedChannelServiceImpl*>>), GetRegisteredServices, (), (override));
+};
+
+} // namespace testing
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/internal/fixed_channel_service_manager_test.cc b/gd/l2cap/classic/internal/fixed_channel_service_manager_test.cc
new file mode 100644
index 0000000..d586913
--- /dev/null
+++ b/gd/l2cap/classic/internal/fixed_channel_service_manager_test.cc
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2018 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 "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
+
+#include <future>
+
+#include "common/bind.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic/fixed_channel_manager.h"
+#include "l2cap/classic/fixed_channel_service.h"
+#include "os/handler.h"
+#include "os/thread.h"
+
+#include <gtest/gtest.h>
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+class L2capClassicFixedServiceManagerTest : public ::testing::Test {
+ public:
+ ~L2capClassicFixedServiceManagerTest() override = default;
+
+ void OnServiceRegistered(bool expect_success, FixedChannelManager::RegistrationResult result,
+ std::unique_ptr<FixedChannelService> user_service) {
+ EXPECT_EQ(result == FixedChannelManager::RegistrationResult::SUCCESS, expect_success);
+ service_registered_ = expect_success;
+ }
+
+ protected:
+ void SetUp() override {
+ manager_ = new FixedChannelServiceManagerImpl{nullptr};
+ thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+ user_handler_ = new os::Handler(thread_);
+ }
+
+ void TearDown() override {
+ user_handler_->Clear();
+ delete user_handler_;
+ delete thread_;
+ delete manager_;
+ }
+
+ void sync_user_handler() {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ user_handler_->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+ future.wait_for(std::chrono::milliseconds(3));
+ }
+
+ FixedChannelServiceManagerImpl* manager_ = nullptr;
+ os::Thread* thread_ = nullptr;
+ os::Handler* user_handler_ = nullptr;
+
+ bool service_registered_ = false;
+};
+
+TEST_F(L2capClassicFixedServiceManagerTest, register_and_unregister_classic_fixed_channel) {
+ FixedChannelServiceImpl::PendingRegistration pending_registration{
+ .user_handler_ = user_handler_,
+ .on_registration_complete_callback_ =
+ common::BindOnce(&L2capClassicFixedServiceManagerTest::OnServiceRegistered, common::Unretained(this), true)};
+ Cid cid = kSmpBrCid;
+ EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+ manager_->Register(cid, std::move(pending_registration));
+ EXPECT_TRUE(manager_->IsServiceRegistered(cid));
+ sync_user_handler();
+ EXPECT_TRUE(service_registered_);
+ manager_->Unregister(cid, common::BindOnce([] {}), user_handler_);
+ EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+}
+
+TEST_F(L2capClassicFixedServiceManagerTest, register_classic_fixed_channel_bad_cid) {
+ FixedChannelServiceImpl::PendingRegistration pending_registration{
+ .user_handler_ = user_handler_,
+ .on_registration_complete_callback_ =
+ common::BindOnce(&L2capClassicFixedServiceManagerTest::OnServiceRegistered, common::Unretained(this), false)};
+ Cid cid = 0x1000;
+ EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+ manager_->Register(cid, std::move(pending_registration));
+ EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+ sync_user_handler();
+ EXPECT_FALSE(service_registered_);
+}
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/link.cc b/gd/l2cap/classic/internal/link.cc
new file mode 100644
index 0000000..63f5f71
--- /dev/null
+++ b/gd/l2cap/classic/internal/link.cc
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2019 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 <chrono>
+#include <memory>
+
+#include "hci/acl_manager.h"
+#include "l2cap/classic/dynamic_channel_manager.h"
+#include "l2cap/classic/internal/fixed_channel_impl.h"
+#include "l2cap/classic/internal/link.h"
+#include "l2cap/internal/parameter_provider.h"
+#include "os/alarm.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+Link::Link(os::Handler* l2cap_handler, std::unique_ptr<hci::AclConnection> acl_connection,
+ l2cap::internal::ParameterProvider* parameter_provider,
+ DynamicChannelServiceManagerImpl* dynamic_service_manager,
+ FixedChannelServiceManagerImpl* fixed_service_manager)
+ : l2cap_handler_(l2cap_handler), acl_connection_(std::move(acl_connection)),
+ data_pipeline_manager_(l2cap_handler, acl_connection_->GetAclQueueEnd()), parameter_provider_(parameter_provider),
+ dynamic_service_manager_(dynamic_service_manager), fixed_service_manager_(fixed_service_manager),
+ signalling_manager_(l2cap_handler_, this, dynamic_service_manager_, &dynamic_channel_allocator_,
+ fixed_service_manager_) {
+ ASSERT(l2cap_handler_ != nullptr);
+ ASSERT(acl_connection_ != nullptr);
+ ASSERT(parameter_provider_ != nullptr);
+ link_idle_disconnect_alarm_.Schedule(common::BindOnce(&Link::Disconnect, common::Unretained(this)),
+ parameter_provider_->GetClassicLinkIdleDisconnectTimeout());
+}
+
+void Link::OnAclDisconnected(hci::ErrorCode status) {
+ fixed_channel_allocator_.OnAclDisconnected(status);
+ dynamic_channel_allocator_.OnAclDisconnected(status);
+}
+
+void Link::Disconnect() {
+ acl_connection_->Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION);
+}
+
+std::shared_ptr<FixedChannelImpl> Link::AllocateFixedChannel(Cid cid, SecurityPolicy security_policy) {
+ auto channel = fixed_channel_allocator_.AllocateChannel(cid, security_policy);
+ data_pipeline_manager_.AttachChannel(cid, channel);
+ return channel;
+}
+
+bool Link::IsFixedChannelAllocated(Cid cid) {
+ return fixed_channel_allocator_.IsChannelAllocated(cid);
+}
+
+Cid Link::ReserveDynamicChannel() {
+ return dynamic_channel_allocator_.ReserveChannel();
+}
+
+void Link::SendConnectionRequest(Psm psm, Cid local_cid) {
+ signalling_manager_.SendConnectionRequest(psm, local_cid);
+}
+
+void Link::SendConnectionRequest(Psm psm, Cid local_cid,
+ PendingDynamicChannelConnection pending_dynamic_channel_connection) {
+ local_cid_to_pending_dynamic_channel_connection_map_[local_cid] = std::move(pending_dynamic_channel_connection);
+ signalling_manager_.SendConnectionRequest(psm, local_cid);
+}
+
+void Link::SendDisconnectionRequest(Cid local_cid, Cid remote_cid) {
+ signalling_manager_.SendDisconnectionRequest(local_cid, remote_cid);
+}
+
+void Link::SendInformationRequest(InformationRequestInfoType type) {
+ signalling_manager_.SendInformationRequest(type);
+}
+
+std::shared_ptr<DynamicChannelImpl> Link::AllocateDynamicChannel(Psm psm, Cid remote_cid,
+ SecurityPolicy security_policy) {
+ auto channel = dynamic_channel_allocator_.AllocateChannel(psm, remote_cid, security_policy);
+ if (channel != nullptr) {
+ data_pipeline_manager_.AttachChannel(channel->GetCid(), channel);
+ }
+ channel->local_initiated_ = false;
+ return channel;
+}
+
+std::shared_ptr<DynamicChannelImpl> Link::AllocateReservedDynamicChannel(Cid reserved_cid, Psm psm, Cid remote_cid,
+ SecurityPolicy security_policy) {
+ auto channel = dynamic_channel_allocator_.AllocateReservedChannel(reserved_cid, psm, remote_cid, security_policy);
+ if (channel != nullptr) {
+ data_pipeline_manager_.AttachChannel(channel->GetCid(), channel);
+ }
+ channel->local_initiated_ = true;
+ return channel;
+}
+
+classic::DynamicChannelConfigurationOption Link::GetConfigurationForInitialConfiguration(Cid cid) {
+ ASSERT(local_cid_to_pending_dynamic_channel_connection_map_.find(cid) !=
+ local_cid_to_pending_dynamic_channel_connection_map_.end());
+ return local_cid_to_pending_dynamic_channel_connection_map_[cid].configuration_;
+}
+
+void Link::FreeDynamicChannel(Cid cid) {
+ if (dynamic_channel_allocator_.FindChannelByCid(cid) == nullptr) {
+ return;
+ }
+ data_pipeline_manager_.DetachChannel(cid);
+ dynamic_channel_allocator_.FreeChannel(cid);
+}
+
+void Link::RefreshRefCount() {
+ int ref_count = 0;
+ ref_count += fixed_channel_allocator_.GetRefCount();
+ ref_count += dynamic_channel_allocator_.NumberOfChannels();
+ ASSERT_LOG(ref_count >= 0, "ref_count %d is less than 0", ref_count);
+ if (ref_count > 0) {
+ link_idle_disconnect_alarm_.Cancel();
+ } else {
+ link_idle_disconnect_alarm_.Schedule(common::BindOnce(&Link::Disconnect, common::Unretained(this)),
+ parameter_provider_->GetClassicLinkIdleDisconnectTimeout());
+ }
+}
+
+void Link::NotifyChannelCreation(Cid cid, std::unique_ptr<DynamicChannel> user_channel) {
+ ASSERT(local_cid_to_pending_dynamic_channel_connection_map_.find(cid) !=
+ local_cid_to_pending_dynamic_channel_connection_map_.end());
+ auto& pending_dynamic_channel_connection = local_cid_to_pending_dynamic_channel_connection_map_[cid];
+ pending_dynamic_channel_connection.handler_->Post(
+ common::BindOnce(std::move(pending_dynamic_channel_connection.on_open_callback_), std::move(user_channel)));
+ local_cid_to_pending_dynamic_channel_connection_map_.erase(cid);
+}
+
+void Link::NotifyChannelFail(Cid cid) {
+ ASSERT(local_cid_to_pending_dynamic_channel_connection_map_.find(cid) !=
+ local_cid_to_pending_dynamic_channel_connection_map_.end());
+ auto& pending_dynamic_channel_connection = local_cid_to_pending_dynamic_channel_connection_map_[cid];
+ // TODO(cmanton) Pass proper connection falure result to user
+ DynamicChannelManager::ConnectionResult result;
+ pending_dynamic_channel_connection.handler_->Post(
+ common::BindOnce(std::move(pending_dynamic_channel_connection.on_fail_callback_), result));
+ local_cid_to_pending_dynamic_channel_connection_map_.erase(cid);
+}
+
+void Link::SetRemoteConnectionlessMtu(Mtu mtu) {
+ remote_mtu_ = mtu;
+}
+
+Mtu Link::GetRemoteConnectionlessMtu() const {
+ return remote_mtu_;
+}
+
+void Link::SetRemoteSupportsErtm(bool supported) {
+ remote_supports_ertm_ = supported;
+}
+
+bool Link::GetRemoteSupportsErtm() const {
+ return remote_supports_ertm_;
+}
+
+void Link::SetRemoteSupportsFcs(bool supported) {
+ remote_supports_fcs_ = supported;
+}
+
+bool Link::GetRemoteSupportsFcs() const {
+ return remote_supports_fcs_;
+}
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/link.h b/gd/l2cap/classic/internal/link.h
new file mode 100644
index 0000000..44a5b25
--- /dev/null
+++ b/gd/l2cap/classic/internal/link.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <unordered_map>
+
+#include "hci/acl_manager.h"
+#include "l2cap/classic/dynamic_channel_configuration_option.h"
+#include "l2cap/classic/internal/dynamic_channel_allocator.h"
+#include "l2cap/classic/internal/dynamic_channel_impl.h"
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
+#include "l2cap/classic/internal/fixed_channel_impl.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
+#include "l2cap/internal/data_pipeline_manager.h"
+#include "l2cap/internal/fixed_channel_allocator.h"
+#include "l2cap/internal/parameter_provider.h"
+#include "os/alarm.h"
+#include "os/handler.h"
+#include "signalling_manager.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+class Link {
+ public:
+ Link(os::Handler* l2cap_handler, std::unique_ptr<hci::AclConnection> acl_connection,
+ l2cap::internal::ParameterProvider* parameter_provider,
+ DynamicChannelServiceManagerImpl* dynamic_service_manager,
+ FixedChannelServiceManagerImpl* fixed_service_manager);
+
+ virtual ~Link() = default;
+
+ virtual hci::Address GetDevice() {
+ return acl_connection_->GetAddress();
+ }
+
+ struct PendingDynamicChannelConnection {
+ os::Handler* handler_;
+ DynamicChannelManager::OnConnectionOpenCallback on_open_callback_;
+ DynamicChannelManager::OnConnectionFailureCallback on_fail_callback_;
+ classic::DynamicChannelConfigurationOption configuration_;
+ };
+
+ // ACL methods
+
+ virtual void OnAclDisconnected(hci::ErrorCode status);
+
+ virtual void Disconnect();
+
+ // FixedChannel methods
+
+ std::shared_ptr<FixedChannelImpl> AllocateFixedChannel(Cid cid, SecurityPolicy security_policy);
+
+ virtual bool IsFixedChannelAllocated(Cid cid);
+
+ // DynamicChannel methods
+
+ virtual Cid ReserveDynamicChannel();
+
+ virtual void SendConnectionRequest(Psm psm, Cid local_cid);
+ virtual void SendConnectionRequest(Psm psm, Cid local_cid,
+ PendingDynamicChannelConnection pending_dynamic_channel_connection);
+
+ virtual void SendInformationRequest(InformationRequestInfoType type);
+
+ virtual void SendDisconnectionRequest(Cid local_cid, Cid remote_cid);
+
+ virtual std::shared_ptr<DynamicChannelImpl> AllocateDynamicChannel(Psm psm, Cid remote_cid,
+ SecurityPolicy security_policy);
+
+ virtual std::shared_ptr<DynamicChannelImpl> AllocateReservedDynamicChannel(Cid reserved_cid, Psm psm, Cid remote_cid,
+ SecurityPolicy security_policy);
+
+ virtual classic::DynamicChannelConfigurationOption GetConfigurationForInitialConfiguration(Cid cid);
+
+ virtual void FreeDynamicChannel(Cid cid);
+
+ // Check how many channels are acquired or in use, if zero, start tear down timer, if non-zero, cancel tear down timer
+ virtual void RefreshRefCount();
+
+ virtual void NotifyChannelCreation(Cid cid, std::unique_ptr<DynamicChannel> channel);
+ virtual void NotifyChannelFail(Cid cid);
+
+ // Information received from signaling channel
+ virtual void SetRemoteConnectionlessMtu(Mtu mtu);
+ virtual Mtu GetRemoteConnectionlessMtu() const;
+ virtual void SetRemoteSupportsErtm(bool supported);
+ virtual bool GetRemoteSupportsErtm() const;
+ virtual void SetRemoteSupportsFcs(bool supported);
+ virtual bool GetRemoteSupportsFcs() const;
+
+ virtual std::string ToString() {
+ return GetDevice().ToString();
+ }
+
+ private:
+ os::Handler* l2cap_handler_;
+ l2cap::internal::FixedChannelAllocator<FixedChannelImpl, Link> fixed_channel_allocator_{this, l2cap_handler_};
+ DynamicChannelAllocator dynamic_channel_allocator_{this, l2cap_handler_};
+ std::unique_ptr<hci::AclConnection> acl_connection_;
+ l2cap::internal::DataPipelineManager data_pipeline_manager_;
+ l2cap::internal::ParameterProvider* parameter_provider_;
+ DynamicChannelServiceManagerImpl* dynamic_service_manager_;
+ FixedChannelServiceManagerImpl* fixed_service_manager_;
+ ClassicSignallingManager signalling_manager_;
+ std::unordered_map<Cid, PendingDynamicChannelConnection> local_cid_to_pending_dynamic_channel_connection_map_;
+ os::Alarm link_idle_disconnect_alarm_{l2cap_handler_};
+ Mtu remote_mtu_ = kMinimumClassicMtu;
+ bool remote_supports_ertm_ = false;
+ bool remote_supports_fcs_ = false;
+ DISALLOW_COPY_AND_ASSIGN(Link);
+};
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/link_manager.cc b/gd/l2cap/classic/internal/link_manager.cc
new file mode 100644
index 0000000..812b180
--- /dev/null
+++ b/gd/l2cap/classic/internal/link_manager.cc
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2019 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 <memory>
+#include <unordered_map>
+
+#include "hci/acl_manager.h"
+#include "hci/address.h"
+#include "l2cap/classic/internal/link.h"
+#include "l2cap/internal/scheduler_fifo.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+#include "l2cap/classic/internal/link_manager.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+void LinkManager::ConnectFixedChannelServices(hci::Address device,
+ PendingFixedChannelConnection pending_fixed_channel_connection) {
+ // Check if there is any service registered
+ auto fixed_channel_services = fixed_channel_service_manager_->GetRegisteredServices();
+ if (fixed_channel_services.empty()) {
+ // If so, return error
+ pending_fixed_channel_connection.handler_->Post(common::BindOnce(
+ std::move(pending_fixed_channel_connection.on_fail_callback_),
+ FixedChannelManager::ConnectionResult{
+ .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_NO_SERVICE_REGISTERED}));
+ return;
+ }
+ // Otherwise, check if device has an ACL connection
+ auto* link = GetLink(device);
+ if (link != nullptr) {
+ // If device already have an ACL connection
+ // Check if all registered services have an allocated channel and allocate one if not already allocated
+ int num_new_channels = 0;
+ for (auto& fixed_channel_service : fixed_channel_services) {
+ if (link->IsFixedChannelAllocated(fixed_channel_service.first)) {
+ // This channel is already allocated for this link, do not allocated twice
+ continue;
+ }
+ // Allocate channel for newly registered fixed channels
+ auto fixed_channel_impl = link->AllocateFixedChannel(fixed_channel_service.first, SecurityPolicy());
+ fixed_channel_service.second->NotifyChannelCreation(
+ std::make_unique<FixedChannel>(fixed_channel_impl, l2cap_handler_));
+ num_new_channels++;
+ }
+ // Declare connection failure if no new channels are created
+ if (num_new_channels == 0) {
+ pending_fixed_channel_connection.handler_->Post(common::BindOnce(
+ std::move(pending_fixed_channel_connection.on_fail_callback_),
+ FixedChannelManager::ConnectionResult{
+ .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_ALL_SERVICES_HAVE_CHANNEL}));
+ }
+ // No need to create ACL connection, return without saving any pending connections
+ return;
+ }
+ // If not, create new ACL connection
+ // Add request to pending link list first
+ auto pending_link = pending_links_.find(device);
+ if (pending_link == pending_links_.end()) {
+ // Create pending link if not exist
+ pending_links_.try_emplace(device);
+ pending_link = pending_links_.find(device);
+ }
+ pending_link->second.pending_fixed_channel_connections_.push_back(std::move(pending_fixed_channel_connection));
+ // Then create new ACL connection
+ acl_manager_->CreateConnection(device);
+}
+
+void LinkManager::ConnectDynamicChannelServices(
+ hci::Address device, Link::PendingDynamicChannelConnection pending_dynamic_channel_connection, Psm psm) {
+ auto* link = GetLink(device);
+ if (link == nullptr) {
+ acl_manager_->CreateConnection(device);
+ if (pending_dynamic_channels_.find(device) != pending_dynamic_channels_.end()) {
+ pending_dynamic_channels_[device].push_back(psm);
+ pending_dynamic_channels_callbacks_[device].push_back(std::move(pending_dynamic_channel_connection));
+ } else {
+ pending_dynamic_channels_[device] = {psm};
+ pending_dynamic_channels_callbacks_[device].push_back(std::move(pending_dynamic_channel_connection));
+ }
+ return;
+ }
+ link->SendConnectionRequest(psm, link->ReserveDynamicChannel(), std::move(pending_dynamic_channel_connection));
+}
+
+Link* LinkManager::GetLink(const hci::Address device) {
+ if (links_.find(device) == links_.end()) {
+ return nullptr;
+ }
+ return &links_.find(device)->second;
+}
+
+void LinkManager::OnConnectSuccess(std::unique_ptr<hci::AclConnection> acl_connection) {
+ // Same link should not be connected twice
+ hci::Address device = acl_connection->GetAddress();
+ ASSERT_LOG(GetLink(device) == nullptr, "%s is connected twice without disconnection",
+ acl_connection->GetAddress().ToString().c_str());
+ // Register ACL disconnection callback in LinkManager so that we can clean up link resource properly
+ acl_connection->RegisterDisconnectCallback(
+ common::BindOnce(&LinkManager::OnDisconnect, common::Unretained(this), device), l2cap_handler_);
+ links_.try_emplace(device, l2cap_handler_, std::move(acl_connection), parameter_provider_,
+ dynamic_channel_service_manager_, fixed_channel_service_manager_);
+ auto* link = GetLink(device);
+ ASSERT(link != nullptr);
+ link->SendInformationRequest(InformationRequestInfoType::EXTENDED_FEATURES_SUPPORTED);
+ link->SendInformationRequest(InformationRequestInfoType::FIXED_CHANNELS_SUPPORTED);
+
+ // Allocate and distribute channels for all registered fixed channel services
+ auto fixed_channel_services = fixed_channel_service_manager_->GetRegisteredServices();
+ for (auto& fixed_channel_service : fixed_channel_services) {
+ auto fixed_channel_impl = link->AllocateFixedChannel(fixed_channel_service.first, SecurityPolicy());
+ fixed_channel_service.second->NotifyChannelCreation(
+ std::make_unique<FixedChannel>(fixed_channel_impl, l2cap_handler_));
+ }
+ if (pending_dynamic_channels_.find(device) != pending_dynamic_channels_.end()) {
+ for (Psm psm : pending_dynamic_channels_[device]) {
+ auto& callbacks = pending_dynamic_channels_callbacks_[device].front();
+ link->SendConnectionRequest(psm, link->ReserveDynamicChannel(), std::move(callbacks));
+ pending_dynamic_channels_callbacks_[device].pop_front();
+ }
+ pending_dynamic_channels_.erase(device);
+ pending_dynamic_channels_callbacks_.erase(device);
+ }
+ // Remove device from pending links list, if any
+ auto pending_link = pending_links_.find(device);
+ if (pending_link == pending_links_.end()) {
+ // This an incoming connection, exit
+ return;
+ }
+ // This is an outgoing connection, remove entry in pending link list
+ pending_links_.erase(pending_link);
+}
+
+void LinkManager::OnConnectFail(hci::Address device, hci::ErrorCode reason) {
+ // Notify all pending links for this device
+ auto pending_link = pending_links_.find(device);
+ if (pending_link == pending_links_.end()) {
+ // There is no pending link, exit
+ LOG_DEBUG("Connection to %s failed without a pending link", device.ToString().c_str());
+ if (pending_dynamic_channels_callbacks_.find(device) != pending_dynamic_channels_callbacks_.end()) {
+ for (Link::PendingDynamicChannelConnection& callbacks : pending_dynamic_channels_callbacks_[device]) {
+ callbacks.handler_->Post(common::BindOnce(std::move(callbacks.on_fail_callback_),
+ DynamicChannelManager::ConnectionResult{
+ .hci_error = hci::ErrorCode::CONNECTION_TIMEOUT,
+ }));
+ }
+ pending_dynamic_channels_.erase(device);
+ pending_dynamic_channels_callbacks_.erase(device);
+ }
+ return;
+ }
+ for (auto& pending_fixed_channel_connection : pending_link->second.pending_fixed_channel_connections_) {
+ pending_fixed_channel_connection.handler_->Post(common::BindOnce(
+ std::move(pending_fixed_channel_connection.on_fail_callback_),
+ FixedChannelManager::ConnectionResult{
+ .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_HCI_ERROR, .hci_error = reason}));
+ }
+ // Remove entry in pending link list
+ pending_links_.erase(pending_link);
+}
+
+void LinkManager::OnDisconnect(hci::Address device, hci::ErrorCode status) {
+ auto* link = GetLink(device);
+ ASSERT_LOG(link != nullptr, "Device %s is disconnected with reason 0x%x, but not in local database",
+ device.ToString().c_str(), static_cast<uint8_t>(status));
+ link->OnAclDisconnected(status);
+ links_.erase(device);
+}
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/link_manager.h b/gd/l2cap/classic/internal/link_manager.h
new file mode 100644
index 0000000..6d282a2
--- /dev/null
+++ b/gd/l2cap/classic/internal/link_manager.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <unordered_map>
+
+#include "hci/acl_manager.h"
+#include "hci/address.h"
+#include "l2cap/classic/dynamic_channel_manager.h"
+#include "l2cap/classic/fixed_channel_manager.h"
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
+#include "l2cap/classic/internal/link.h"
+#include "l2cap/internal/parameter_provider.h"
+#include "l2cap/internal/scheduler.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+class LinkManager : public hci::ConnectionCallbacks {
+ public:
+ LinkManager(os::Handler* l2cap_handler, hci::AclManager* acl_manager,
+ FixedChannelServiceManagerImpl* fixed_channel_service_manager,
+ DynamicChannelServiceManagerImpl* dynamic_channel_service_manager,
+ l2cap::internal::ParameterProvider* parameter_provider)
+ : l2cap_handler_(l2cap_handler), acl_manager_(acl_manager),
+ fixed_channel_service_manager_(fixed_channel_service_manager),
+ dynamic_channel_service_manager_(dynamic_channel_service_manager), parameter_provider_(parameter_provider) {
+ acl_manager_->RegisterCallbacks(this, l2cap_handler_);
+ }
+
+ struct PendingFixedChannelConnection {
+ os::Handler* handler_;
+ FixedChannelManager::OnConnectionFailureCallback on_fail_callback_;
+ };
+
+ struct PendingLink {
+ std::vector<PendingFixedChannelConnection> pending_fixed_channel_connections_;
+ };
+
+ // ACL methods
+
+ Link* GetLink(hci::Address device);
+ void OnConnectSuccess(std::unique_ptr<hci::AclConnection> acl_connection) override;
+ void OnConnectFail(hci::Address device, hci::ErrorCode reason) override;
+ void OnDisconnect(hci::Address device, hci::ErrorCode status);
+
+ // FixedChannelManager methods
+
+ void ConnectFixedChannelServices(hci::Address device, PendingFixedChannelConnection pending_fixed_channel_connection);
+
+ // DynamicChannelManager methods
+
+ void ConnectDynamicChannelServices(hci::Address device,
+ Link::PendingDynamicChannelConnection pending_dynamic_channel_connection, Psm psm);
+
+ private:
+ // Dependencies
+ os::Handler* l2cap_handler_;
+ hci::AclManager* acl_manager_;
+ FixedChannelServiceManagerImpl* fixed_channel_service_manager_;
+ DynamicChannelServiceManagerImpl* dynamic_channel_service_manager_;
+ l2cap::internal::ParameterProvider* parameter_provider_;
+
+ // Internal states
+ std::unordered_map<hci::Address, PendingLink> pending_links_;
+ std::unordered_map<hci::Address, Link> links_;
+ std::unordered_map<hci::Address, std::list<Psm>> pending_dynamic_channels_;
+ std::unordered_map<hci::Address, std::list<Link::PendingDynamicChannelConnection>>
+ pending_dynamic_channels_callbacks_;
+ DISALLOW_COPY_AND_ASSIGN(LinkManager);
+};
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/link_manager_test.cc b/gd/l2cap/classic/internal/link_manager_test.cc
new file mode 100644
index 0000000..aa7bfa4
--- /dev/null
+++ b/gd/l2cap/classic/internal/link_manager_test.cc
@@ -0,0 +1,461 @@
+/*
+ * Copyright 2018 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 "l2cap/classic/internal/link_manager.h"
+
+#include <future>
+#include <thread>
+
+#include "common/bind.h"
+#include "common/testing/bind_test_util.h"
+#include "dynamic_channel_service_manager_impl_mock.h"
+#include "hci/acl_manager_mock.h"
+#include "hci/address.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic/fixed_channel_manager.h"
+#include "l2cap/classic/internal/fixed_channel_service_impl_mock.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl_mock.h"
+#include "l2cap/internal/parameter_provider_mock.h"
+#include "os/handler.h"
+#include "os/thread.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+using hci::testing::MockAclConnection;
+using hci::testing::MockAclManager;
+using l2cap::internal::testing::MockParameterProvider;
+using ::testing::_; // Matcher to any value
+using ::testing::ByMove;
+using ::testing::DoAll;
+using testing::MockDynamicChannelServiceManagerImpl;
+using testing::MockFixedChannelServiceImpl;
+using testing::MockFixedChannelServiceManagerImpl;
+using ::testing::Return;
+using ::testing::SaveArg;
+
+constexpr static auto kTestIdleDisconnectTimeoutLong = std::chrono::milliseconds(1000);
+constexpr static auto kTestIdleDisconnectTimeoutShort = std::chrono::milliseconds(30);
+
+class L2capClassicLinkManagerTest : public ::testing::Test {
+ public:
+ static void SyncHandler(os::Handler* handler) {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+ future.wait_for(std::chrono::milliseconds(3));
+ }
+
+ protected:
+ void SetUp() override {
+ thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+ l2cap_handler_ = new os::Handler(thread_);
+ mock_parameter_provider_ = new MockParameterProvider;
+ EXPECT_CALL(*mock_parameter_provider_, GetClassicLinkIdleDisconnectTimeout)
+ .WillRepeatedly(Return(kTestIdleDisconnectTimeoutLong));
+ }
+
+ void TearDown() override {
+ delete mock_parameter_provider_;
+ l2cap_handler_->Clear();
+ delete l2cap_handler_;
+ delete thread_;
+ }
+
+ os::Thread* thread_ = nullptr;
+ os::Handler* l2cap_handler_ = nullptr;
+ MockParameterProvider* mock_parameter_provider_ = nullptr;
+};
+
+TEST_F(L2capClassicLinkManagerTest, connect_fixed_channel_service_without_acl) {
+ MockFixedChannelServiceManagerImpl mock_classic_fixed_channel_service_manager;
+ MockDynamicChannelServiceManagerImpl mock_classic_dynamic_channel_service_manager;
+ MockAclManager mock_acl_manager;
+ hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+
+ // Step 1: Verify callback registration with HCI
+ hci::ConnectionCallbacks* hci_connection_callbacks = nullptr;
+ os::Handler* hci_callback_handler = nullptr;
+ EXPECT_CALL(mock_acl_manager, RegisterCallbacks(_, _))
+ .WillOnce(DoAll(SaveArg<0>(&hci_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+ LinkManager classic_link_manager(l2cap_handler_, &mock_acl_manager, &mock_classic_fixed_channel_service_manager,
+ &mock_classic_dynamic_channel_service_manager, mock_parameter_provider_);
+ EXPECT_EQ(hci_connection_callbacks, &classic_link_manager);
+ EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+ // Register fake services
+ MockFixedChannelServiceImpl mock_service_1, mock_service_2;
+ std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+ results.emplace_back(kSmpBrCid, &mock_service_1);
+ results.emplace_back(kConnectionlessCid, &mock_service_2);
+ EXPECT_CALL(mock_classic_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+ // Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
+ EXPECT_CALL(mock_acl_manager, CreateConnection(device)).Times(1);
+ LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+ .handler_ = user_handler.get(),
+ .on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
+ classic_link_manager.ConnectFixedChannelServices(device, std::move(pending_fixed_channel_connection));
+
+ // Step 3: ACL connection success event should trigger channel creation for all registered services
+
+ std::unique_ptr<MockAclConnection> acl_connection = std::make_unique<MockAclConnection>();
+ EXPECT_CALL(*acl_connection, RegisterDisconnectCallback(_, l2cap_handler_)).Times(1);
+ EXPECT_CALL(*acl_connection, GetAddress()).WillRepeatedly(Return(device));
+ std::unique_ptr<FixedChannel> channel_1, channel_2;
+ EXPECT_CALL(mock_service_1, NotifyChannelCreation(_)).WillOnce([&channel_1](std::unique_ptr<FixedChannel> channel) {
+ channel_1 = std::move(channel);
+ });
+ EXPECT_CALL(mock_service_2, NotifyChannelCreation(_)).WillOnce([&channel_2](std::unique_ptr<FixedChannel> channel) {
+ channel_2 = std::move(channel);
+ });
+ hci_callback_handler->Post(common::BindOnce(&hci::ConnectionCallbacks::OnConnectSuccess,
+ common::Unretained(hci_connection_callbacks), std::move(acl_connection)));
+ SyncHandler(hci_callback_handler);
+ EXPECT_NE(channel_1, nullptr);
+ EXPECT_NE(channel_2, nullptr);
+
+ // Step 4: Calling ConnectServices() to the same device will no trigger another connection attempt
+ FixedChannelManager::ConnectionResult my_result;
+ LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection_2{
+ .handler_ = user_handler.get(),
+ .on_fail_callback_ = common::testing::BindLambdaForTesting(
+ [&my_result](FixedChannelManager::ConnectionResult result) { my_result = result; })};
+ classic_link_manager.ConnectFixedChannelServices(device, std::move(pending_fixed_channel_connection_2));
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(my_result.connection_result_code,
+ FixedChannelManager::ConnectionResultCode::FAIL_ALL_SERVICES_HAVE_CHANNEL);
+
+ // Step 5: Register new service will cause new channels to be created during ConnectServices()
+ MockFixedChannelServiceImpl mock_service_3;
+ results.emplace_back(kSmpBrCid + 1, &mock_service_3);
+ EXPECT_CALL(mock_classic_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+ LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection_3{
+ .handler_ = user_handler.get(),
+ .on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
+ std::unique_ptr<FixedChannel> channel_3;
+ EXPECT_CALL(mock_service_3, NotifyChannelCreation(_)).WillOnce([&channel_3](std::unique_ptr<FixedChannel> channel) {
+ channel_3 = std::move(channel);
+ });
+ classic_link_manager.ConnectFixedChannelServices(device, std::move(pending_fixed_channel_connection_3));
+ EXPECT_NE(channel_3, nullptr);
+
+ user_handler->Clear();
+
+ classic_link_manager.OnDisconnect(device, hci::ErrorCode::SUCCESS);
+}
+
+TEST_F(L2capClassicLinkManagerTest, connect_fixed_channel_service_without_acl_with_no_service) {
+ MockFixedChannelServiceManagerImpl mock_classic_fixed_channel_service_manager;
+ MockAclManager mock_acl_manager;
+ hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+
+ // Step 1: Verify callback registration with HCI
+ hci::ConnectionCallbacks* hci_connection_callbacks = nullptr;
+ os::Handler* hci_callback_handler = nullptr;
+ EXPECT_CALL(mock_acl_manager, RegisterCallbacks(_, _))
+ .WillOnce(DoAll(SaveArg<0>(&hci_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+ LinkManager classic_link_manager(l2cap_handler_, &mock_acl_manager, &mock_classic_fixed_channel_service_manager,
+ nullptr, mock_parameter_provider_);
+ EXPECT_EQ(hci_connection_callbacks, &classic_link_manager);
+ EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+ // Make sure no service is registered
+ std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+ EXPECT_CALL(mock_classic_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+ // Step 2: Connect to fixed channel without any service registered will result in failure
+ EXPECT_CALL(mock_acl_manager, CreateConnection(device)).Times(0);
+ FixedChannelManager::ConnectionResult my_result;
+ LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+ .handler_ = user_handler.get(),
+ .on_fail_callback_ = common::testing::BindLambdaForTesting(
+ [&my_result](FixedChannelManager::ConnectionResult result) { my_result = result; })};
+ classic_link_manager.ConnectFixedChannelServices(device, std::move(pending_fixed_channel_connection));
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(my_result.connection_result_code, FixedChannelManager::ConnectionResultCode::FAIL_NO_SERVICE_REGISTERED);
+
+ user_handler->Clear();
+}
+
+TEST_F(L2capClassicLinkManagerTest, connect_fixed_channel_service_without_acl_with_hci_failure) {
+ MockFixedChannelServiceManagerImpl mock_classic_fixed_channel_service_manager;
+ MockAclManager mock_acl_manager;
+ hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+
+ // Step 1: Verify callback registration with HCI
+ hci::ConnectionCallbacks* hci_connection_callbacks = nullptr;
+ os::Handler* hci_callback_handler = nullptr;
+ EXPECT_CALL(mock_acl_manager, RegisterCallbacks(_, _))
+ .WillOnce(DoAll(SaveArg<0>(&hci_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+ LinkManager classic_link_manager(l2cap_handler_, &mock_acl_manager, &mock_classic_fixed_channel_service_manager,
+ nullptr, mock_parameter_provider_);
+ EXPECT_EQ(hci_connection_callbacks, &classic_link_manager);
+ EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+ // Register fake services
+ MockFixedChannelServiceImpl mock_service_1;
+ std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+ results.emplace_back(kSmpBrCid, &mock_service_1);
+ EXPECT_CALL(mock_classic_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+ // Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
+ EXPECT_CALL(mock_acl_manager, CreateConnection(device)).Times(1);
+ FixedChannelManager::ConnectionResult my_result;
+ LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+ .handler_ = user_handler.get(),
+ .on_fail_callback_ = common::testing::BindLambdaForTesting(
+ [&my_result](FixedChannelManager::ConnectionResult result) { my_result = result; })};
+ classic_link_manager.ConnectFixedChannelServices(device, std::move(pending_fixed_channel_connection));
+
+ // Step 3: ACL connection failure event should trigger connection failure callback
+ EXPECT_CALL(mock_service_1, NotifyChannelCreation(_)).Times(0);
+ hci_callback_handler->Post(common::BindOnce(&hci::ConnectionCallbacks::OnConnectFail,
+ common::Unretained(hci_connection_callbacks), device,
+ hci::ErrorCode::PAGE_TIMEOUT));
+ SyncHandler(hci_callback_handler);
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(my_result.connection_result_code, FixedChannelManager::ConnectionResultCode::FAIL_HCI_ERROR);
+ EXPECT_EQ(my_result.hci_error, hci::ErrorCode::PAGE_TIMEOUT);
+
+ user_handler->Clear();
+}
+
+TEST_F(L2capClassicLinkManagerTest, not_acquiring_channels_should_disconnect_acl_after_timeout) {
+ EXPECT_CALL(*mock_parameter_provider_, GetClassicLinkIdleDisconnectTimeout)
+ .WillRepeatedly(Return(kTestIdleDisconnectTimeoutShort));
+ MockFixedChannelServiceManagerImpl mock_classic_fixed_channel_service_manager;
+ MockAclManager mock_acl_manager;
+ hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+
+ // Step 1: Verify callback registration with HCI
+ hci::ConnectionCallbacks* hci_connection_callbacks = nullptr;
+ os::Handler* hci_callback_handler = nullptr;
+ EXPECT_CALL(mock_acl_manager, RegisterCallbacks(_, _))
+ .WillOnce(DoAll(SaveArg<0>(&hci_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+ LinkManager classic_link_manager(l2cap_handler_, &mock_acl_manager, &mock_classic_fixed_channel_service_manager,
+ nullptr, mock_parameter_provider_);
+ EXPECT_EQ(hci_connection_callbacks, &classic_link_manager);
+ EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+ // Register fake services
+ MockFixedChannelServiceImpl mock_service_1, mock_service_2;
+ std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+ results.emplace_back(kSmpBrCid, &mock_service_1);
+ results.emplace_back(kConnectionlessCid, &mock_service_2);
+ EXPECT_CALL(mock_classic_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+ // Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
+ EXPECT_CALL(mock_acl_manager, CreateConnection(device)).Times(1);
+ LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+ .handler_ = user_handler.get(),
+ .on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
+ classic_link_manager.ConnectFixedChannelServices(device, std::move(pending_fixed_channel_connection));
+
+ // Step 3: ACL connection success event should trigger channel creation for all registered services
+ auto* raw_acl_connection = new MockAclConnection();
+ std::unique_ptr<MockAclConnection> acl_connection(raw_acl_connection);
+ EXPECT_CALL(*acl_connection, GetAddress()).WillRepeatedly(Return(device));
+ std::unique_ptr<FixedChannel> channel_1, channel_2;
+ EXPECT_CALL(mock_service_1, NotifyChannelCreation(_)).WillOnce([&channel_1](std::unique_ptr<FixedChannel> channel) {
+ channel_1 = std::move(channel);
+ });
+ EXPECT_CALL(mock_service_2, NotifyChannelCreation(_)).WillOnce([&channel_2](std::unique_ptr<FixedChannel> channel) {
+ channel_2 = std::move(channel);
+ });
+ hci_callback_handler->Post(common::BindOnce(&hci::ConnectionCallbacks::OnConnectSuccess,
+ common::Unretained(hci_connection_callbacks), std::move(acl_connection)));
+ SyncHandler(hci_callback_handler);
+ EXPECT_NE(channel_1, nullptr);
+ EXPECT_NE(channel_2, nullptr);
+ hci::ErrorCode status_1 = hci::ErrorCode::SUCCESS;
+ channel_1->RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_1 = status; }));
+ hci::ErrorCode status_2 = hci::ErrorCode::SUCCESS;
+ channel_2->RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_2 = status; }));
+
+ // Step 4: Leave channel IDLE long enough, they will disconnect
+ EXPECT_CALL(*raw_acl_connection, Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION)).Times(1);
+ std::this_thread::sleep_for(kTestIdleDisconnectTimeoutShort * 1.2);
+
+ // Step 5: Link disconnect will trigger all callbacks
+ classic_link_manager.OnDisconnect(device, hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST);
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_1);
+ EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_2);
+
+ user_handler->Clear();
+}
+
+TEST_F(L2capClassicLinkManagerTest, acquiring_channels_should_not_disconnect_acl_after_timeout) {
+ EXPECT_CALL(*mock_parameter_provider_, GetClassicLinkIdleDisconnectTimeout)
+ .WillRepeatedly(Return(kTestIdleDisconnectTimeoutShort));
+ MockFixedChannelServiceManagerImpl mock_classic_fixed_channel_service_manager;
+ MockAclManager mock_acl_manager;
+ hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+
+ // Step 1: Verify callback registration with HCI
+ hci::ConnectionCallbacks* hci_connection_callbacks = nullptr;
+ os::Handler* hci_callback_handler = nullptr;
+ EXPECT_CALL(mock_acl_manager, RegisterCallbacks(_, _))
+ .WillOnce(DoAll(SaveArg<0>(&hci_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+ LinkManager classic_link_manager(l2cap_handler_, &mock_acl_manager, &mock_classic_fixed_channel_service_manager,
+ nullptr, mock_parameter_provider_);
+ EXPECT_EQ(hci_connection_callbacks, &classic_link_manager);
+ EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+ // Register fake services
+ MockFixedChannelServiceImpl mock_service_1, mock_service_2;
+ std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+ results.emplace_back(kSmpBrCid, &mock_service_1);
+ results.emplace_back(kConnectionlessCid, &mock_service_2);
+ EXPECT_CALL(mock_classic_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+ // Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
+ EXPECT_CALL(mock_acl_manager, CreateConnection(device)).Times(1);
+ LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+ .handler_ = user_handler.get(),
+ .on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
+ classic_link_manager.ConnectFixedChannelServices(device, std::move(pending_fixed_channel_connection));
+
+ // Step 3: ACL connection success event should trigger channel creation for all registered services
+ auto* raw_acl_connection = new MockAclConnection();
+ std::unique_ptr<MockAclConnection> acl_connection(raw_acl_connection);
+ EXPECT_CALL(*acl_connection, GetAddress()).WillRepeatedly(Return(device));
+ std::unique_ptr<FixedChannel> channel_1, channel_2;
+ EXPECT_CALL(mock_service_1, NotifyChannelCreation(_)).WillOnce([&channel_1](std::unique_ptr<FixedChannel> channel) {
+ channel_1 = std::move(channel);
+ });
+ EXPECT_CALL(mock_service_2, NotifyChannelCreation(_)).WillOnce([&channel_2](std::unique_ptr<FixedChannel> channel) {
+ channel_2 = std::move(channel);
+ });
+ hci_callback_handler->Post(common::BindOnce(&hci::ConnectionCallbacks::OnConnectSuccess,
+ common::Unretained(hci_connection_callbacks), std::move(acl_connection)));
+ SyncHandler(hci_callback_handler);
+ EXPECT_NE(channel_1, nullptr);
+ EXPECT_NE(channel_2, nullptr);
+ hci::ErrorCode status_1 = hci::ErrorCode::SUCCESS;
+ channel_1->RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_1 = status; }));
+ hci::ErrorCode status_2 = hci::ErrorCode::SUCCESS;
+ channel_2->RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_2 = status; }));
+
+ channel_1->Acquire();
+
+ // Step 4: Leave channel IDLE, it won't disconnect to due acquired channel 1
+ EXPECT_CALL(*raw_acl_connection, Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION)).Times(0);
+ std::this_thread::sleep_for(kTestIdleDisconnectTimeoutShort * 2);
+
+ // Step 5: Link disconnect will trigger all callbacks
+ classic_link_manager.OnDisconnect(device, hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST);
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_1);
+ EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_2);
+
+ user_handler->Clear();
+}
+
+TEST_F(L2capClassicLinkManagerTest, acquiring_and_releasing_channels_should_eventually_disconnect_acl) {
+ EXPECT_CALL(*mock_parameter_provider_, GetClassicLinkIdleDisconnectTimeout)
+ .WillRepeatedly(Return(kTestIdleDisconnectTimeoutShort));
+ MockFixedChannelServiceManagerImpl mock_classic_fixed_channel_service_manager;
+ MockAclManager mock_acl_manager;
+ hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+
+ // Step 1: Verify callback registration with HCI
+ hci::ConnectionCallbacks* hci_connection_callbacks = nullptr;
+ os::Handler* hci_callback_handler = nullptr;
+ EXPECT_CALL(mock_acl_manager, RegisterCallbacks(_, _))
+ .WillOnce(DoAll(SaveArg<0>(&hci_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+ LinkManager classic_link_manager(l2cap_handler_, &mock_acl_manager, &mock_classic_fixed_channel_service_manager,
+ nullptr, mock_parameter_provider_);
+ EXPECT_EQ(hci_connection_callbacks, &classic_link_manager);
+ EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+ // Register fake services
+ MockFixedChannelServiceImpl mock_service_1, mock_service_2;
+ std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+ results.emplace_back(kSmpBrCid, &mock_service_1);
+ results.emplace_back(kConnectionlessCid, &mock_service_2);
+ EXPECT_CALL(mock_classic_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+ // Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
+ EXPECT_CALL(mock_acl_manager, CreateConnection(device)).Times(1);
+ LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+ .handler_ = user_handler.get(),
+ .on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
+ classic_link_manager.ConnectFixedChannelServices(device, std::move(pending_fixed_channel_connection));
+
+ // Step 3: ACL connection success event should trigger channel creation for all registered services
+ auto* raw_acl_connection = new MockAclConnection();
+ std::unique_ptr<MockAclConnection> acl_connection(raw_acl_connection);
+ EXPECT_CALL(*acl_connection, GetAddress()).WillRepeatedly(Return(device));
+ std::unique_ptr<FixedChannel> channel_1, channel_2;
+ EXPECT_CALL(mock_service_1, NotifyChannelCreation(_)).WillOnce([&channel_1](std::unique_ptr<FixedChannel> channel) {
+ channel_1 = std::move(channel);
+ });
+ EXPECT_CALL(mock_service_2, NotifyChannelCreation(_)).WillOnce([&channel_2](std::unique_ptr<FixedChannel> channel) {
+ channel_2 = std::move(channel);
+ });
+ hci_callback_handler->Post(common::BindOnce(&hci::ConnectionCallbacks::OnConnectSuccess,
+ common::Unretained(hci_connection_callbacks), std::move(acl_connection)));
+ SyncHandler(hci_callback_handler);
+ EXPECT_NE(channel_1, nullptr);
+ EXPECT_NE(channel_2, nullptr);
+ hci::ErrorCode status_1 = hci::ErrorCode::SUCCESS;
+ channel_1->RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_1 = status; }));
+ hci::ErrorCode status_2 = hci::ErrorCode::SUCCESS;
+ channel_2->RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_2 = status; }));
+
+ channel_1->Acquire();
+
+ // Step 4: Leave channel IDLE, it won't disconnect to due acquired channel 1
+ EXPECT_CALL(*raw_acl_connection, Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION)).Times(0);
+ std::this_thread::sleep_for(kTestIdleDisconnectTimeoutShort * 2);
+
+ // Step 5: Leave channel IDLE long enough, they will disconnect
+ channel_1->Release();
+ EXPECT_CALL(*raw_acl_connection, Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION)).Times(1);
+ std::this_thread::sleep_for(kTestIdleDisconnectTimeoutShort * 1.2);
+
+ // Step 6: Link disconnect will trigger all callbacks
+ classic_link_manager.OnDisconnect(device, hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST);
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_1);
+ EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_2);
+
+ user_handler->Clear();
+}
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/link_mock.h b/gd/l2cap/classic/internal/link_mock.h
new file mode 100644
index 0000000..cbbad15
--- /dev/null
+++ b/gd/l2cap/classic/internal/link_mock.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include "hci/acl_manager_mock.h"
+#include "hci/address.h"
+#include "l2cap/classic/internal/link.h"
+#include "l2cap/internal/scheduler_mock.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+namespace testing {
+
+using hci::testing::MockAclConnection;
+
+class MockLink : public Link {
+ public:
+ explicit MockLink(os::Handler* handler, l2cap::internal::ParameterProvider* parameter_provider)
+ : Link(handler, std::make_unique<MockAclConnection>(), parameter_provider, nullptr, nullptr){};
+ explicit MockLink(os::Handler* handler, l2cap::internal::ParameterProvider* parameter_provider,
+ std::unique_ptr<hci::AclConnection> acl_connection)
+ : Link(handler, std::move(acl_connection), parameter_provider, nullptr, nullptr){};
+ MOCK_METHOD(hci::Address, GetDevice, (), (override));
+ MOCK_METHOD(void, OnAclDisconnected, (hci::ErrorCode status), (override));
+ MOCK_METHOD(void, Disconnect, (), (override));
+ MOCK_METHOD(std::shared_ptr<DynamicChannelImpl>, AllocateDynamicChannel,
+ (Psm psm, Cid cid, SecurityPolicy security_policy), (override));
+ MOCK_METHOD(bool, IsFixedChannelAllocated, (Cid cid), (override));
+ MOCK_METHOD(void, RefreshRefCount, (), (override));
+};
+
+} // namespace testing
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/classic/internal/signalling_manager.cc b/gd/l2cap/classic/internal/signalling_manager.cc
new file mode 100644
index 0000000..7398c17
--- /dev/null
+++ b/gd/l2cap/classic/internal/signalling_manager.cc
@@ -0,0 +1,656 @@
+/*
+ * Copyright 2019 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 "l2cap/classic/internal/signalling_manager.h"
+
+#include <chrono>
+
+#include "common/bind.h"
+#include "l2cap/classic/internal/link.h"
+#include "l2cap/l2cap_packets.h"
+#include "os/log.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+static constexpr auto kTimeout = std::chrono::seconds(3);
+
+ClassicSignallingManager::ClassicSignallingManager(os::Handler* handler, Link* link,
+ DynamicChannelServiceManagerImpl* dynamic_service_manager,
+ DynamicChannelAllocator* channel_allocator,
+ FixedChannelServiceManagerImpl* fixed_service_manager)
+ : handler_(handler), link_(link), dynamic_service_manager_(dynamic_service_manager),
+ channel_allocator_(channel_allocator), fixed_service_manager_(fixed_service_manager), alarm_(handler) {
+ ASSERT(handler_ != nullptr);
+ ASSERT(link_ != nullptr);
+ signalling_channel_ = link_->AllocateFixedChannel(kClassicSignallingCid, {});
+ signalling_channel_->GetQueueUpEnd()->RegisterDequeue(
+ handler_, common::Bind(&ClassicSignallingManager::on_incoming_packet, common::Unretained(this)));
+ enqueue_buffer_ =
+ std::make_unique<os::EnqueueBuffer<packet::BasePacketBuilder>>(signalling_channel_->GetQueueUpEnd());
+}
+
+ClassicSignallingManager::~ClassicSignallingManager() {
+ enqueue_buffer_.reset();
+ signalling_channel_->GetQueueUpEnd()->UnregisterDequeue();
+ signalling_channel_ = nullptr;
+}
+
+void ClassicSignallingManager::OnCommandReject(CommandRejectView command_reject_view) {
+ if (pending_commands_.empty()) {
+ LOG_WARN("Unexpected command reject: no pending request");
+ return;
+ }
+ auto last_sent_command = std::move(pending_commands_.front());
+ pending_commands_.pop();
+
+ SignalId signal_id = command_reject_view.GetIdentifier();
+ if (last_sent_command.signal_id_ != signal_id) {
+ LOG_WARN("Unknown command reject");
+ return;
+ }
+ handle_send_next_command();
+
+ LOG_INFO("Command rejected");
+}
+
+void ClassicSignallingManager::SendConnectionRequest(Psm psm, Cid local_cid) {
+ PendingCommand pending_command = {next_signal_id_, CommandCode::CONNECTION_REQUEST, psm, local_cid, {}, {}, {}};
+ next_signal_id_++;
+ pending_commands_.push(std::move(pending_command));
+ if (pending_commands_.size() == 1) {
+ handle_send_next_command();
+ }
+}
+
+void ClassicSignallingManager::SendConfigurationRequest(Cid remote_cid,
+ std::vector<std::unique_ptr<ConfigurationOption>> config) {
+ PendingCommand pending_command = {next_signal_id_, CommandCode::CONFIGURATION_REQUEST, {}, {}, remote_cid, {},
+ std::move(config)};
+ next_signal_id_++;
+ pending_commands_.push(std::move(pending_command));
+ if (pending_commands_.size() == 1) {
+ handle_send_next_command();
+ }
+}
+
+void ClassicSignallingManager::SendDisconnectionRequest(Cid local_cid, Cid remote_cid) {
+ PendingCommand pending_command = {
+ next_signal_id_, CommandCode::DISCONNECTION_REQUEST, {}, local_cid, remote_cid, {}, {}};
+ next_signal_id_++;
+ pending_commands_.push(std::move(pending_command));
+ if (pending_commands_.size() == 1) {
+ handle_send_next_command();
+ }
+}
+
+void ClassicSignallingManager::SendInformationRequest(InformationRequestInfoType type) {
+ PendingCommand pending_command = {next_signal_id_, CommandCode::INFORMATION_REQUEST, {}, {}, {}, type, {}};
+ next_signal_id_++;
+ pending_commands_.push(std::move(pending_command));
+ if (pending_commands_.size() == 1) {
+ handle_send_next_command();
+ }
+}
+
+void ClassicSignallingManager::SendEchoRequest(std::unique_ptr<packet::RawBuilder> payload) {
+ LOG_WARN("Not supported");
+}
+
+void ClassicSignallingManager::OnConnectionRequest(SignalId signal_id, Psm psm, Cid remote_cid) {
+ if (!IsPsmValid(psm)) {
+ LOG_WARN("Invalid psm received from remote psm:%d remote_cid:%d", psm, remote_cid);
+ send_connection_response(signal_id, remote_cid, kInvalidCid, ConnectionResponseResult::PSM_NOT_SUPPORTED,
+ ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
+ return;
+ }
+
+ if (remote_cid == kInvalidCid) {
+ LOG_WARN("Invalid remote cid received from remote psm:%d remote_cid:%d", psm, remote_cid);
+ send_connection_response(signal_id, remote_cid, kInvalidCid, ConnectionResponseResult::INVALID_CID,
+ ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
+ return;
+ }
+ if (channel_allocator_->IsPsmUsed(psm)) {
+ LOG_WARN("Psm already exists");
+ send_connection_response(signal_id, remote_cid, kInvalidCid, ConnectionResponseResult::PSM_NOT_SUPPORTED,
+ ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
+ return;
+ }
+
+ if (!dynamic_service_manager_->IsServiceRegistered(psm)) {
+ LOG_INFO("Service for this psm (%d) is not registered", psm);
+ send_connection_response(signal_id, remote_cid, kInvalidCid, ConnectionResponseResult::PSM_NOT_SUPPORTED,
+ ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
+ return;
+ }
+
+ auto new_channel = link_->AllocateDynamicChannel(psm, remote_cid, {});
+ if (new_channel == nullptr) {
+ LOG_WARN("Can't allocate dynamic channel");
+ return;
+ }
+ send_connection_response(signal_id, remote_cid, new_channel->GetCid(), ConnectionResponseResult::SUCCESS,
+ ConnectionResponseStatus::NO_FURTHER_INFORMATION_AVAILABLE);
+ auto* service = dynamic_service_manager_->GetService(psm);
+ auto initial_config = service->GetConfigOption();
+ if (!link_->GetRemoteSupportsErtm()) {
+ initial_config.channel_mode = DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC;
+ }
+ auto mtu_configuration = std::make_unique<MtuConfigurationOption>();
+ mtu_configuration->mtu_ = initial_config.incoming_mtu;
+ auto fcs_option = std::make_unique<FrameCheckSequenceOption>();
+ fcs_option->fcs_type_ = FcsType::NO_FCS;
+ auto retransmission_flow_control_configuration = std::make_unique<RetransmissionAndFlowControlConfigurationOption>();
+ switch (initial_config.channel_mode) {
+ case DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC:
+ retransmission_flow_control_configuration->mode_ = RetransmissionAndFlowControlModeOption::L2CAP_BASIC;
+ break;
+ case DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::ENHANCED_RETRANSMISSION:
+ retransmission_flow_control_configuration->mode_ =
+ RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION;
+ // TODO: Decide where to put initial values
+ retransmission_flow_control_configuration->tx_window_size_ = 10;
+ retransmission_flow_control_configuration->max_transmit_ = 20;
+ retransmission_flow_control_configuration->retransmission_time_out_ = 2000;
+ retransmission_flow_control_configuration->monitor_time_out_ = 12000;
+ retransmission_flow_control_configuration->maximum_pdu_size_ = 1010;
+ break;
+ }
+
+ new_channel->SetRetransmissionFlowControlConfig(*retransmission_flow_control_configuration);
+ new_channel->SetIncomingMtu(initial_config.incoming_mtu);
+ std::vector<std::unique_ptr<ConfigurationOption>> config;
+ config.emplace_back(std::move(mtu_configuration));
+ config.emplace_back(std::move(retransmission_flow_control_configuration));
+ config.emplace_back(std::move(fcs_option));
+ SendConfigurationRequest(remote_cid, std::move(config));
+}
+
+void ClassicSignallingManager::OnConnectionResponse(SignalId signal_id, Cid remote_cid, Cid cid,
+ ConnectionResponseResult result, ConnectionResponseStatus status) {
+ if (pending_commands_.empty()) {
+ LOG_WARN("Unexpected response: no pending request");
+ return;
+ }
+ auto last_sent_command = std::move(pending_commands_.front());
+ pending_commands_.pop();
+ if (last_sent_command.signal_id_ != signal_id || last_sent_command.command_code_ != CommandCode::CONNECTION_REQUEST) {
+ LOG_WARN("Received unexpected connection response");
+ return;
+ }
+ if (last_sent_command.source_cid_ != cid) {
+ LOG_WARN("SCID doesn't match: expected %d, received %d", last_sent_command.source_cid_, cid);
+ handle_send_next_command();
+ return;
+ }
+ if (result != ConnectionResponseResult::SUCCESS) {
+ handle_send_next_command();
+ return;
+ }
+ Psm pending_psm = last_sent_command.psm_;
+ auto new_channel = link_->AllocateReservedDynamicChannel(cid, pending_psm, remote_cid, {});
+ if (new_channel == nullptr) {
+ LOG_WARN("Can't allocate dynamic channel");
+ handle_send_next_command();
+ return;
+ }
+ alarm_.Cancel();
+ auto initial_config = link_->GetConfigurationForInitialConfiguration(new_channel->GetCid());
+ if (!link_->GetRemoteSupportsErtm()) {
+ initial_config.channel_mode = DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC;
+ }
+ auto mtu_configuration = std::make_unique<MtuConfigurationOption>();
+ mtu_configuration->mtu_ = initial_config.incoming_mtu;
+ auto retransmission_flow_control_configuration = std::make_unique<RetransmissionAndFlowControlConfigurationOption>();
+ switch (initial_config.channel_mode) {
+ case DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC:
+ retransmission_flow_control_configuration->mode_ = RetransmissionAndFlowControlModeOption::L2CAP_BASIC;
+ break;
+ case DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::ENHANCED_RETRANSMISSION:
+ retransmission_flow_control_configuration->mode_ =
+ RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION;
+ // TODO: Decide where to put initial values
+ retransmission_flow_control_configuration->tx_window_size_ = 10;
+ retransmission_flow_control_configuration->max_transmit_ = 20;
+ retransmission_flow_control_configuration->retransmission_time_out_ = 2000;
+ retransmission_flow_control_configuration->monitor_time_out_ = 12000;
+ retransmission_flow_control_configuration->maximum_pdu_size_ = 1010;
+ break;
+ }
+ std::vector<std::unique_ptr<ConfigurationOption>> config;
+ config.emplace_back(std::move(mtu_configuration));
+ if (initial_config.channel_mode != DynamicChannelConfigurationOption::RetransmissionAndFlowControlMode::L2CAP_BASIC) {
+ config.emplace_back(std::move(retransmission_flow_control_configuration));
+ }
+ SendConfigurationRequest(remote_cid, {});
+}
+
+void ClassicSignallingManager::OnConfigurationRequest(SignalId signal_id, Cid cid, Continuation is_continuation,
+ std::vector<std::unique_ptr<ConfigurationOption>> options) {
+ auto channel = channel_allocator_->FindChannelByCid(cid);
+ if (channel == nullptr) {
+ LOG_WARN("Configuration request for an unknown channel");
+ return;
+ }
+
+ for (auto& option : options) {
+ switch (option->type_) {
+ case ConfigurationOptionType::MTU: {
+ channel->SetIncomingMtu(MtuConfigurationOption::Specialize(option.get())->mtu_);
+ break;
+ }
+ case ConfigurationOptionType::FLUSH_TIMEOUT: {
+ // TODO: Handle this configuration option
+ break;
+ }
+ case ConfigurationOptionType::RETRANSMISSION_AND_FLOW_CONTROL: {
+ auto config = RetransmissionAndFlowControlConfigurationOption::Specialize(option.get());
+ channel->SetRetransmissionFlowControlConfig(*config);
+ break;
+ }
+ case ConfigurationOptionType::FRAME_CHECK_SEQUENCE: {
+ channel->SetFcsType(FrameCheckSequenceOption::Specialize(option.get())->fcs_type_);
+ break;
+ }
+ default:
+ LOG_WARN("Received some unsupported configuration option: %d", static_cast<int>(option->type_));
+ auto response =
+ ConfigurationResponseBuilder::Create(signal_id.Value(), channel->GetRemoteCid(), is_continuation,
+ ConfigurationResponseResult::UNKNOWN_OPTIONS, {});
+ enqueue_buffer_->Enqueue(std::move(response), handler_);
+ return;
+ }
+ }
+
+ auto response = ConfigurationResponseBuilder::Create(signal_id.Value(), channel->GetRemoteCid(), is_continuation,
+ ConfigurationResponseResult::SUCCESS, {});
+ enqueue_buffer_->Enqueue(std::move(response), handler_);
+ channel->SetIncomingConfigurationStatus(DynamicChannelImpl::ConfigurationStatus::CONFIGURED);
+ if (channel->GetOutgoingConfigurationStatus() == DynamicChannelImpl::ConfigurationStatus::CONFIGURED) {
+ std::unique_ptr<DynamicChannel> user_channel = std::make_unique<DynamicChannel>(channel, handler_);
+ if (channel->local_initiated_) {
+ link_->NotifyChannelCreation(cid, std::move(user_channel));
+ } else {
+ dynamic_service_manager_->GetService(channel->GetPsm())->NotifyChannelCreation(std::move(user_channel));
+ }
+ }
+}
+
+void ClassicSignallingManager::OnConfigurationResponse(SignalId signal_id, Cid cid, Continuation is_continuation,
+ ConfigurationResponseResult result,
+ std::vector<std::unique_ptr<ConfigurationOption>> options) {
+ if (pending_commands_.empty()) {
+ LOG_WARN("Unexpected response: no pending request");
+ return;
+ }
+
+ auto last_sent_command = std::move(pending_commands_.front());
+ pending_commands_.pop();
+
+ auto channel = channel_allocator_->FindChannelByCid(cid);
+ if (channel == nullptr) {
+ LOG_WARN("Configuration request for an unknown channel");
+ handle_send_next_command();
+ return;
+ }
+
+ channel->SetOutgoingConfigurationStatus(DynamicChannelImpl::ConfigurationStatus::CONFIGURED);
+ if (channel->GetIncomingConfigurationStatus() == DynamicChannelImpl::ConfigurationStatus::CONFIGURED) {
+ std::unique_ptr<DynamicChannel> user_channel = std::make_unique<DynamicChannel>(channel, handler_);
+ if (channel->local_initiated_) {
+ link_->NotifyChannelCreation(cid, std::move(user_channel));
+ } else {
+ dynamic_service_manager_->GetService(channel->GetPsm())->NotifyChannelCreation(std::move(user_channel));
+ }
+ }
+ alarm_.Cancel();
+ handle_send_next_command();
+}
+
+void ClassicSignallingManager::OnDisconnectionRequest(SignalId signal_id, Cid cid, Cid remote_cid) {
+ // TODO: check cid match
+ auto channel = channel_allocator_->FindChannelByCid(cid);
+ if (channel == nullptr) {
+ LOG_WARN("Disconnect request for an unknown channel");
+ return;
+ }
+ auto builder = DisconnectionResponseBuilder::Create(signal_id.Value(), cid, remote_cid);
+ enqueue_buffer_->Enqueue(std::move(builder), handler_);
+ channel->OnClosed(hci::ErrorCode::SUCCESS);
+ link_->FreeDynamicChannel(cid);
+ handle_send_next_command();
+}
+
+void ClassicSignallingManager::OnDisconnectionResponse(SignalId signal_id, Cid remote_cid, Cid cid) {
+ if (pending_commands_.empty()) {
+ LOG_WARN("Unexpected response: no pending request");
+ return;
+ }
+ auto last_sent_command = std::move(pending_commands_.front());
+ pending_commands_.pop();
+ alarm_.Cancel();
+
+ if (last_sent_command.signal_id_ != signal_id ||
+ last_sent_command.command_code_ != CommandCode::DISCONNECTION_REQUEST) {
+ return;
+ }
+
+ auto channel = channel_allocator_->FindChannelByCid(cid);
+ if (channel == nullptr) {
+ LOG_WARN("Disconnect response for an unknown channel");
+ handle_send_next_command();
+ return;
+ }
+
+ channel->OnClosed(hci::ErrorCode::SUCCESS);
+ link_->FreeDynamicChannel(cid);
+ handle_send_next_command();
+}
+
+void ClassicSignallingManager::OnEchoRequest(SignalId signal_id, const PacketView<kLittleEndian>& packet) {
+ std::vector<uint8_t> packet_vector{packet.begin(), packet.end()};
+ auto raw_builder = std::make_unique<packet::RawBuilder>();
+ raw_builder->AddOctets(packet_vector);
+ auto builder = EchoResponseBuilder::Create(signal_id.Value(), std::move(raw_builder));
+ enqueue_buffer_->Enqueue(std::move(builder), handler_);
+ handle_send_next_command();
+}
+
+void ClassicSignallingManager::OnEchoResponse(SignalId signal_id, const PacketView<kLittleEndian>& packet) {
+ if (pending_commands_.empty()) {
+ LOG_WARN("Unexpected response: no pending request");
+ return;
+ }
+ auto last_sent_command = std::move(pending_commands_.front());
+ pending_commands_.pop();
+
+ if (last_sent_command.signal_id_ != signal_id || last_sent_command.command_code_ != CommandCode::ECHO_REQUEST) {
+ return;
+ }
+ LOG_INFO("Echo response received");
+ alarm_.Cancel();
+ handle_send_next_command();
+}
+
+void ClassicSignallingManager::OnInformationRequest(SignalId signal_id, InformationRequestInfoType type) {
+ switch (type) {
+ case InformationRequestInfoType::CONNECTIONLESS_MTU: {
+ auto response = InformationResponseConnectionlessMtuBuilder::Create(
+ signal_id.Value(), InformationRequestResult::SUCCESS, kDefaultClassicMtu);
+ enqueue_buffer_->Enqueue(std::move(response), handler_);
+ break;
+ }
+ case InformationRequestInfoType::EXTENDED_FEATURES_SUPPORTED: {
+ // TODO: implement this response
+ auto response = InformationResponseExtendedFeaturesBuilder::Create(
+ signal_id.Value(), InformationRequestResult::SUCCESS, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0);
+ enqueue_buffer_->Enqueue(std::move(response), handler_);
+ break;
+ }
+ case InformationRequestInfoType::FIXED_CHANNELS_SUPPORTED: {
+ auto response = InformationResponseFixedChannelsBuilder::Create(
+ signal_id.Value(), InformationRequestResult::SUCCESS, fixed_service_manager_->GetSupportedFixedChannelMask());
+ enqueue_buffer_->Enqueue(std::move(response), handler_);
+ break;
+ }
+ }
+}
+
+void ClassicSignallingManager::OnInformationResponse(SignalId signal_id, const InformationResponseView& response) {
+ if (pending_commands_.empty()) {
+ LOG_WARN("Unexpected response: no pending request");
+ return;
+ }
+ auto last_sent_command = std::move(pending_commands_.front());
+ pending_commands_.pop();
+
+ if (last_sent_command.signal_id_ != signal_id ||
+ last_sent_command.command_code_ != CommandCode::INFORMATION_REQUEST) {
+ return;
+ }
+
+ auto type = response.GetInfoType();
+ switch (type) {
+ case InformationRequestInfoType::CONNECTIONLESS_MTU: {
+ auto view = InformationResponseConnectionlessMtuView::Create(response);
+ if (!view.IsValid()) {
+ LOG_WARN("Invalid InformationResponseConnectionlessMtu received");
+ return;
+ }
+ link_->SetRemoteConnectionlessMtu(view.GetConnectionlessMtu());
+ break;
+ }
+ case InformationRequestInfoType::EXTENDED_FEATURES_SUPPORTED: {
+ auto view = InformationResponseExtendedFeaturesView::Create(response);
+ if (!view.IsValid()) {
+ LOG_WARN("Invalid InformationResponseExtendedFeatures received");
+ return;
+ }
+ link_->SetRemoteSupportsErtm((view.GetEnhancedRetransmissionMode()));
+ link_->SetRemoteSupportsFcs(view.GetFcsOption());
+ // We don't care about other parameters
+ break;
+ }
+ case InformationRequestInfoType::FIXED_CHANNELS_SUPPORTED: {
+ auto view = InformationResponseFixedChannelsView::Create(response);
+ if (!view.IsValid()) {
+ LOG_WARN("Invalid InformationResponseFixedChannel received");
+ return;
+ }
+ // We don't use fixed channels (connectionless or BR/EDR security) for now so we don't care
+ break;
+ }
+ }
+
+ alarm_.Cancel();
+ handle_send_next_command();
+}
+
+void ClassicSignallingManager::on_incoming_packet() {
+ auto packet = signalling_channel_->GetQueueUpEnd()->TryDequeue();
+ ControlView control_packet_view = ControlView::Create(*packet);
+ if (!control_packet_view.IsValid()) {
+ LOG_WARN("Invalid signalling packet received");
+ return;
+ }
+ auto code = control_packet_view.GetCode();
+ switch (code) {
+ case CommandCode::COMMAND_REJECT: {
+ CommandRejectView command_reject_view = CommandRejectView::Create(control_packet_view);
+ if (!command_reject_view.IsValid()) {
+ return;
+ }
+ OnCommandReject(command_reject_view);
+ return;
+ }
+ case CommandCode::CONNECTION_REQUEST: {
+ ConnectionRequestView connection_request_view = ConnectionRequestView::Create(control_packet_view);
+ if (!connection_request_view.IsValid()) {
+ return;
+ }
+ OnConnectionRequest(control_packet_view.GetIdentifier(), connection_request_view.GetPsm(),
+ connection_request_view.GetSourceCid());
+ return;
+ }
+ case CommandCode::CONNECTION_RESPONSE: {
+ ConnectionResponseView connection_response_view = ConnectionResponseView::Create(control_packet_view);
+ if (!connection_response_view.IsValid()) {
+ return;
+ }
+ OnConnectionResponse(connection_response_view.GetIdentifier(), connection_response_view.GetDestinationCid(),
+ connection_response_view.GetSourceCid(), connection_response_view.GetResult(),
+ connection_response_view.GetStatus());
+ return;
+ }
+ case CommandCode::CONFIGURATION_REQUEST: {
+ ConfigurationRequestView configuration_request_view = ConfigurationRequestView::Create(control_packet_view);
+ if (!configuration_request_view.IsValid()) {
+ return;
+ }
+ OnConfigurationRequest(configuration_request_view.GetIdentifier(), configuration_request_view.GetDestinationCid(),
+ configuration_request_view.GetContinuation(), configuration_request_view.GetConfig());
+ return;
+ }
+ case CommandCode::CONFIGURATION_RESPONSE: {
+ ConfigurationResponseView configuration_response_view = ConfigurationResponseView::Create(control_packet_view);
+ if (!configuration_response_view.IsValid()) {
+ return;
+ }
+ OnConfigurationResponse(configuration_response_view.GetIdentifier(), configuration_response_view.GetSourceCid(),
+ configuration_response_view.GetContinuation(), configuration_response_view.GetResult(),
+ configuration_response_view.GetConfig());
+ return;
+ }
+ case CommandCode::DISCONNECTION_REQUEST: {
+ DisconnectionRequestView disconnection_request_view = DisconnectionRequestView::Create(control_packet_view);
+ if (!disconnection_request_view.IsValid()) {
+ return;
+ }
+ OnDisconnectionRequest(disconnection_request_view.GetIdentifier(), disconnection_request_view.GetDestinationCid(),
+ disconnection_request_view.GetSourceCid());
+ return;
+ }
+ case CommandCode::DISCONNECTION_RESPONSE: {
+ DisconnectionResponseView disconnection_response_view = DisconnectionResponseView::Create(control_packet_view);
+ if (!disconnection_response_view.IsValid()) {
+ return;
+ }
+ OnDisconnectionResponse(disconnection_response_view.GetIdentifier(),
+ disconnection_response_view.GetDestinationCid(),
+ disconnection_response_view.GetSourceCid());
+ return;
+ }
+ case CommandCode::ECHO_REQUEST: {
+ EchoRequestView echo_request_view = EchoRequestView::Create(control_packet_view);
+ if (!echo_request_view.IsValid()) {
+ return;
+ }
+ OnEchoRequest(echo_request_view.GetIdentifier(), echo_request_view.GetPayload());
+ return;
+ }
+ case CommandCode::ECHO_RESPONSE: {
+ EchoResponseView echo_response_view = EchoResponseView::Create(control_packet_view);
+ if (!echo_response_view.IsValid()) {
+ return;
+ }
+ OnEchoResponse(echo_response_view.GetIdentifier(), echo_response_view.GetPayload());
+ return;
+ }
+ case CommandCode::INFORMATION_REQUEST: {
+ InformationRequestView information_request_view = InformationRequestView::Create(control_packet_view);
+ if (!information_request_view.IsValid()) {
+ return;
+ }
+ OnInformationRequest(information_request_view.GetIdentifier(), information_request_view.GetInfoType());
+ return;
+ }
+ case CommandCode::INFORMATION_RESPONSE: {
+ InformationResponseView information_response_view = InformationResponseView::Create(control_packet_view);
+ if (!information_response_view.IsValid()) {
+ return;
+ }
+ OnInformationResponse(information_response_view.GetIdentifier(), information_response_view);
+ return;
+ }
+ default:
+ LOG_WARN("Unhandled event 0x%x", static_cast<int>(code));
+ auto builder = CommandRejectNotUnderstoodBuilder::Create(control_packet_view.GetIdentifier());
+ enqueue_buffer_->Enqueue(std::move(builder), handler_);
+ return;
+ }
+}
+
+void ClassicSignallingManager::send_connection_response(SignalId signal_id, Cid remote_cid, Cid local_cid,
+ ConnectionResponseResult result,
+ ConnectionResponseStatus status) {
+ auto builder = ConnectionResponseBuilder::Create(signal_id.Value(), local_cid, remote_cid, result, status);
+ enqueue_buffer_->Enqueue(std::move(builder), handler_);
+}
+
+void ClassicSignallingManager::on_command_timeout() {
+ LOG_WARN("Response time out");
+ if (pending_commands_.empty()) {
+ LOG_ERROR("No pending command");
+ return;
+ }
+
+ auto last_sent_command = std::move(pending_commands_.front());
+ pending_commands_.pop();
+ switch (last_sent_command.command_code_) {
+ case CommandCode::CONFIGURATION_REQUEST: {
+ SendDisconnectionRequest(last_sent_command.source_cid_, last_sent_command.destination_cid_);
+ break;
+ }
+ default:
+ break;
+ }
+ handle_send_next_command();
+}
+
+void ClassicSignallingManager::handle_send_next_command() {
+ if (pending_commands_.empty()) {
+ return;
+ }
+ auto& last_sent_command = pending_commands_.front();
+
+ auto signal_id = last_sent_command.signal_id_;
+ auto psm = last_sent_command.psm_;
+ auto source_cid = last_sent_command.source_cid_;
+ auto destination_cid = last_sent_command.destination_cid_;
+ auto info_type = last_sent_command.info_type_;
+ auto config = std::move(last_sent_command.config_);
+ switch (last_sent_command.command_code_) {
+ case CommandCode::CONNECTION_REQUEST: {
+ auto builder = ConnectionRequestBuilder::Create(signal_id.Value(), psm, source_cid);
+ enqueue_buffer_->Enqueue(std::move(builder), handler_);
+ alarm_.Schedule(common::BindOnce(&ClassicSignallingManager::on_command_timeout, common::Unretained(this)),
+ kTimeout);
+ break;
+ }
+ case CommandCode::CONFIGURATION_REQUEST: {
+ auto builder =
+ ConfigurationRequestBuilder::Create(signal_id.Value(), destination_cid, Continuation::END, std::move(config));
+ enqueue_buffer_->Enqueue(std::move(builder), handler_);
+ alarm_.Schedule(common::BindOnce(&ClassicSignallingManager::on_command_timeout, common::Unretained(this)),
+ kTimeout);
+ break;
+ }
+ case CommandCode::DISCONNECTION_REQUEST: {
+ auto builder = DisconnectionRequestBuilder::Create(signal_id.Value(), destination_cid, source_cid);
+ enqueue_buffer_->Enqueue(std::move(builder), handler_);
+ alarm_.Schedule(common::BindOnce(&ClassicSignallingManager::on_command_timeout, common::Unretained(this)),
+ kTimeout);
+ break;
+ }
+ case CommandCode::INFORMATION_REQUEST: {
+ auto builder = InformationRequestBuilder::Create(signal_id.Value(), info_type);
+ enqueue_buffer_->Enqueue(std::move(builder), handler_);
+ alarm_.Schedule(common::BindOnce(&ClassicSignallingManager::on_command_timeout, common::Unretained(this)),
+ kTimeout);
+ break;
+ }
+ default:
+ LOG_WARN("Unsupported command code 0x%x", static_cast<int>(last_sent_command.command_code_));
+ }
+}
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/signalling_manager.h b/gd/l2cap/classic/internal/signalling_manager.h
new file mode 100644
index 0000000..0e17ec7
--- /dev/null
+++ b/gd/l2cap/classic/internal/signalling_manager.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <queue>
+#include <vector>
+
+#include "l2cap/cid.h"
+#include "l2cap/classic/internal/dynamic_channel_allocator.h"
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
+#include "l2cap/classic/internal/fixed_channel_impl.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
+#include "l2cap/l2cap_packets.h"
+#include "l2cap/psm.h"
+#include "l2cap/signal_id.h"
+#include "os/alarm.h"
+#include "os/handler.h"
+#include "os/queue.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+
+struct PendingCommand {
+ SignalId signal_id_;
+ CommandCode command_code_;
+ Psm psm_;
+ Cid source_cid_;
+ Cid destination_cid_;
+ InformationRequestInfoType info_type_;
+ std::vector<std::unique_ptr<ConfigurationOption>> config_;
+};
+
+class Link;
+
+class ClassicSignallingManager {
+ public:
+ ClassicSignallingManager(os::Handler* handler, Link* link,
+ classic::internal::DynamicChannelServiceManagerImpl* dynamic_service_manager,
+ classic::internal::DynamicChannelAllocator* channel_allocator,
+ classic::internal::FixedChannelServiceManagerImpl* fixed_service_manager);
+
+ virtual ~ClassicSignallingManager();
+
+ void OnCommandReject(CommandRejectView command_reject_view);
+
+ void SendConnectionRequest(Psm psm, Cid local_cid);
+
+ void SendConfigurationRequest(Cid remote_cid, std::vector<std::unique_ptr<ConfigurationOption>> config);
+
+ void SendDisconnectionRequest(Cid local_cid, Cid remote_cid);
+
+ void SendInformationRequest(InformationRequestInfoType type);
+
+ void SendEchoRequest(std::unique_ptr<packet::RawBuilder> payload);
+
+ void OnConnectionRequest(SignalId signal_id, Psm psm, Cid remote_cid);
+
+ void OnConnectionResponse(SignalId signal_id, Cid remote_cid, Cid cid, ConnectionResponseResult result,
+ ConnectionResponseStatus status);
+
+ void OnDisconnectionRequest(SignalId signal_id, Cid cid, Cid remote_cid);
+
+ void OnDisconnectionResponse(SignalId signal_id, Cid cid, Cid remote_cid);
+
+ void OnConfigurationRequest(SignalId signal_id, Cid cid, Continuation is_continuation,
+ std::vector<std::unique_ptr<ConfigurationOption>>);
+
+ void OnConfigurationResponse(SignalId signal_id, Cid cid, Continuation is_continuation,
+ ConfigurationResponseResult result, std::vector<std::unique_ptr<ConfigurationOption>>);
+
+ void OnEchoRequest(SignalId signal_id, const PacketView<kLittleEndian>& packet);
+
+ void OnEchoResponse(SignalId signal_id, const PacketView<kLittleEndian>& packet);
+
+ void OnInformationRequest(SignalId signal_id, InformationRequestInfoType type);
+
+ void OnInformationResponse(SignalId signal_id, const InformationResponseView& response);
+
+ private:
+ void on_incoming_packet();
+ void send_connection_response(SignalId signal_id, Cid remote_cid, Cid local_cid, ConnectionResponseResult result,
+ ConnectionResponseStatus status);
+ void on_command_timeout();
+ void handle_send_next_command();
+
+ os::Handler* handler_;
+ Link* link_;
+ std::shared_ptr<classic::internal::FixedChannelImpl> signalling_channel_;
+ DynamicChannelServiceManagerImpl* dynamic_service_manager_;
+ DynamicChannelAllocator* channel_allocator_;
+ FixedChannelServiceManagerImpl* fixed_service_manager_;
+ std::unique_ptr<os::EnqueueBuffer<packet::BasePacketBuilder>> enqueue_buffer_;
+ PendingCommand last_sent_command_;
+ std::queue<PendingCommand> pending_commands_;
+ os::Alarm alarm_;
+ SignalId next_signal_id_ = kInitialSignalId;
+};
+
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/internal/signalling_manager_test.cc b/gd/l2cap/classic/internal/signalling_manager_test.cc
new file mode 100644
index 0000000..a89b445
--- /dev/null
+++ b/gd/l2cap/classic/internal/signalling_manager_test.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2019 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 "l2cap/classic/internal/signalling_manager.h"
+
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl_mock.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl_mock.h"
+#include "l2cap/classic/internal/link_mock.h"
+#include "l2cap/internal/parameter_provider_mock.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+using ::testing::_;
+using ::testing::Return;
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace internal {
+namespace {
+
+class L2capClassicSignallingManagerTest : public ::testing::Test {
+ public:
+ static void SyncHandler(os::Handler* handler) {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+ future.wait_for(std::chrono::milliseconds(3));
+ }
+
+ protected:
+ void SetUp() override {
+ thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+ l2cap_handler_ = new os::Handler(thread_);
+ }
+
+ void TearDown() override {
+ l2cap_handler_->Clear();
+ delete l2cap_handler_;
+ delete thread_;
+ }
+
+ os::Thread* thread_ = nullptr;
+ os::Handler* l2cap_handler_ = nullptr;
+};
+
+TEST_F(L2capClassicSignallingManagerTest, precondition) {}
+
+} // namespace
+} // namespace internal
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/l2cap_classic_module.cc b/gd/l2cap/classic/l2cap_classic_module.cc
new file mode 100644
index 0000000..ca5a0d5
--- /dev/null
+++ b/gd/l2cap/classic/l2cap_classic_module.cc
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2019 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.
+ */
+#define LOG_TAG "l2cap2"
+
+#include <memory>
+
+#include "common/bidi_queue.h"
+#include "hci/acl_manager.h"
+#include "hci/address.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "l2cap/classic/internal/dynamic_channel_service_manager_impl.h"
+#include "l2cap/classic/internal/fixed_channel_service_manager_impl.h"
+#include "l2cap/classic/internal/link_manager.h"
+#include "l2cap/internal/parameter_provider.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+#include "l2cap/classic/l2cap_classic_module.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+const ModuleFactory L2capClassicModule::Factory = ModuleFactory([]() { return new L2capClassicModule(); });
+
+struct L2capClassicModule::impl {
+ impl(os::Handler* l2cap_handler, hci::AclManager* acl_manager)
+ : l2cap_handler_(l2cap_handler), acl_manager_(acl_manager) {}
+ os::Handler* l2cap_handler_;
+ hci::AclManager* acl_manager_;
+ l2cap::internal::ParameterProvider parameter_provider_;
+ internal::FixedChannelServiceManagerImpl fixed_channel_service_manager_impl_{l2cap_handler_};
+ internal::DynamicChannelServiceManagerImpl dynamic_channel_service_manager_impl_{l2cap_handler_};
+ internal::LinkManager link_manager_{l2cap_handler_, acl_manager_, &fixed_channel_service_manager_impl_,
+ &dynamic_channel_service_manager_impl_, ¶meter_provider_};
+};
+
+L2capClassicModule::L2capClassicModule() {}
+
+L2capClassicModule::~L2capClassicModule() {}
+
+void L2capClassicModule::ListDependencies(ModuleList* list) {
+ list->add<hci::AclManager>();
+}
+
+void L2capClassicModule::Start() {
+ pimpl_ = std::make_unique<impl>(GetHandler(), GetDependency<hci::AclManager>());
+}
+
+void L2capClassicModule::Stop() {
+ pimpl_.reset();
+}
+
+std::string L2capClassicModule::ToString() const {
+ return "L2cap Classic Module";
+}
+
+std::unique_ptr<FixedChannelManager> L2capClassicModule::GetFixedChannelManager() {
+ return std::unique_ptr<FixedChannelManager>(new FixedChannelManager(&pimpl_->fixed_channel_service_manager_impl_,
+ &pimpl_->link_manager_, pimpl_->l2cap_handler_));
+}
+
+std::unique_ptr<DynamicChannelManager> L2capClassicModule::GetDynamicChannelManager() {
+ return std::unique_ptr<DynamicChannelManager>(new DynamicChannelManager(
+ &pimpl_->dynamic_channel_service_manager_impl_, &pimpl_->link_manager_, pimpl_->l2cap_handler_));
+}
+
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/l2cap_classic_module.h b/gd/l2cap/classic/l2cap_classic_module.h
new file mode 100644
index 0000000..388cae2
--- /dev/null
+++ b/gd/l2cap/classic/l2cap_classic_module.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <memory>
+
+#include "l2cap/classic/dynamic_channel_manager.h"
+#include "l2cap/classic/fixed_channel_manager.h"
+#include "module.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+
+class L2capClassicModule : public bluetooth::Module {
+ public:
+ L2capClassicModule();
+ virtual ~L2capClassicModule();
+
+ /**
+ * Get the api to the classic fixed channel l2cap module
+ */
+ virtual std::unique_ptr<FixedChannelManager> GetFixedChannelManager();
+
+ /**
+ * Get the api to the classic dynamic channel l2cap module
+ */
+ virtual std::unique_ptr<DynamicChannelManager> GetDynamicChannelManager();
+
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override;
+
+ void Start() override;
+
+ void Stop() override;
+
+ std::string ToString() const override;
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+ DISALLOW_COPY_AND_ASSIGN(L2capClassicModule);
+};
+
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/classic/l2cap_classic_module_mock.h b/gd/l2cap/classic/l2cap_classic_module_mock.h
new file mode 100644
index 0000000..1252854
--- /dev/null
+++ b/gd/l2cap/classic/l2cap_classic_module_mock.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include "l2cap/classic/l2cap_classic_module.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace classic {
+namespace testing {
+
+class MockL2capClassicModule : public L2capClassicModule {
+ public:
+ MOCK_METHOD(std::unique_ptr<FixedChannelManager>, GetFixedChannelManager, (), (override));
+ MOCK_METHOD(std::unique_ptr<DynamicChannelManager>, GetDynamicChannelManager, (), (override));
+};
+
+} // namespace testing
+} // namespace classic
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/fcs.cc b/gd/l2cap/fcs.cc
new file mode 100644
index 0000000..3ad78cc
--- /dev/null
+++ b/gd/l2cap/fcs.cc
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019 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 "l2cap/fcs.h"
+
+namespace {
+// Table for optimizing the CRC calculation, which is a bitwise operation.
+static const uint16_t crctab[256] = {
+ 0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241, 0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1,
+ 0xc481, 0x0440, 0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40, 0x0a00, 0xcac1, 0xcb81, 0x0b40,
+ 0xc901, 0x09c0, 0x0880, 0xc841, 0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40, 0x1e00, 0xdec1,
+ 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41, 0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
+ 0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040, 0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1,
+ 0xf281, 0x3240, 0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441, 0x3c00, 0xfcc1, 0xfd81, 0x3d40,
+ 0xff01, 0x3fc0, 0x3e80, 0xfe41, 0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840, 0x2800, 0xe8c1,
+ 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41, 0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
+ 0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640, 0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0,
+ 0x2080, 0xe041, 0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240, 0x6600, 0xa6c1, 0xa781, 0x6740,
+ 0xa501, 0x65c0, 0x6480, 0xa441, 0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41, 0xaa01, 0x6ac0,
+ 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840, 0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
+ 0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40, 0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1,
+ 0xb681, 0x7640, 0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041, 0x5000, 0x90c1, 0x9181, 0x5140,
+ 0x9301, 0x53c0, 0x5280, 0x9241, 0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440, 0x9c01, 0x5cc0,
+ 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40, 0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
+ 0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40, 0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0,
+ 0x4c80, 0x8c41, 0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641, 0x8201, 0x42c0, 0x4380, 0x8341,
+ 0x4100, 0x81c1, 0x8081, 0x4040,
+};
+} // namespace
+
+namespace bluetooth {
+namespace l2cap {
+
+void Fcs::Initialize() {
+ crc = 0;
+}
+
+void Fcs::AddByte(uint8_t byte) {
+ crc = ((crc >> 8) & 0x00ff) ^ crctab[(crc & 0x00ff) ^ byte];
+}
+
+uint16_t Fcs::GetChecksum() const {
+ return crc;
+}
+
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/fcs.h b/gd/l2cap/fcs.h
new file mode 100644
index 0000000..127fa9d
--- /dev/null
+++ b/gd/l2cap/fcs.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+namespace bluetooth {
+namespace l2cap {
+
+// Frame Check Sequence from the L2CAP spec.
+class Fcs {
+ public:
+ void Initialize();
+
+ void AddByte(uint8_t byte);
+
+ uint16_t GetChecksum() const;
+
+ private:
+ uint16_t crc;
+};
+
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/basic_mode_channel_data_controller.cc b/gd/l2cap/internal/basic_mode_channel_data_controller.cc
new file mode 100644
index 0000000..3575e25
--- /dev/null
+++ b/gd/l2cap/internal/basic_mode_channel_data_controller.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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 "l2cap/internal/basic_mode_channel_data_controller.h"
+
+#include "l2cap/l2cap_packets.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+BasicModeDataController::BasicModeDataController(Cid cid, Cid remote_cid, UpperQueueDownEnd* channel_queue_end,
+ os::Handler* handler, Scheduler* scheduler)
+ : cid_(cid), remote_cid_(remote_cid), enqueue_buffer_(channel_queue_end), handler_(handler), scheduler_(scheduler) {
+}
+
+void BasicModeDataController::OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) {
+ auto l2cap_information = BasicFrameBuilder::Create(remote_cid_, std::move(sdu));
+ pdu_queue_.emplace(std::move(l2cap_information));
+ scheduler_->OnPacketsReady(cid_, 1);
+}
+
+void BasicModeDataController::OnPdu(packet::PacketView<true> pdu) {
+ auto basic_frame_view = BasicFrameView::Create(pdu);
+ if (!basic_frame_view.IsValid()) {
+ return;
+ }
+ enqueue_buffer_.Enqueue(std::make_unique<PacketView<kLittleEndian>>(basic_frame_view.GetPayload()), handler_);
+}
+
+std::unique_ptr<packet::BasePacketBuilder> BasicModeDataController::GetNextPacket() {
+ auto next = std::move(pdu_queue_.front());
+ pdu_queue_.pop();
+ return next;
+}
+
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/basic_mode_channel_data_controller.h b/gd/l2cap/internal/basic_mode_channel_data_controller.h
new file mode 100644
index 0000000..8e40402
--- /dev/null
+++ b/gd/l2cap/internal/basic_mode_channel_data_controller.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <unordered_map>
+#include <utility>
+
+#include "common/bidi_queue.h"
+#include "l2cap/cid.h"
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/internal/data_controller.h"
+#include "l2cap/internal/scheduler.h"
+#include "l2cap/l2cap_packets.h"
+#include "l2cap/mtu.h"
+#include "os/handler.h"
+#include "os/queue.h"
+#include "packet/base_packet_builder.h"
+#include "packet/packet_view.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+class BasicModeDataController : public DataController {
+ public:
+ using UpperEnqueue = packet::PacketView<packet::kLittleEndian>;
+ using UpperDequeue = packet::BasePacketBuilder;
+ using UpperQueueDownEnd = common::BidiQueueEnd<UpperEnqueue, UpperDequeue>;
+ BasicModeDataController(Cid cid, Cid remote_cid, UpperQueueDownEnd* channel_queue_end, os::Handler* handler,
+ Scheduler* scheduler);
+
+ void OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) override;
+
+ void OnPdu(packet::PacketView<true> pdu) override;
+
+ std::unique_ptr<packet::BasePacketBuilder> GetNextPacket() override;
+
+ void EnableFcs(bool enabled) override {}
+ void SetRetransmissionAndFlowControlOptions(const RetransmissionAndFlowControlConfigurationOption& option) override {}
+
+ private:
+ Cid cid_;
+ Cid remote_cid_;
+ os::EnqueueBuffer<UpperEnqueue> enqueue_buffer_;
+ os::Handler* handler_;
+ std::queue<std::unique_ptr<packet::BasePacketBuilder>> pdu_queue_;
+ Scheduler* scheduler_;
+};
+
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/basic_mode_channel_data_controller_test.cc b/gd/l2cap/internal/basic_mode_channel_data_controller_test.cc
new file mode 100644
index 0000000..c4cc56d
--- /dev/null
+++ b/gd/l2cap/internal/basic_mode_channel_data_controller_test.cc
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2019 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 "l2cap/internal/basic_mode_channel_data_controller.h"
+
+#include <gtest/gtest.h>
+
+#include "l2cap/internal/scheduler_mock.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+namespace {
+
+std::unique_ptr<packet::BasePacketBuilder> CreateSdu(std::vector<uint8_t> payload) {
+ auto raw_builder = std::make_unique<packet::RawBuilder>();
+ raw_builder->AddOctets(payload);
+ return raw_builder;
+}
+
+PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+ auto bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter i(*bytes);
+ bytes->reserve(packet->size());
+ packet->Serialize(i);
+ return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+void sync_handler(os::Handler* handler) {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+ auto status = future.wait_for(std::chrono::milliseconds(300));
+ EXPECT_EQ(status, std::future_status::ready);
+}
+
+class BasicModeDataControllerTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+ user_handler_ = new os::Handler(thread_);
+ queue_handler_ = new os::Handler(thread_);
+ }
+
+ void TearDown() override {
+ queue_handler_->Clear();
+ user_handler_->Clear();
+ delete queue_handler_;
+ delete user_handler_;
+ delete thread_;
+ }
+
+ os::Thread* thread_ = nullptr;
+ os::Handler* user_handler_ = nullptr;
+ os::Handler* queue_handler_ = nullptr;
+};
+
+TEST_F(BasicModeDataControllerTest, transmit) {
+ common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10};
+ testing::MockScheduler scheduler;
+ BasicModeDataController controller{1, 1, channel_queue.GetDownEnd(), queue_handler_, &scheduler};
+ EXPECT_CALL(scheduler, OnPacketsReady(1, 1));
+ controller.OnSdu(CreateSdu({'a', 'b', 'c', 'd'}));
+ auto next_packet = controller.GetNextPacket();
+ EXPECT_NE(next_packet, nullptr);
+ auto view = GetPacketView(std::move(next_packet));
+ auto pdu_view = BasicFrameView::Create(view);
+ EXPECT_TRUE(pdu_view.IsValid());
+ auto payload = pdu_view.GetPayload();
+ std::string data = std::string(payload.begin(), payload.end());
+ EXPECT_EQ(data, "abcd");
+}
+
+TEST_F(BasicModeDataControllerTest, receive) {
+ common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10};
+ testing::MockScheduler scheduler;
+ BasicModeDataController controller{1, 1, channel_queue.GetDownEnd(), queue_handler_, &scheduler};
+ auto base_view = GetPacketView(BasicFrameBuilder::Create(1, CreateSdu({'a', 'b', 'c', 'd'})));
+ controller.OnPdu(base_view);
+ sync_handler(queue_handler_);
+ auto packet_view = channel_queue.GetUpEnd()->TryDequeue();
+ EXPECT_NE(packet_view, nullptr);
+ std::string data = std::string(packet_view->begin(), packet_view->end());
+ EXPECT_EQ(data, "abcd");
+}
+
+} // namespace
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/channel_impl.h b/gd/l2cap/internal/channel_impl.h
new file mode 100644
index 0000000..ae17660
--- /dev/null
+++ b/gd/l2cap/internal/channel_impl.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "common/bidi_queue.h"
+#include "l2cap/cid.h"
+#include "l2cap/l2cap_packets.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+class Sender;
+
+/**
+ * Common interface for internal channel implementation
+ */
+class ChannelImpl {
+ public:
+ virtual ~ChannelImpl() = default;
+
+ /**
+ * Return the queue end for upper layer (L2CAP user)
+ */
+ virtual common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>*
+ GetQueueUpEnd() = 0;
+
+ /**
+ * Return the queue end for lower layer (sender and receiver)
+ */
+ virtual common::BidiQueueEnd<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>*
+ GetQueueDownEnd() = 0;
+
+ virtual Cid GetCid() const = 0;
+
+ virtual Cid GetRemoteCid() const = 0;
+
+ /**
+ * Callback from the Scheduler to notify the Sender for this channel. On config update, channel might notify the
+ * configuration change to Sender.
+ * Fixed channel doesn't need to implement it, as it doesn't need to send config update to Sender.
+ */
+ virtual void SetSender(l2cap::internal::Sender* sender) = 0;
+};
+
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/channel_impl_mock.h b/gd/l2cap/internal/channel_impl_mock.h
new file mode 100644
index 0000000..710e69a
--- /dev/null
+++ b/gd/l2cap/internal/channel_impl_mock.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "l2cap/internal/channel_impl.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+namespace testing {
+
+class MockChannelImpl : public ChannelImpl {
+ public:
+ MOCK_METHOD((common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>*),
+ GetQueueUpEnd, (), (override));
+ MOCK_METHOD((common::BidiQueueEnd<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>*),
+ GetQueueDownEnd, (), (override));
+ MOCK_METHOD(Cid, GetCid, (), (const, override));
+ MOCK_METHOD(Cid, GetRemoteCid, (), (const, override));
+ MOCK_METHOD(void, SetSender, (l2cap::internal::Sender*), (override));
+};
+
+} // namespace testing
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/data_controller.h b/gd/l2cap/internal/data_controller.h
new file mode 100644
index 0000000..bc7c2e5
--- /dev/null
+++ b/gd/l2cap/internal/data_controller.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include "l2cap/l2cap_packets.h"
+#include "packet/base_packet_builder.h"
+#include "packet/packet_view.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+class DataController {
+ public:
+ virtual ~DataController() = default;
+
+ // SDU -> PDUs and notify Scheduler
+ virtual void OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) = 0;
+
+ // PDUs -> SDU and enqueue to channel queue end
+ virtual void OnPdu(packet::PacketView<true> pdu) = 0;
+
+ // Used by Scheduler to get next PDU
+ virtual std::unique_ptr<packet::BasePacketBuilder> GetNextPacket() = 0;
+
+ // Set FCS mode. This only applies to some modes (ERTM).
+ virtual void EnableFcs(bool enabled) = 0;
+
+ // Set retransmission and flow control. Ignore the mode option because each DataController only handles one mode.
+ // This only applies to some modes (ERTM).
+ virtual void SetRetransmissionAndFlowControlOptions(
+ const RetransmissionAndFlowControlConfigurationOption& option) = 0;
+};
+
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/data_controller_mock.h b/gd/l2cap/internal/data_controller_mock.h
new file mode 100644
index 0000000..d071c68
--- /dev/null
+++ b/gd/l2cap/internal/data_controller_mock.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "l2cap/internal/data_controller.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+namespace testing {
+
+class MockDataController : public DataController {
+ public:
+ MOCK_METHOD(void, OnSdu, (std::unique_ptr<packet::BasePacketBuilder>), (override));
+ MOCK_METHOD(void, OnPdu, (packet::PacketView<true>), (override));
+ MOCK_METHOD(std::unique_ptr<packet::BasePacketBuilder>, GetNextPacket, (), (override));
+ MOCK_METHOD(void, EnableFcs, (bool), (override));
+ MOCK_METHOD(void, SetRetransmissionAndFlowControlOptions, (const RetransmissionAndFlowControlConfigurationOption&),
+ (override));
+};
+
+} // namespace testing
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/data_pipeline_manager.cc b/gd/l2cap/internal/data_pipeline_manager.cc
new file mode 100644
index 0000000..d0023c0
--- /dev/null
+++ b/gd/l2cap/internal/data_pipeline_manager.cc
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2019 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 <unordered_map>
+
+#include "l2cap/cid.h"
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/internal/data_controller.h"
+#include "l2cap/internal/data_pipeline_manager.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+void DataPipelineManager::AttachChannel(Cid cid, std::shared_ptr<ChannelImpl> channel) {
+ ASSERT(sender_map_.find(cid) == sender_map_.end());
+ sender_map_.emplace(std::piecewise_construct, std::forward_as_tuple(cid),
+ std::forward_as_tuple(handler_, scheduler_.get(), channel));
+ if (channel->GetCid() >= kFirstDynamicChannel) {
+ channel->SetSender(&sender_map_.find(cid)->second);
+ }
+}
+
+void DataPipelineManager::DetachChannel(Cid cid) {
+ ASSERT(sender_map_.find(cid) != sender_map_.end());
+ sender_map_.erase(cid);
+}
+
+DataController* DataPipelineManager::GetDataController(Cid cid) {
+ ASSERT(sender_map_.find(cid) != sender_map_.end());
+ return sender_map_.find(cid)->second.GetDataController();
+}
+
+void DataPipelineManager::OnPacketSent(Cid cid) {
+ ASSERT(sender_map_.find(cid) != sender_map_.end());
+ sender_map_.find(cid)->second.OnPacketSent();
+}
+
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/data_pipeline_manager.h b/gd/l2cap/internal/data_pipeline_manager.h
new file mode 100644
index 0000000..f801297
--- /dev/null
+++ b/gd/l2cap/internal/data_pipeline_manager.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <string>
+#include <unordered_map>
+
+#include "common/bidi_queue.h"
+#include "common/bind.h"
+#include "data_controller.h"
+#include "l2cap/cid.h"
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/internal/receiver.h"
+#include "l2cap/internal/scheduler.h"
+#include "l2cap/internal/scheduler_fifo.h"
+#include "l2cap/l2cap_packets.h"
+#include "l2cap/mtu.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "os/queue.h"
+#include "packet/base_packet_builder.h"
+#include "packet/packet_view.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+/**
+ * Manages data pipeline from channel queue end to link queue end, per link.
+ * Contains a Scheduler and Receiver per link.
+ * Contains a Sender and its corrsponding DataController per attached channel.
+ */
+class DataPipelineManager {
+ public:
+ using UpperEnqueue = packet::PacketView<packet::kLittleEndian>;
+ using UpperDequeue = packet::BasePacketBuilder;
+ using UpperQueueDownEnd = common::BidiQueueEnd<UpperEnqueue, UpperDequeue>;
+ using LowerEnqueue = UpperDequeue;
+ using LowerDequeue = UpperEnqueue;
+ using LowerQueueUpEnd = common::BidiQueueEnd<LowerEnqueue, LowerDequeue>;
+
+ DataPipelineManager(os::Handler* handler, LowerQueueUpEnd* link_queue_up_end)
+ : handler_(handler), scheduler_(std::make_unique<Fifo>(this, link_queue_up_end, handler)),
+ receiver_(link_queue_up_end, handler, this) {}
+
+ virtual void AttachChannel(Cid cid, std::shared_ptr<ChannelImpl> channel);
+ virtual void DetachChannel(Cid cid);
+ virtual DataController* GetDataController(Cid cid);
+ virtual void OnPacketSent(Cid cid);
+ virtual ~DataPipelineManager() = default;
+
+ private:
+ os::Handler* handler_;
+ std::unique_ptr<Scheduler> scheduler_;
+ Receiver receiver_;
+ std::unordered_map<Cid, Sender> sender_map_;
+};
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/data_pipeline_manager_mock.h b/gd/l2cap/internal/data_pipeline_manager_mock.h
new file mode 100644
index 0000000..f5a24f4
--- /dev/null
+++ b/gd/l2cap/internal/data_pipeline_manager_mock.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "l2cap/internal/data_pipeline_manager.h"
+
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/internal/data_controller.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+namespace testing {
+
+class MockDataPipelineManager : public DataPipelineManager {
+ public:
+ MockDataPipelineManager(os::Handler* handler, LowerQueueUpEnd* link_queue_up_end)
+ : DataPipelineManager(handler, link_queue_up_end) {}
+ MOCK_METHOD(void, AttachChannel, (Cid, std::shared_ptr<ChannelImpl>), (override));
+ MOCK_METHOD(void, DetachChannel, (Cid), (override));
+ MOCK_METHOD(DataController*, GetDataController, (Cid), (override));
+ MOCK_METHOD(void, OnPacketSent, (Cid), (override));
+};
+
+} // namespace testing
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.cc b/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.cc
new file mode 100644
index 0000000..97f9702
--- /dev/null
+++ b/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.cc
@@ -0,0 +1,1021 @@
+/*
+ * Copyright 2019 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 "l2cap/internal/enhanced_retransmission_mode_channel_data_controller.h"
+
+#include <map>
+#include <queue>
+#include <vector>
+
+#include "common/bind.h"
+#include "os/alarm.h"
+#include "packet/fragmenting_inserter.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+ErtmController::ErtmController(Cid cid, Cid remote_cid, UpperQueueDownEnd* channel_queue_end, os::Handler* handler,
+ Scheduler* scheduler)
+ : cid_(cid), remote_cid_(remote_cid), enqueue_buffer_(channel_queue_end), handler_(handler), scheduler_(scheduler),
+ pimpl_(std::make_unique<impl>(this, handler)) {}
+
+ErtmController::~ErtmController() = default;
+
+struct ErtmController::impl {
+ impl(ErtmController* controller, os::Handler* handler)
+ : controller_(controller), handler_(handler), retrans_timer_(handler), monitor_timer_(handler) {}
+
+ ErtmController* controller_;
+ os::Handler* handler_;
+
+ // We don't support extended window
+ static constexpr uint8_t kMaxTxWin = 64;
+
+ // We don't support sending SREJ
+ static constexpr bool kSendSrej = false;
+
+ // States (@see 8.6.5.2): Transmitter state and receiver state
+
+ enum class TxState {
+ XMIT,
+ WAIT_F,
+ };
+ TxState tx_state_ = TxState::XMIT;
+
+ enum class RxState {
+ RECV,
+ REJ_SENT,
+ SREJ_SENT,
+ };
+ RxState rx_state_ = RxState::RECV;
+
+ // Variables and Timers (@see 8.6.5.3)
+
+ uint8_t tx_seq_ = 0;
+ uint8_t next_tx_seq_ = 0;
+ uint8_t expected_ack_seq_ = 0;
+ uint8_t req_seq_ = 0;
+ uint8_t expected_tx_seq_ = 0;
+ uint8_t buffer_seq_ = 0;
+
+ bool remote_busy_ = false;
+ bool local_busy_ = false;
+ int unacked_frames_ = 0;
+ // TODO: Instead of having a map, we may consider about a better data structure
+ // Map from TxSeq to (SAR, SDU size for START packet, information payload)
+ std::map<uint8_t, std::tuple<SegmentationAndReassembly, uint16_t, std::shared_ptr<packet::RawBuilder>>> unacked_list_;
+ // Stores (SAR, SDU size for START packet, information payload)
+ std::queue<std::tuple<SegmentationAndReassembly, uint16_t, std::unique_ptr<packet::RawBuilder>>> pending_frames_;
+ int retry_count_ = 0;
+ std::map<uint8_t /* tx_seq, */, int /* count */> retry_i_frames_;
+ bool rnr_sent_ = false;
+ bool rej_actioned_ = false;
+ bool srej_actioned_ = false;
+ uint16_t srej_save_req_seq_ = 0;
+ bool send_rej_ = false;
+ int buffer_seq_srej_ = 0;
+ int frames_sent_ = 0;
+ os::Alarm retrans_timer_;
+ os::Alarm monitor_timer_;
+
+ // Events (@see 8.6.5.4)
+
+ void data_request(SegmentationAndReassembly sar, std::unique_ptr<packet::RawBuilder> pdu, uint16_t sdu_size = 0) {
+ // Note: sdu_size only applies to START packet
+ if (tx_state_ == TxState::XMIT && !remote_busy() && rem_window_not_full()) {
+ send_data(sar, sdu_size, std::move(pdu));
+ } else if (tx_state_ == TxState::XMIT && (remote_busy() || rem_window_full())) {
+ pend_data(sar, sdu_size, std::move(pdu));
+ } else if (tx_state_ == TxState::WAIT_F) {
+ pend_data(sar, sdu_size, std::move(pdu));
+ }
+ }
+
+ void local_busy_detected() {
+ local_busy_ = true;
+ }
+
+ void local_busy_clear() {
+ if (tx_state_ == TxState::XMIT && rnr_sent()) {
+ local_busy_ = false;
+ rnr_sent_ = false;
+ send_rr(Poll::POLL);
+ retry_count_ = 1;
+ stop_retrans_timer();
+ start_monitor_timer();
+ } else if (tx_state_ == TxState::XMIT) {
+ local_busy_ = false;
+ rnr_sent_ = false;
+ }
+ }
+
+ void recv_req_seq_and_f_bit(uint8_t req_seq, Final f) {
+ if (tx_state_ == TxState::XMIT) {
+ process_req_seq(req_seq);
+ } else if (f == Final::POLL_RESPONSE) {
+ process_req_seq(req_seq);
+ stop_monitor_timer();
+ if (unacked_frames_ > 0) {
+ start_retrans_timer();
+ }
+ tx_state_ = TxState::XMIT;
+ } else {
+ process_req_seq(req_seq);
+ }
+ }
+
+ void recv_f_bit(Final f) {
+ if (tx_state_ == TxState::WAIT_F && f == Final::POLL_RESPONSE) {
+ stop_monitor_timer();
+ if (unacked_frames_ > 0) {
+ start_retrans_timer();
+ }
+ tx_state_ = TxState::XMIT;
+ }
+ }
+
+ void retrans_timer_expires() {
+ if (tx_state_ == TxState::XMIT) {
+ send_rr_or_rnr(Poll::POLL);
+ // send rr or rnr(p=1)
+ retry_count_ = 1;
+ start_retrans_timer();
+ tx_state_ = TxState::WAIT_F;
+ }
+ }
+
+ void monitor_timer_expires() {
+ if (tx_state_ == TxState::WAIT_F && retry_count_less_than_max_transmit()) {
+ retry_count_++;
+ send_rr_or_rnr(Poll::POLL);
+ start_monitor_timer();
+ } else if (tx_state_ == TxState::WAIT_F) {
+ CloseChannel();
+ }
+ }
+
+ void recv_i_frame(Final f, uint8_t tx_seq, uint8_t req_seq, SegmentationAndReassembly sar, uint16_t sdu_size,
+ const packet::PacketView<true>& payload) {
+ if (rx_state_ == RxState::RECV) {
+ if (f == Final::NOT_SET && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f) &&
+ !local_busy()) {
+ increment_expected_tx_seq();
+ pass_to_tx(req_seq, f);
+ data_indication(sar, sdu_size, payload);
+ send_ack(Final::NOT_SET);
+ } else if (f == Final::POLL_RESPONSE && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) &&
+ with_valid_f_bit(f) && !local_busy()) {
+ increment_expected_tx_seq();
+ pass_to_tx(req_seq, f);
+ data_indication(sar, sdu_size, payload);
+ if (!rej_actioned_) {
+ retransmit_i_frames(req_seq);
+ send_pending_i_frames();
+ } else {
+ rej_actioned_ = false;
+ }
+ send_ack(Final::NOT_SET);
+ } else if (with_duplicate_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f) && !local_busy()) {
+ pass_to_tx(req_seq, f);
+ } else if (with_unexpected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f) &&
+ !local_busy()) {
+ if constexpr (kSendSrej) {
+ // We don't support sending SREJ
+ } else {
+ pass_to_tx(req_seq, f);
+ send_rej();
+ rx_state_ = RxState::REJ_SENT;
+ }
+ } else if (with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f) && local_busy()) {
+ pass_to_tx(req_seq, f);
+ store_or_ignore();
+ } else if (with_valid_req_seq(req_seq) && not_with_expected_tx_seq(tx_seq) && with_valid_f_bit(f) &&
+ local_busy()) {
+ pass_to_tx(req_seq, f);
+ } else if ((with_invalid_tx_seq(tx_seq) && controller_->local_tx_window_ > kMaxTxWin / 2) ||
+ with_invalid_req_seq(req_seq)) {
+ CloseChannel();
+ } else if (with_invalid_tx_seq(tx_seq) && controller_->local_tx_window_ <= kMaxTxWin / 2) {
+ // We decided to ignore
+ }
+ } else if (rx_state_ == RxState::REJ_SENT) {
+ if (f == Final::NOT_SET && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+ increment_expected_tx_seq();
+ pass_to_tx(req_seq, f);
+ data_indication(sar, sdu_size, payload);
+ send_ack(Final::NOT_SET);
+ rx_state_ = RxState::RECV;
+ } else if (f == Final::POLL_RESPONSE && with_expected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) &&
+ with_valid_f_bit(f)) {
+ increment_expected_tx_seq();
+ pass_to_tx(req_seq, f);
+ data_indication(sar, sdu_size, payload);
+ if (!rej_actioned_) {
+ retransmit_i_frames(req_seq);
+ send_pending_i_frames();
+ } else {
+ rej_actioned_ = false;
+ }
+ send_ack(Final::NOT_SET);
+ rx_state_ = RxState::RECV;
+ } else if (with_unexpected_tx_seq(tx_seq) && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+ pass_to_tx(req_seq, f);
+ }
+ } else if (rx_state_ == RxState::SREJ_SENT) {
+ // SREJ NOT SUPPORTED
+ }
+ }
+
+ void recv_rr(uint8_t req_seq, Poll p = Poll::NOT_SET, Final f = Final::NOT_SET) {
+ if (rx_state_ == RxState::RECV) {
+ if (p == Poll::NOT_SET && f == Final::NOT_SET && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+ pass_to_tx(req_seq, f);
+ if (remote_busy() && unacked_frames_ > 0) {
+ start_retrans_timer();
+ }
+ remote_busy_ = false;
+ send_pending_i_frames();
+ } else if (f == Final::POLL_RESPONSE && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+ remote_busy_ = false;
+ pass_to_tx(req_seq, f);
+ if (!rej_actioned_) {
+ retransmit_i_frames(req_seq, p);
+ } else {
+ rej_actioned_ = false;
+ }
+ send_pending_i_frames();
+ } else if (p == Poll::POLL && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+ pass_to_tx(req_seq, f);
+ send_i_or_rr_or_rnr(Final::POLL_RESPONSE);
+ } else if (with_invalid_req_seq(req_seq)) {
+ CloseChannel();
+ }
+ } else if (rx_state_ == RxState::REJ_SENT) {
+ if (f == Final::POLL_RESPONSE && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+ remote_busy_ = false;
+ pass_to_tx(req_seq, f);
+ if (!rej_actioned_) {
+ retransmit_i_frames(req_seq, p);
+ } else {
+ rej_actioned_ = false;
+ }
+ send_pending_i_frames();
+ } else if (p == Poll::NOT_SET && f == Final::NOT_SET && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+ pass_to_tx(req_seq, f);
+ if (remote_busy() and unacked_frames_ > 0) {
+ start_retrans_timer();
+ }
+ remote_busy_ = false;
+ send_ack(Final::NOT_SET);
+ } else if (p == Poll::POLL && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+ pass_to_tx(req_seq, f);
+ if (remote_busy() and unacked_frames_ > 0) {
+ start_retrans_timer();
+ }
+ remote_busy_ = false;
+ send_rr(Final::POLL_RESPONSE);
+ } else if (with_invalid_req_seq(req_seq)) {
+ CloseChannel();
+ }
+ } else if (rx_state_ == RxState::SREJ_SENT) {
+ // SREJ NOT SUPPORTED
+ }
+ }
+
+ void recv_rej(uint8_t req_seq, Poll p = Poll::NOT_SET, Final f = Final::NOT_SET) {
+ if (rx_state_ == RxState::RECV) {
+ if (f == Final::NOT_SET && with_valid_req_seq_retrans(req_seq) &&
+ retry_i_frames_less_than_max_transmit(req_seq) && with_valid_f_bit(f)) {
+ remote_busy_ = false;
+ pass_to_tx(req_seq, f);
+ retransmit_i_frames(req_seq, p);
+ send_pending_i_frames();
+ if (p_bit_outstanding()) {
+ rej_actioned_ = true;
+ }
+ } else if (f == Final::POLL_RESPONSE && with_valid_req_seq_retrans(req_seq) &&
+ retry_i_frames_less_than_max_transmit(req_seq) && with_valid_f_bit(f)) {
+ remote_busy_ = false;
+ pass_to_tx(req_seq, f);
+ if (!rej_actioned_) {
+ retransmit_i_frames(req_seq, p);
+ } else {
+ rej_actioned_ = false;
+ }
+ send_pending_i_frames();
+ } else if (with_valid_req_seq_retrans(req_seq) && !retry_i_frames_less_than_max_transmit(req_seq)) {
+ CloseChannel();
+ } else if (with_invalid_req_seq_retrans(req_seq)) {
+ CloseChannel();
+ }
+ } else if (rx_state_ == RxState::REJ_SENT) {
+ if (f == Final::NOT_SET && with_valid_req_seq_retrans(req_seq) &&
+ retry_i_frames_less_than_max_transmit(req_seq) && with_valid_f_bit(f)) {
+ remote_busy_ = false;
+ pass_to_tx(req_seq, f);
+ retransmit_i_frames(req_seq, p);
+ send_pending_i_frames();
+ if (p_bit_outstanding()) {
+ rej_actioned_ = true;
+ }
+ } else if (f == Final::POLL_RESPONSE && with_valid_req_seq_retrans(req_seq) &&
+ retry_i_frames_less_than_max_transmit(req_seq) && with_valid_f_bit(f)) {
+ remote_busy_ = false;
+ pass_to_tx(req_seq, f);
+ if (!rej_actioned_) {
+ retransmit_i_frames(req_seq, p);
+ } else {
+ rej_actioned_ = false;
+ }
+ send_pending_i_frames();
+ } else if (with_valid_req_seq_retrans(req_seq) && !retry_i_frames_less_than_max_transmit(req_seq)) {
+ CloseChannel();
+ } else if (with_invalid_req_seq_retrans(req_seq)) {
+ CloseChannel();
+ }
+ } else if (rx_state_ == RxState::SREJ_SENT) {
+ // SREJ NOT SUPPORTED
+ }
+ }
+
+ void recv_rnr(uint8_t req_seq, Poll p = Poll::NOT_SET, Final f = Final::NOT_SET) {
+ if (rx_state_ == RxState::RECV) {
+ if (p == Poll::NOT_SET && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+ remote_busy_ = true;
+ pass_to_tx(req_seq, f);
+ stop_retrans_timer();
+ } else if (p == Poll::POLL && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+ remote_busy_ = true;
+ pass_to_tx(req_seq, f);
+ stop_retrans_timer();
+ send_rr_or_rnr(Poll::NOT_SET, Final::POLL_RESPONSE);
+ } else if (with_invalid_req_seq_retrans(req_seq)) {
+ CloseChannel();
+ }
+ } else if (rx_state_ == RxState::REJ_SENT) {
+ if (p == Poll::NOT_SET && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+ remote_busy_ = true;
+ pass_to_tx(req_seq, f);
+ send_rr(Final::POLL_RESPONSE);
+ } else if (p == Poll::POLL && with_valid_req_seq(req_seq) && with_valid_f_bit(f)) {
+ remote_busy_ = true;
+ pass_to_tx(req_seq, f);
+ send_rr(Final::NOT_SET);
+ } else if (with_invalid_req_seq_retrans(req_seq)) {
+ CloseChannel();
+ }
+ } else if (rx_state_ == RxState::SREJ_SENT) {
+ // SREJ NOT SUPPORTED
+ }
+ }
+
+ void recv_srej(uint8_t req_seq, Poll p = Poll::NOT_SET, Final f = Final::NOT_SET) {
+ if (rx_state_ == RxState::RECV) {
+ if (p == Poll::NOT_SET && f == Final::NOT_SET && with_valid_req_seq_retrans(req_seq) &&
+ retry_i_frames_less_than_max_transmit(req_seq) && with_valid_f_bit(f)) {
+ remote_busy_ = false;
+ pass_to_tx_f_bit(f);
+ retransmit_requested_i_frame(req_seq, p);
+ if (p_bit_outstanding()) {
+ srej_actioned_ = true;
+ srej_save_req_seq_ = req_seq;
+ }
+ } else if (f == Final::POLL_RESPONSE && with_valid_req_seq_retrans(req_seq) &&
+ retry_i_frames_less_than_max_transmit(req_seq) && with_valid_f_bit(f)) {
+ remote_busy_ = false;
+ pass_to_tx_f_bit(f);
+ if (srej_actioned_ && srej_save_req_seq_ == req_seq) {
+ srej_actioned_ = false;
+ } else {
+ retransmit_requested_i_frame(req_seq, p);
+ }
+ } else if (p == Poll::POLL && with_valid_req_seq_retrans(req_seq) &&
+ retry_i_frames_less_than_max_transmit(req_seq) && with_valid_f_bit(f)) {
+ remote_busy_ = false;
+ pass_to_tx(req_seq, f);
+ retransmit_requested_i_frame(req_seq, p);
+ if (p_bit_outstanding()) {
+ srej_actioned_ = true;
+ srej_save_req_seq_ = req_seq;
+ }
+ } else if (with_valid_req_seq_retrans(req_seq) && !retry_i_frames_less_than_max_transmit(req_seq)) {
+ CloseChannel();
+ } else if (with_invalid_req_seq_retrans(req_seq)) {
+ CloseChannel();
+ }
+ } else if (rx_state_ == RxState::REJ_SENT) {
+ if (p == Poll::NOT_SET && f == Final::NOT_SET && with_valid_req_seq_retrans(req_seq) &&
+ retry_i_frames_less_than_max_transmit(req_seq) && with_valid_f_bit(f)) {
+ remote_busy_ = false;
+ pass_to_tx_f_bit(f);
+ retransmit_requested_i_frame(req_seq, p);
+ if (p_bit_outstanding()) {
+ srej_actioned_ = true;
+ srej_save_req_seq_ = req_seq;
+ }
+ } else if (f == Final::POLL_RESPONSE && with_valid_req_seq_retrans(req_seq) &&
+ retry_i_frames_less_than_max_transmit(req_seq) && with_valid_f_bit(f)) {
+ remote_busy_ = false;
+ pass_to_tx_f_bit(f);
+ if (srej_actioned_ && srej_save_req_seq_ == req_seq) {
+ srej_actioned_ = false;
+ } else {
+ retransmit_requested_i_frame(req_seq, p);
+ }
+ } else if (p == Poll::POLL && with_valid_req_seq_retrans(req_seq) &&
+ retry_i_frames_less_than_max_transmit(req_seq) && with_valid_f_bit(f)) {
+ remote_busy_ = false;
+ pass_to_tx(req_seq, f);
+ retransmit_requested_i_frame(req_seq, p);
+ send_pending_i_frames();
+ if (p_bit_outstanding()) {
+ srej_actioned_ = true;
+ srej_save_req_seq_ = req_seq;
+ }
+ } else if (with_valid_req_seq_retrans(req_seq) && !retry_i_frames_less_than_max_transmit(req_seq)) {
+ CloseChannel();
+ } else if (with_invalid_req_seq_retrans(req_seq)) {
+ CloseChannel();
+ }
+ } else if (rx_state_ == RxState::SREJ_SENT) {
+ // SREJ NOT SUPPORTED
+ }
+ }
+
+ // Conditions (@see 8.6.5.5)
+ bool remote_busy() {
+ return remote_busy_;
+ }
+
+ bool local_busy() {
+ return local_busy_;
+ }
+
+ bool rem_window_not_full() {
+ return unacked_frames_ < controller_->remote_tx_window_;
+ }
+
+ bool rem_window_full() {
+ return unacked_frames_ == controller_->remote_tx_window_;
+ }
+
+ bool rnr_sent() {
+ return rnr_sent_;
+ }
+
+ bool retry_i_frames_less_than_max_transmit(uint8_t req_seq) {
+ return retry_i_frames_[req_seq] < controller_->local_max_transmit_;
+ }
+
+ bool retry_count_less_than_max_transmit() {
+ return retry_count_ < controller_->local_max_transmit_;
+ }
+
+ bool with_expected_tx_seq(uint8_t tx_seq) {
+ return tx_seq == expected_tx_seq_;
+ }
+
+ bool with_valid_req_seq(uint8_t req_seq) {
+ return expected_ack_seq_ <= req_seq && req_seq <= next_tx_seq_;
+ }
+
+ bool with_valid_req_seq_retrans(uint8_t req_seq) {
+ return expected_ack_seq_ <= req_seq && req_seq <= next_tx_seq_;
+ }
+
+ bool with_valid_f_bit(Final f) {
+ return f == Final::NOT_SET || tx_state_ == TxState::WAIT_F;
+ }
+
+ bool with_unexpected_tx_seq(uint8_t tx_seq) {
+ return tx_seq > expected_tx_seq_ && tx_seq <= expected_tx_seq_ + controller_->local_tx_window_;
+ }
+
+ bool with_duplicate_tx_seq(uint8_t tx_seq) {
+ return tx_seq < expected_tx_seq_ && tx_seq >= expected_tx_seq_ - controller_->local_tx_window_;
+ }
+
+ bool with_invalid_tx_seq(uint8_t tx_seq) {
+ return tx_seq < expected_tx_seq_ - controller_->local_tx_window_ ||
+ tx_seq > expected_tx_seq_ + controller_->local_tx_window_;
+ }
+
+ bool with_invalid_req_seq(uint8_t req_seq) {
+ return req_seq < expected_ack_seq_ || req_seq >= next_tx_seq_;
+ }
+
+ bool with_invalid_req_seq_retrans(uint8_t req_seq) {
+ return req_seq < expected_ack_seq_ || req_seq >= next_tx_seq_;
+ }
+
+ bool not_with_expected_tx_seq(uint8_t tx_seq) {
+ return !with_invalid_tx_seq(tx_seq) && !with_expected_tx_seq(tx_seq);
+ }
+
+ bool with_expected_tx_seq_srej() {
+ // We don't support sending SREJ
+ return false;
+ }
+
+ bool send_req_is_true() {
+ // We don't support sending SREJ
+ return false;
+ }
+
+ bool srej_list_is_one() {
+ // We don't support sending SREJ
+ return false;
+ }
+
+ bool with_unexpected_tx_seq_srej() {
+ // We don't support sending SREJ
+ return false;
+ }
+
+ bool with_duplicate_tx_seq_srej() {
+ // We don't support sending SREJ
+ return false;
+ }
+
+ // Actions (@see 8.6.5.6)
+
+ void _send_i_frame(SegmentationAndReassembly sar, std::unique_ptr<CopyablePacketBuilder> segment, uint8_t req_seq,
+ uint8_t tx_seq, uint16_t sdu_size = 0, Final f = Final::NOT_SET) {
+ std::unique_ptr<packet::BasePacketBuilder> builder;
+ if (sar == SegmentationAndReassembly::START) {
+ if (controller_->fcs_enabled_) {
+ builder = EnhancedInformationStartFrameWithFcsBuilder::Create(controller_->remote_cid_, tx_seq, f, req_seq,
+ sdu_size, std::move(segment));
+ } else {
+ builder = EnhancedInformationStartFrameBuilder::Create(controller_->remote_cid_, tx_seq, f, req_seq, sdu_size,
+ std::move(segment));
+ }
+ } else {
+ if (controller_->fcs_enabled_) {
+ builder = EnhancedInformationFrameWithFcsBuilder::Create(controller_->remote_cid_, tx_seq, f, req_seq, sar,
+ std::move(segment));
+ } else {
+ builder = EnhancedInformationFrameBuilder::Create(controller_->remote_cid_, tx_seq, f, req_seq, sar,
+ std::move(segment));
+ }
+ }
+ controller_->send_pdu(std::move(builder));
+ }
+
+ void send_data(SegmentationAndReassembly sar, uint16_t sdu_size, std::unique_ptr<packet::RawBuilder> segment,
+ Final f = Final::NOT_SET) {
+ std::shared_ptr<packet::RawBuilder> shared_segment(segment.release());
+ unacked_list_.emplace(std::piecewise_construct, std::forward_as_tuple(next_tx_seq_),
+ std::forward_as_tuple(sar, sdu_size, shared_segment));
+
+ std::unique_ptr<CopyablePacketBuilder> copyable_packet_builder =
+ std::make_unique<CopyablePacketBuilder>(std::get<2>(unacked_list_.find(next_tx_seq_)->second));
+ _send_i_frame(sar, std::move(copyable_packet_builder), buffer_seq_, next_tx_seq_, sdu_size, f);
+ unacked_frames_++;
+ frames_sent_++;
+ retry_i_frames_[next_tx_seq_] = 1;
+ next_tx_seq_ = (next_tx_seq_ + 1) % kMaxTxWin;
+ start_retrans_timer();
+ }
+
+ void pend_data(SegmentationAndReassembly sar, uint16_t sdu_size, std::unique_ptr<packet::RawBuilder> data) {
+ pending_frames_.emplace(std::make_tuple(sar, sdu_size, std::move(data)));
+ }
+
+ void process_req_seq(uint8_t req_seq) {
+ for (int i = expected_ack_seq_; i < req_seq; i++) {
+ unacked_list_.erase(i);
+ retry_i_frames_[i] = 0;
+ }
+ unacked_frames_ -= ((req_seq - expected_ack_seq_) + kMaxTxWin) % kMaxTxWin;
+ if (unacked_frames_ == 0) {
+ stop_retrans_timer();
+ }
+ }
+
+ void _send_s_frame(SupervisoryFunction s, uint8_t req_seq, Poll p, Final f) {
+ std::unique_ptr<packet::BasePacketBuilder> builder;
+ if (controller_->fcs_enabled_) {
+ builder = EnhancedSupervisoryFrameWithFcsBuilder::Create(controller_->remote_cid_, s, p, f, req_seq);
+ } else {
+ builder = EnhancedSupervisoryFrameBuilder::Create(controller_->remote_cid_, s, p, f, req_seq);
+ }
+ controller_->send_pdu(std::move(builder));
+ }
+
+ void send_rr(Poll p) {
+ _send_s_frame(SupervisoryFunction::RECEIVER_READY, expected_tx_seq_, p, Final::NOT_SET);
+ }
+
+ void send_rr(Final f) {
+ _send_s_frame(SupervisoryFunction::RECEIVER_READY, expected_tx_seq_, Poll::NOT_SET, f);
+ }
+
+ void send_rnr(Poll p) {
+ _send_s_frame(SupervisoryFunction::RECEIVER_NOT_READY, expected_tx_seq_, p, Final::NOT_SET);
+ }
+
+ void send_rnr(Final f) {
+ _send_s_frame(SupervisoryFunction::RECEIVER_NOT_READY, expected_tx_seq_, Poll::NOT_SET, f);
+ }
+
+ void send_rej(Poll p = Poll::NOT_SET, Final f = Final::NOT_SET) {
+ _send_s_frame(SupervisoryFunction::REJECT, expected_tx_seq_, p, f);
+ }
+
+ void send_rr_or_rnr(Poll p = Poll::NOT_SET, Final f = Final::NOT_SET) {
+ if (local_busy()) {
+ _send_s_frame(SupervisoryFunction::RECEIVER_NOT_READY, buffer_seq_, p, f);
+ } else {
+ _send_s_frame(SupervisoryFunction::RECEIVER_READY, buffer_seq_, p, f);
+ }
+ }
+
+ void send_i_or_rr_or_rnr(Final f = Final::POLL_RESPONSE) {
+ auto frames_sent = 0;
+ if (local_busy()) {
+ send_rnr(Final::POLL_RESPONSE);
+ }
+ if (remote_busy() && unacked_frames_ > 0) {
+ start_retrans_timer();
+ }
+ remote_busy_ = false;
+ send_pending_i_frames(f); // TODO: Only first has f = 1, other f = 0. Also increase frames_sent
+ if (!local_busy() && frames_sent == 0) {
+ send_rr(Final::POLL_RESPONSE);
+ }
+ }
+
+ void send_srej() {
+ // Sending SREJ is not supported
+ }
+
+ void start_retrans_timer() {
+ retrans_timer_.Schedule(common::BindOnce(&impl::retrans_timer_expires, common::Unretained(this)),
+ std::chrono::milliseconds(controller_->local_retransmit_timeout_ms_));
+ }
+
+ void start_monitor_timer() {
+ monitor_timer_.Schedule(common::BindOnce(&impl::monitor_timer_expires, common::Unretained(this)),
+ std::chrono::milliseconds(controller_->local_monitor_timeout_ms_));
+ }
+
+ void pass_to_tx(uint8_t req_seq, Final f) {
+ recv_req_seq_and_f_bit(req_seq, f);
+ }
+
+ void pass_to_tx_f_bit(Final f) {
+ recv_f_bit(f);
+ }
+
+ void data_indication(SegmentationAndReassembly sar, uint16_t sdu_size, const packet::PacketView<true>& segment) {
+ controller_->stage_for_reassembly(sar, sdu_size, segment);
+ buffer_seq_ = (buffer_seq_ + 1) % kMaxTxWin;
+ }
+
+ void increment_expected_tx_seq() {
+ expected_tx_seq_ = (expected_tx_seq_ + 1) % kMaxTxWin;
+ }
+
+ void stop_retrans_timer() {
+ retrans_timer_.Cancel();
+ }
+
+ void stop_monitor_timer() {
+ monitor_timer_.Cancel();
+ }
+
+ void send_ack(Final f = Final::NOT_SET) {
+ if (local_busy()) {
+ send_rnr(f);
+ } else if (!remote_busy() && /* pending i frames exist */ rem_window_not_full()) {
+ send_pending_i_frames(f);
+ } else {
+ send_rr(f);
+ }
+ }
+
+ void init_srej() {
+ // We don't support sending SREJ
+ }
+
+ void save_i_frame_srej() {
+ // We don't support sending SREJ
+ }
+
+ void store_or_ignore() {
+ // We choose to ignore. We don't support local busy so far.
+ }
+
+ bool p_bit_outstanding() {
+ return tx_state_ == TxState::WAIT_F;
+ }
+
+ void retransmit_i_frames(uint8_t req_seq, Poll p = Poll::NOT_SET) {
+ uint8_t i = req_seq;
+ Final f = (p == Poll::NOT_SET ? Final::NOT_SET : Final::POLL_RESPONSE);
+ while (unacked_list_.find(i) == unacked_list_.end()) {
+ std::unique_ptr<CopyablePacketBuilder> copyable_packet_builder =
+ std::make_unique<CopyablePacketBuilder>(std::get<2>(unacked_list_.find(i)->second));
+ _send_i_frame(std::get<0>(unacked_list_.find(i)->second), std::move(copyable_packet_builder), buffer_seq_, i,
+ std::get<1>(unacked_list_.find(i)->second), f);
+ retry_i_frames_[i]++;
+ if (retry_i_frames_[i] == controller_->local_max_transmit_) {
+ CloseChannel();
+ }
+ frames_sent_++;
+ f = Final::NOT_SET;
+ }
+ start_retrans_timer();
+ }
+
+ void retransmit_requested_i_frame(uint8_t req_seq, Poll p) {
+ Final f = p == Poll::POLL ? Final::POLL_RESPONSE : Final::NOT_SET;
+ if (unacked_list_.find(req_seq) == unacked_list_.end()) {
+ LOG_ERROR("Received invalid SREJ");
+ return;
+ }
+ std::unique_ptr<CopyablePacketBuilder> copyable_packet_builder =
+ std::make_unique<CopyablePacketBuilder>(std::get<2>(unacked_list_.find(req_seq)->second));
+ _send_i_frame(std::get<0>(unacked_list_.find(req_seq)->second), std::move(copyable_packet_builder), buffer_seq_,
+ req_seq, std::get<1>(unacked_list_.find(req_seq)->second), f);
+ retry_i_frames_[req_seq]++;
+ start_retrans_timer();
+ }
+
+ void send_pending_i_frames(Final f = Final::NOT_SET) {
+ if (p_bit_outstanding()) {
+ return;
+ }
+ while (rem_window_not_full() && !pending_frames_.empty()) {
+ auto& frame = pending_frames_.front();
+ send_data(std::get<0>(frame), std::get<1>(frame), std::move(std::get<2>(frame)), f);
+ pending_frames_.pop();
+ f = Final::NOT_SET;
+ }
+ }
+
+ void CloseChannel() {
+ // TODO: Needs a reference to signaller
+ }
+
+ void pop_srej_list() {
+ // We don't support sending SREJ
+ }
+
+ void data_indication_srej() {
+ // We don't support sending SREJ
+ }
+};
+
+// Segmentation is handled here
+void ErtmController::OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) {
+ auto sdu_size = sdu->size();
+ std::vector<std::unique_ptr<packet::RawBuilder>> segments;
+ packet::FragmentingInserter fragmenting_inserter(size_each_packet_, std::back_insert_iterator(segments));
+ sdu->Serialize(fragmenting_inserter);
+ fragmenting_inserter.finalize();
+ if (segments.size() == 1) {
+ pimpl_->data_request(SegmentationAndReassembly::UNSEGMENTED, std::move(segments[0]));
+ return;
+ }
+ pimpl_->data_request(SegmentationAndReassembly::START, std::move(segments[0]), sdu_size);
+ for (auto i = 1; i < segments.size() - 1; i++) {
+ pimpl_->data_request(SegmentationAndReassembly::CONTINUATION, std::move(segments[i]));
+ }
+ pimpl_->data_request(SegmentationAndReassembly::END, std::move(segments.back()));
+}
+
+void ErtmController::OnPdu(packet::PacketView<true> pdu) {
+ if (fcs_enabled_) {
+ on_pdu_fcs(pdu);
+ } else {
+ on_pdu_no_fcs(pdu);
+ }
+}
+
+void ErtmController::on_pdu_no_fcs(const packet::PacketView<true>& pdu) {
+ auto basic_frame_view = BasicFrameView::Create(pdu);
+ if (!basic_frame_view.IsValid()) {
+ return;
+ }
+ auto standard_frame_view = StandardFrameView::Create(basic_frame_view);
+ if (!standard_frame_view.IsValid()) {
+ LOG_WARN("Received invalid frame");
+ return;
+ }
+ auto type = standard_frame_view.GetFrameType();
+ if (type == FrameType::I_FRAME) {
+ auto i_frame_view = EnhancedInformationFrameView::Create(standard_frame_view);
+ if (!i_frame_view.IsValid()) {
+ LOG_WARN("Received invalid frame");
+ return;
+ }
+ Final f = i_frame_view.GetF();
+ uint8_t tx_seq = i_frame_view.GetTxSeq();
+ uint8_t req_seq = i_frame_view.GetReqSeq();
+ auto sar = i_frame_view.GetSar();
+ if (sar == SegmentationAndReassembly::START) {
+ auto i_frame_start_view = EnhancedInformationStartFrameView::Create(i_frame_view);
+ if (!i_frame_start_view.IsValid()) {
+ LOG_WARN("Received invalid I-Frame START");
+ return;
+ }
+ pimpl_->recv_i_frame(f, tx_seq, req_seq, sar, i_frame_start_view.GetL2capSduLength(),
+ i_frame_start_view.GetPayload());
+ } else {
+ pimpl_->recv_i_frame(f, tx_seq, req_seq, sar, 0, i_frame_view.GetPayload());
+ }
+ } else if (type == FrameType::S_FRAME) {
+ auto s_frame_view = EnhancedSupervisoryFrameView::Create(standard_frame_view);
+ if (!s_frame_view.IsValid()) {
+ LOG_WARN("Received invalid frame");
+ return;
+ }
+ auto req_seq = s_frame_view.GetReqSeq();
+ auto f = s_frame_view.GetF();
+ auto p = s_frame_view.GetP();
+ switch (s_frame_view.GetS()) {
+ case SupervisoryFunction::RECEIVER_READY:
+ pimpl_->recv_rr(req_seq, p, f);
+ break;
+ case SupervisoryFunction::RECEIVER_NOT_READY:
+ pimpl_->recv_rnr(req_seq, p, f);
+ break;
+ case SupervisoryFunction::REJECT:
+ pimpl_->recv_rej(req_seq, p, f);
+ break;
+ case SupervisoryFunction::SELECT_REJECT:
+ pimpl_->recv_srej(req_seq, p, f);
+ break;
+ }
+ } else {
+ LOG_WARN("Received invalid frame");
+ }
+}
+
+void ErtmController::on_pdu_fcs(const packet::PacketView<true>& pdu) {
+ auto basic_frame_view = BasicFrameWithFcsView::Create(pdu);
+ if (!basic_frame_view.IsValid()) {
+ return;
+ }
+ auto standard_frame_view = StandardFrameWithFcsView::Create(basic_frame_view);
+ if (!standard_frame_view.IsValid()) {
+ LOG_WARN("Received invalid frame");
+ return;
+ }
+ auto type = standard_frame_view.GetFrameType();
+ if (type == FrameType::I_FRAME) {
+ auto i_frame_view = EnhancedInformationFrameWithFcsView::Create(standard_frame_view);
+ if (!i_frame_view.IsValid()) {
+ LOG_WARN("Received invalid frame");
+ return;
+ }
+ Final f = i_frame_view.GetF();
+ uint8_t tx_seq = i_frame_view.GetTxSeq();
+ uint8_t req_seq = i_frame_view.GetReqSeq();
+ auto sar = i_frame_view.GetSar();
+ if (sar == SegmentationAndReassembly::START) {
+ auto i_frame_start_view = EnhancedInformationStartFrameWithFcsView::Create(i_frame_view);
+ if (!i_frame_start_view.IsValid()) {
+ LOG_WARN("Received invalid I-Frame START");
+ return;
+ }
+ pimpl_->recv_i_frame(f, tx_seq, req_seq, sar, i_frame_start_view.GetL2capSduLength(),
+ i_frame_start_view.GetPayload());
+ } else {
+ pimpl_->recv_i_frame(f, tx_seq, req_seq, sar, 0, i_frame_view.GetPayload());
+ }
+ } else if (type == FrameType::S_FRAME) {
+ auto s_frame_view = EnhancedSupervisoryFrameWithFcsView::Create(standard_frame_view);
+ if (!s_frame_view.IsValid()) {
+ LOG_WARN("Received invalid frame");
+ return;
+ }
+ auto req_seq = s_frame_view.GetReqSeq();
+ auto f = s_frame_view.GetF();
+ auto p = s_frame_view.GetP();
+ switch (s_frame_view.GetS()) {
+ case SupervisoryFunction::RECEIVER_READY:
+ pimpl_->recv_rr(req_seq, p, f);
+ break;
+ case SupervisoryFunction::RECEIVER_NOT_READY:
+ pimpl_->recv_rnr(req_seq, p, f);
+ break;
+ case SupervisoryFunction::REJECT:
+ pimpl_->recv_rej(req_seq, p, f);
+ break;
+ case SupervisoryFunction::SELECT_REJECT:
+ pimpl_->recv_srej(req_seq, p, f);
+ break;
+ }
+ } else {
+ LOG_WARN("Received invalid frame");
+ }
+}
+
+std::unique_ptr<packet::BasePacketBuilder> ErtmController::GetNextPacket() {
+ auto next = std::move(pdu_queue_.front());
+ pdu_queue_.pop();
+ return next;
+}
+
+void ErtmController::stage_for_reassembly(SegmentationAndReassembly sar, uint16_t sdu_size,
+ const packet::PacketView<kLittleEndian>& payload) {
+ switch (sar) {
+ case SegmentationAndReassembly::UNSEGMENTED:
+ if (sar_state_ != SegmentationAndReassembly::END) {
+ LOG_WARN("Received invalid SAR");
+ close_channel();
+ return;
+ }
+ // TODO: Enforce MTU
+ enqueue_buffer_.Enqueue(std::make_unique<packet::PacketView<kLittleEndian>>(payload), handler_);
+ break;
+ case SegmentationAndReassembly::START:
+ if (sar_state_ != SegmentationAndReassembly::END) {
+ LOG_WARN("Received invalid SAR");
+ close_channel();
+ return;
+ }
+ // TODO: Enforce MTU
+ sar_state_ = SegmentationAndReassembly::START;
+ reassembly_stage_ = payload;
+ remaining_sdu_continuation_packet_size_ = sdu_size - payload.size();
+ break;
+ case SegmentationAndReassembly::CONTINUATION:
+ if (sar_state_ == SegmentationAndReassembly::END) {
+ LOG_WARN("Received invalid SAR");
+ close_channel();
+ return;
+ }
+ reassembly_stage_.AppendPacketView(payload);
+ remaining_sdu_continuation_packet_size_ -= payload.size();
+ break;
+ case SegmentationAndReassembly::END:
+ if (sar_state_ == SegmentationAndReassembly::END) {
+ LOG_WARN("Received invalid SAR");
+ close_channel();
+ return;
+ }
+ sar_state_ = SegmentationAndReassembly::END;
+ remaining_sdu_continuation_packet_size_ -= payload.size();
+ if (remaining_sdu_continuation_packet_size_ != 0) {
+ LOG_WARN("Received invalid END I-Frame");
+ reassembly_stage_ = PacketViewForReassembly(std::make_shared<std::vector<uint8_t>>());
+ remaining_sdu_continuation_packet_size_ = 0;
+ close_channel();
+ return;
+ }
+ reassembly_stage_.AppendPacketView(payload);
+ enqueue_buffer_.Enqueue(std::make_unique<packet::PacketView<kLittleEndian>>(reassembly_stage_), handler_);
+ break;
+ }
+}
+
+void ErtmController::EnableFcs(bool enabled) {
+ fcs_enabled_ = enabled;
+}
+
+void ErtmController::send_pdu(std::unique_ptr<packet::BasePacketBuilder> pdu) {
+ pdu_queue_.emplace(std::move(pdu));
+ scheduler_->OnPacketsReady(cid_, 1);
+}
+
+void ErtmController::SetRetransmissionAndFlowControlOptions(
+ const RetransmissionAndFlowControlConfigurationOption& option) {
+ local_tx_window_ = option.tx_window_size_;
+ local_max_transmit_ = option.max_transmit_;
+ local_retransmit_timeout_ms_ = option.retransmission_time_out_;
+ local_monitor_timeout_ms_ = option.monitor_time_out_;
+}
+
+void ErtmController::close_channel() {
+ // TODO: Get a reference to signalling manager
+}
+
+size_t ErtmController::CopyablePacketBuilder::size() const {
+ return builder_->size();
+}
+
+void ErtmController::CopyablePacketBuilder::Serialize(BitInserter& it) const {
+ builder_->Serialize(it);
+}
+
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.h b/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.h
new file mode 100644
index 0000000..dd1ca64
--- /dev/null
+++ b/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <unordered_map>
+#include <utility>
+
+#include "common/bidi_queue.h"
+#include "l2cap/cid.h"
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/internal/data_controller.h"
+#include "l2cap/internal/scheduler.h"
+#include "l2cap/l2cap_packets.h"
+#include "l2cap/mtu.h"
+#include "os/handler.h"
+#include "os/queue.h"
+#include "packet/base_packet_builder.h"
+#include "packet/packet_view.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+class ErtmController : public DataController {
+ public:
+ using UpperEnqueue = packet::PacketView<packet::kLittleEndian>;
+ using UpperDequeue = packet::BasePacketBuilder;
+ using UpperQueueDownEnd = common::BidiQueueEnd<UpperEnqueue, UpperDequeue>;
+ ErtmController(Cid cid, Cid remote_cid, UpperQueueDownEnd* channel_queue_end, os::Handler* handler,
+ Scheduler* scheduler);
+ ~ErtmController();
+ // Segmentation is handled here
+ void OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) override;
+ void OnPdu(packet::PacketView<true> pdu) override;
+ std::unique_ptr<packet::BasePacketBuilder> GetNextPacket() override;
+ void EnableFcs(bool enabled) override;
+ void SetRetransmissionAndFlowControlOptions(const RetransmissionAndFlowControlConfigurationOption& option) override;
+
+ private:
+ Cid cid_;
+ Cid remote_cid_;
+ os::EnqueueBuffer<UpperEnqueue> enqueue_buffer_;
+ os::Handler* handler_;
+ std::queue<std::unique_ptr<packet::BasePacketBuilder>> pdu_queue_;
+ Scheduler* scheduler_;
+
+ // Configuration options
+ bool fcs_enabled_ = false;
+ uint16_t local_tx_window_ = 10;
+ uint16_t local_max_transmit_ = 20;
+ uint16_t local_retransmit_timeout_ms_ = 2000;
+ uint16_t local_monitor_timeout_ms_ = 12000;
+
+ uint16_t remote_tx_window_ = 10;
+ uint16_t remote_mps_ = 1010;
+
+ uint16_t size_each_packet_ =
+ (remote_mps_ - 4 /* basic L2CAP header */ - 2 /* SDU length */ - 2 /* Extended control */ - 2 /* FCS */);
+
+ class PacketViewForReassembly : public packet::PacketView<kLittleEndian> {
+ public:
+ PacketViewForReassembly(const PacketView& packetView) : PacketView(packetView) {}
+ void AppendPacketView(packet::PacketView<kLittleEndian> to_append) {
+ Append(to_append);
+ }
+ };
+
+ class CopyablePacketBuilder : public packet::BasePacketBuilder {
+ public:
+ CopyablePacketBuilder(std::shared_ptr<packet::RawBuilder> builder) : builder_(std::move(builder)) {}
+
+ void Serialize(BitInserter& it) const override;
+
+ size_t size() const override;
+
+ private:
+ std::shared_ptr<packet::RawBuilder> builder_;
+ };
+
+ PacketViewForReassembly reassembly_stage_{std::make_shared<std::vector<uint8_t>>()};
+ SegmentationAndReassembly sar_state_ = SegmentationAndReassembly::END;
+ uint16_t remaining_sdu_continuation_packet_size_ = 0;
+
+ void stage_for_reassembly(SegmentationAndReassembly sar, uint16_t sdu_size,
+ const packet::PacketView<kLittleEndian>& payload);
+ void send_pdu(std::unique_ptr<packet::BasePacketBuilder> pdu);
+
+ void close_channel();
+
+ void on_pdu_no_fcs(const packet::PacketView<true>& pdu);
+ void on_pdu_fcs(const packet::PacketView<true>& pdu);
+
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+};
+
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller_test.cc b/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller_test.cc
new file mode 100644
index 0000000..e1b5818
--- /dev/null
+++ b/gd/l2cap/internal/enhanced_retransmission_mode_channel_data_controller_test.cc
@@ -0,0 +1,202 @@
+/*
+ * Copyright 2019 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 "l2cap/internal/enhanced_retransmission_mode_channel_data_controller.h"
+
+#include <gtest/gtest.h>
+
+#include "l2cap/internal/scheduler_mock.h"
+#include "l2cap/l2cap_packets.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+namespace {
+
+std::unique_ptr<packet::BasePacketBuilder> CreateSdu(std::vector<uint8_t> payload) {
+ auto raw_builder = std::make_unique<packet::RawBuilder>();
+ raw_builder->AddOctets(payload);
+ return raw_builder;
+}
+
+PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+ auto bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter i(*bytes);
+ bytes->reserve(packet->size());
+ packet->Serialize(i);
+ return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+void sync_handler(os::Handler* handler) {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+ auto status = future.wait_for(std::chrono::milliseconds(300));
+ EXPECT_EQ(status, std::future_status::ready);
+}
+
+class ErtmDataControllerTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+ user_handler_ = new os::Handler(thread_);
+ queue_handler_ = new os::Handler(thread_);
+ }
+
+ void TearDown() override {
+ queue_handler_->Clear();
+ user_handler_->Clear();
+ delete queue_handler_;
+ delete user_handler_;
+ delete thread_;
+ }
+
+ os::Thread* thread_ = nullptr;
+ os::Handler* user_handler_ = nullptr;
+ os::Handler* queue_handler_ = nullptr;
+};
+
+TEST_F(ErtmDataControllerTest, transmit_no_fcs) {
+ common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10};
+ testing::MockScheduler scheduler;
+ ErtmController controller{1, 1, channel_queue.GetDownEnd(), queue_handler_, &scheduler};
+ EXPECT_CALL(scheduler, OnPacketsReady(1, 1));
+ controller.OnSdu(CreateSdu({'a', 'b', 'c', 'd'}));
+ auto next_packet = controller.GetNextPacket();
+ EXPECT_NE(next_packet, nullptr);
+ auto view = GetPacketView(std::move(next_packet));
+ auto pdu_view = BasicFrameView::Create(view);
+ EXPECT_TRUE(pdu_view.IsValid());
+ auto standard_view = StandardFrameView::Create(pdu_view);
+ EXPECT_TRUE(standard_view.IsValid());
+ auto i_frame_view = EnhancedInformationFrameView::Create(standard_view);
+ EXPECT_TRUE(i_frame_view.IsValid());
+ auto payload = i_frame_view.GetPayload();
+ std::string data = std::string(payload.begin(), payload.end());
+ EXPECT_EQ(data, "abcd");
+ EXPECT_EQ(i_frame_view.GetTxSeq(), 0);
+ EXPECT_EQ(i_frame_view.GetReqSeq(), 0);
+}
+
+TEST_F(ErtmDataControllerTest, receive_no_fcs) {
+ common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10};
+ testing::MockScheduler scheduler;
+ ErtmController controller{1, 1, channel_queue.GetDownEnd(), queue_handler_, &scheduler};
+ auto segment = CreateSdu({'a', 'b', 'c', 'd'});
+ auto builder = EnhancedInformationFrameBuilder::Create(1, 0, Final::NOT_SET, 0,
+ SegmentationAndReassembly::UNSEGMENTED, std::move(segment));
+ auto base_view = GetPacketView(std::move(builder));
+ controller.OnPdu(base_view);
+ sync_handler(queue_handler_);
+ auto payload = channel_queue.GetUpEnd()->TryDequeue();
+ EXPECT_NE(payload, nullptr);
+ std::string data = std::string(payload->begin(), payload->end());
+ EXPECT_EQ(data, "abcd");
+}
+
+TEST_F(ErtmDataControllerTest, reassemble_valid_sdu) {
+ common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10};
+ testing::MockScheduler scheduler;
+ ErtmController controller{1, 1, channel_queue.GetDownEnd(), queue_handler_, &scheduler};
+ auto segment1 = CreateSdu({'a'});
+ auto segment2 = CreateSdu({'b', 'c'});
+ auto segment3 = CreateSdu({'d', 'e', 'f'});
+ auto builder1 = EnhancedInformationStartFrameBuilder::Create(1, 0, Final::NOT_SET, 0, 6, std::move(segment1));
+ auto base_view = GetPacketView(std::move(builder1));
+ controller.OnPdu(base_view);
+ auto builder2 = EnhancedInformationFrameBuilder::Create(1, 1, Final::NOT_SET, 0,
+ SegmentationAndReassembly::CONTINUATION, std::move(segment2));
+ base_view = GetPacketView(std::move(builder2));
+ controller.OnPdu(base_view);
+ auto builder3 = EnhancedInformationFrameBuilder::Create(1, 2, Final::NOT_SET, 0, SegmentationAndReassembly::END,
+ std::move(segment3));
+ base_view = GetPacketView(std::move(builder3));
+ controller.OnPdu(base_view);
+ sync_handler(queue_handler_);
+ auto payload = channel_queue.GetUpEnd()->TryDequeue();
+ EXPECT_NE(payload, nullptr);
+ std::string data = std::string(payload->begin(), payload->end());
+ EXPECT_EQ(data, "abcdef");
+}
+
+TEST_F(ErtmDataControllerTest, reassemble_invalid_sdu_size_in_start_frame) {
+ common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10};
+ testing::MockScheduler scheduler;
+ ErtmController controller{1, 1, channel_queue.GetDownEnd(), queue_handler_, &scheduler};
+ auto segment1 = CreateSdu({'a'});
+ auto segment2 = CreateSdu({'b', 'c'});
+ auto segment3 = CreateSdu({'d', 'e', 'f'});
+ auto builder1 = EnhancedInformationStartFrameBuilder::Create(1, 0, Final::NOT_SET, 0, 10, std::move(segment1));
+ auto base_view = GetPacketView(std::move(builder1));
+ controller.OnPdu(base_view);
+ auto builder2 = EnhancedInformationFrameBuilder::Create(1, 1, Final::NOT_SET, 0,
+ SegmentationAndReassembly::CONTINUATION, std::move(segment2));
+ base_view = GetPacketView(std::move(builder2));
+ controller.OnPdu(base_view);
+ auto builder3 = EnhancedInformationFrameBuilder::Create(1, 2, Final::NOT_SET, 0, SegmentationAndReassembly::END,
+ std::move(segment3));
+ base_view = GetPacketView(std::move(builder3));
+ controller.OnPdu(base_view);
+ sync_handler(queue_handler_);
+ auto payload = channel_queue.GetUpEnd()->TryDequeue();
+ EXPECT_EQ(payload, nullptr);
+}
+
+TEST_F(ErtmDataControllerTest, transmit_with_fcs) {
+ common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10};
+ testing::MockScheduler scheduler;
+ ErtmController controller{1, 1, channel_queue.GetDownEnd(), queue_handler_, &scheduler};
+ controller.EnableFcs(true);
+ EXPECT_CALL(scheduler, OnPacketsReady(1, 1));
+ controller.OnSdu(CreateSdu({'a', 'b', 'c', 'd'}));
+ auto next_packet = controller.GetNextPacket();
+ EXPECT_NE(next_packet, nullptr);
+ auto view = GetPacketView(std::move(next_packet));
+ auto pdu_view = BasicFrameWithFcsView::Create(view);
+ EXPECT_TRUE(pdu_view.IsValid());
+ auto standard_view = StandardFrameWithFcsView::Create(pdu_view);
+ EXPECT_TRUE(standard_view.IsValid());
+ auto i_frame_view = EnhancedInformationFrameWithFcsView::Create(standard_view);
+ EXPECT_TRUE(i_frame_view.IsValid());
+ auto payload = i_frame_view.GetPayload();
+ std::string data = std::string(payload.begin(), payload.end());
+ EXPECT_EQ(data, "abcd");
+ EXPECT_EQ(i_frame_view.GetTxSeq(), 0);
+ EXPECT_EQ(i_frame_view.GetReqSeq(), 0);
+}
+
+TEST_F(ErtmDataControllerTest, receive_packet_with_fcs) {
+ common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10};
+ testing::MockScheduler scheduler;
+ ErtmController controller{1, 1, channel_queue.GetDownEnd(), queue_handler_, &scheduler};
+ controller.EnableFcs(true);
+ auto segment = CreateSdu({'a', 'b', 'c', 'd'});
+ auto builder = EnhancedInformationFrameWithFcsBuilder::Create(
+ 1, 0, Final::NOT_SET, 0, SegmentationAndReassembly::UNSEGMENTED, std::move(segment));
+ auto base_view = GetPacketView(std::move(builder));
+ controller.OnPdu(base_view);
+ sync_handler(queue_handler_);
+ auto payload = channel_queue.GetUpEnd()->TryDequeue();
+ EXPECT_NE(payload, nullptr);
+ std::string data = std::string(payload->begin(), payload->end());
+ EXPECT_EQ(data, "abcd");
+}
+
+} // namespace
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/fixed_channel_allocator.h b/gd/l2cap/internal/fixed_channel_allocator.h
new file mode 100644
index 0000000..b821cb1
--- /dev/null
+++ b/gd/l2cap/internal/fixed_channel_allocator.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <type_traits>
+#include <unordered_map>
+
+#include "hci/hci_packets.h"
+#include "l2cap/cid.h"
+#include "l2cap/security_policy.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+// Helper class for keeping channels in a Link. It allocates and frees Channel object, and supports querying whether a
+// channel is in use
+template <typename FixedChannelImplType, typename LinkType>
+class FixedChannelAllocator {
+ public:
+ FixedChannelAllocator(LinkType* link, os::Handler* l2cap_handler) : link_(link), l2cap_handler_(l2cap_handler) {
+ ASSERT(link_ != nullptr);
+ ASSERT(l2cap_handler_ != nullptr);
+ }
+
+ virtual ~FixedChannelAllocator() = default;
+
+ // Allocates a channel. If cid is used, return nullptr. NOTE: The returned BaseFixedChannelImpl object is still
+ // owned by the channel allocator, NOT the client.
+ virtual std::shared_ptr<FixedChannelImplType> AllocateChannel(Cid cid, SecurityPolicy security_policy) {
+ ASSERT_LOG(!IsChannelAllocated((cid)), "Cid 0x%x for link %s is already in use", cid, link_->ToString().c_str());
+ ASSERT_LOG(cid >= kFirstFixedChannel && cid <= kLastFixedChannel, "Cid %d out of bound", cid);
+ auto elem = channels_.try_emplace(cid, std::make_shared<FixedChannelImplType>(cid, link_, l2cap_handler_));
+ ASSERT_LOG(elem.second, "Failed to create channel for cid 0x%x link %s", cid, link_->ToString().c_str());
+ ASSERT(elem.first->second != nullptr);
+ return elem.first->second;
+ }
+
+ // Frees a channel. If cid doesn't exist, it will crash
+ virtual void FreeChannel(Cid cid) {
+ ASSERT_LOG(IsChannelAllocated(cid), "Channel is not in use: cid %d, link %s", cid, link_->ToString().c_str());
+ channels_.erase(cid);
+ }
+
+ virtual bool IsChannelAllocated(Cid cid) const {
+ return channels_.find(cid) != channels_.end();
+ }
+
+ virtual std::shared_ptr<FixedChannelImplType> FindChannel(Cid cid) {
+ ASSERT_LOG(IsChannelAllocated(cid), "Channel is not in use: cid %d, link %s", cid, link_->ToString().c_str());
+ return channels_.find(cid)->second;
+ }
+
+ virtual size_t NumberOfChannels() const {
+ return channels_.size();
+ }
+
+ virtual void OnAclDisconnected(hci::ErrorCode hci_status) {
+ for (auto& elem : channels_) {
+ elem.second->OnClosed(hci_status);
+ }
+ }
+
+ virtual int GetRefCount() {
+ int ref_count = 0;
+ for (auto& elem : channels_) {
+ if (elem.second->IsAcquired()) {
+ ref_count++;
+ }
+ }
+ return ref_count;
+ }
+
+ private:
+ LinkType* link_;
+ os::Handler* l2cap_handler_;
+ std::unordered_map<Cid, std::shared_ptr<FixedChannelImplType>> channels_;
+};
+
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/fixed_channel_allocator_test.cc b/gd/l2cap/internal/fixed_channel_allocator_test.cc
new file mode 100644
index 0000000..2162d36
--- /dev/null
+++ b/gd/l2cap/internal/fixed_channel_allocator_test.cc
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2019 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 "l2cap/internal/fixed_channel_allocator.h"
+#include "l2cap/classic/internal/fixed_channel_impl_mock.h"
+#include "l2cap/classic/internal/link_mock.h"
+#include "l2cap/internal/parameter_provider_mock.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+using l2cap::classic::internal::testing::MockFixedChannelImpl;
+using l2cap::classic::internal::testing::MockLink;
+using testing::MockParameterProvider;
+using ::testing::Return;
+
+const hci::Address device{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
+
+class L2capFixedChannelAllocatorTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+ handler_ = new os::Handler(thread_);
+ mock_parameter_provider_ = new MockParameterProvider();
+ mock_classic_link_ = new MockLink(handler_, mock_parameter_provider_);
+ EXPECT_CALL(*mock_classic_link_, GetDevice()).WillRepeatedly(Return(device));
+ // Use classic as a place holder
+ channel_allocator_ =
+ std::make_unique<FixedChannelAllocator<MockFixedChannelImpl, MockLink>>(mock_classic_link_, handler_);
+ }
+
+ void TearDown() override {
+ channel_allocator_.reset();
+ delete mock_classic_link_;
+ delete mock_parameter_provider_;
+ handler_->Clear();
+ delete handler_;
+ delete thread_;
+ }
+
+ os::Thread* thread_{nullptr};
+ os::Handler* handler_{nullptr};
+ MockParameterProvider* mock_parameter_provider_{nullptr};
+ MockLink* mock_classic_link_{nullptr};
+ std::unique_ptr<FixedChannelAllocator<MockFixedChannelImpl, MockLink>> channel_allocator_;
+};
+
+TEST_F(L2capFixedChannelAllocatorTest, precondition) {
+ Cid cid = kFirstFixedChannel;
+ EXPECT_FALSE(channel_allocator_->IsChannelAllocated(cid));
+}
+
+TEST_F(L2capFixedChannelAllocatorTest, allocate_and_free_channel) {
+ Cid cid = kFirstFixedChannel;
+ auto channel = channel_allocator_->AllocateChannel(cid, {});
+ EXPECT_TRUE(channel_allocator_->IsChannelAllocated(cid));
+ EXPECT_EQ(channel, channel_allocator_->FindChannel(cid));
+ ASSERT_NO_FATAL_FAILURE(channel_allocator_->FreeChannel(cid));
+ EXPECT_FALSE(channel_allocator_->IsChannelAllocated(cid));
+}
+
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/le_credit_based_channel_data_controller.cc b/gd/l2cap/internal/le_credit_based_channel_data_controller.cc
new file mode 100644
index 0000000..eb510c1
--- /dev/null
+++ b/gd/l2cap/internal/le_credit_based_channel_data_controller.cc
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2019 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 "l2cap/internal/le_credit_based_channel_data_controller.h"
+
+#include "l2cap/l2cap_packets.h"
+#include "packet/fragmenting_inserter.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+LeCreditBasedDataController::LeCreditBasedDataController(Cid cid, Cid remote_cid, UpperQueueDownEnd* channel_queue_end,
+ os::Handler* handler, Scheduler* scheduler)
+ : cid_(cid), remote_cid_(remote_cid), enqueue_buffer_(channel_queue_end), handler_(handler), scheduler_(scheduler) {
+}
+
+void LeCreditBasedDataController::OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) {
+ auto sdu_size = sdu->size();
+ if (sdu_size == 0) {
+ LOG_WARN("Received empty SDU");
+ return;
+ }
+ if (sdu_size > mtu_) {
+ LOG_WARN("Received sdu_size %d > mtu %d", static_cast<int>(sdu_size), mtu_);
+ }
+ std::vector<std::unique_ptr<packet::RawBuilder>> segments;
+ // TODO: We don't need to waste 2 bytes for continuation segment.
+ packet::FragmentingInserter fragmenting_inserter(mps_ - 2, std::back_insert_iterator(segments));
+ sdu->Serialize(fragmenting_inserter);
+ fragmenting_inserter.finalize();
+ std::unique_ptr<BasicFrameBuilder> builder;
+ builder = FirstLeInformationFrameBuilder::Create(remote_cid_, sdu_size, std::move(segments[0]));
+ pdu_queue_.emplace(std::move(builder));
+ for (auto i = 1; i < segments.size(); i++) {
+ builder = BasicFrameBuilder::Create(remote_cid_, std::move(segments[i]));
+ pdu_queue_.emplace(std::move(builder));
+ }
+ scheduler_->OnPacketsReady(cid_, segments.size());
+}
+
+void LeCreditBasedDataController::OnPdu(packet::PacketView<true> pdu) {
+ auto basic_frame_view = BasicFrameView::Create(pdu);
+ if (!basic_frame_view.IsValid()) {
+ LOG_WARN("Received invalid frame");
+ return;
+ }
+ if (basic_frame_view.size() > mps_) {
+ LOG_WARN("Received frame size %d > mps %d, dropping the packet", static_cast<int>(basic_frame_view.size()), mps_);
+ return;
+ }
+ if (remaining_sdu_continuation_packet_size_ == 0) {
+ auto start_frame_view = FirstLeInformationFrameView::Create(basic_frame_view);
+ if (!start_frame_view.IsValid()) {
+ LOG_WARN("Received invalid frame");
+ return;
+ }
+ auto payload = start_frame_view.GetPayload();
+ auto sdu_size = start_frame_view.GetL2capSduLength();
+ remaining_sdu_continuation_packet_size_ = sdu_size - payload.size();
+ reassembly_stage_ = payload;
+ } else {
+ auto payload = basic_frame_view.GetPayload();
+ remaining_sdu_continuation_packet_size_ -= payload.size();
+ reassembly_stage_.AppendPacketView(payload);
+ }
+ if (remaining_sdu_continuation_packet_size_ == 0) {
+ enqueue_buffer_.Enqueue(std::make_unique<PacketView<kLittleEndian>>(reassembly_stage_), handler_);
+ } else if (remaining_sdu_continuation_packet_size_ < 0 || reassembly_stage_.size() > mtu_) {
+ LOG_WARN("Received larger SDU size than expected");
+ reassembly_stage_ = PacketViewForReassembly(std::make_shared<std::vector<uint8_t>>());
+ remaining_sdu_continuation_packet_size_ = 0;
+ // TODO: Close channel
+ }
+}
+
+std::unique_ptr<packet::BasePacketBuilder> LeCreditBasedDataController::GetNextPacket() {
+ auto next = std::move(pdu_queue_.front());
+ pdu_queue_.pop();
+ return next;
+}
+
+void LeCreditBasedDataController::SetMtu(Mtu mtu) {
+ mtu_ = mtu;
+}
+
+void LeCreditBasedDataController::SetMps(uint16_t mps) {
+ mps_ = mps;
+}
+
+void LeCreditBasedDataController::OnCredit(uint16_t credits) {
+ int total_credits = credits_ + credits;
+ credits_ = total_credits > 0xffff ? 0xffff : total_credits;
+}
+
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/le_credit_based_channel_data_controller.h b/gd/l2cap/internal/le_credit_based_channel_data_controller.h
new file mode 100644
index 0000000..9374cd6
--- /dev/null
+++ b/gd/l2cap/internal/le_credit_based_channel_data_controller.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <unordered_map>
+#include <utility>
+
+#include "common/bidi_queue.h"
+#include "l2cap/cid.h"
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/internal/data_controller.h"
+#include "l2cap/internal/scheduler.h"
+#include "l2cap/l2cap_packets.h"
+#include "l2cap/mtu.h"
+#include "os/handler.h"
+#include "os/queue.h"
+#include "packet/base_packet_builder.h"
+#include "packet/packet_view.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+class LeCreditBasedDataController : public DataController {
+ public:
+ using UpperEnqueue = packet::PacketView<packet::kLittleEndian>;
+ using UpperDequeue = packet::BasePacketBuilder;
+ using UpperQueueDownEnd = common::BidiQueueEnd<UpperEnqueue, UpperDequeue>;
+ LeCreditBasedDataController(Cid cid, Cid remote_cid, UpperQueueDownEnd* channel_queue_end, os::Handler* handler,
+ Scheduler* scheduler);
+
+ void OnSdu(std::unique_ptr<packet::BasePacketBuilder> sdu) override;
+ void OnPdu(packet::PacketView<true> pdu) override;
+ std::unique_ptr<packet::BasePacketBuilder> GetNextPacket() override;
+
+ void EnableFcs(bool enabled) override {}
+ void SetRetransmissionAndFlowControlOptions(const RetransmissionAndFlowControlConfigurationOption& option) override {}
+
+ // TODO: Set MTU and MPS from signalling channel
+ void SetMtu(Mtu mtu);
+ void SetMps(uint16_t mps);
+ // TODO: Handle credits
+ void OnCredit(uint16_t credits);
+
+ private:
+ Cid cid_;
+ Cid remote_cid_;
+ os::EnqueueBuffer<UpperEnqueue> enqueue_buffer_;
+ os::Handler* handler_;
+ std::queue<std::unique_ptr<packet::BasePacketBuilder>> pdu_queue_;
+ Scheduler* scheduler_;
+ Mtu mtu_ = 512;
+ uint16_t mps_ = 251;
+ uint16_t credits_ = 0;
+
+ class PacketViewForReassembly : public packet::PacketView<kLittleEndian> {
+ public:
+ PacketViewForReassembly(const PacketView& packetView) : PacketView(packetView) {}
+ void AppendPacketView(packet::PacketView<kLittleEndian> to_append) {
+ Append(to_append);
+ }
+ };
+ PacketViewForReassembly reassembly_stage_{std::make_shared<std::vector<uint8_t>>()};
+ uint16_t remaining_sdu_continuation_packet_size_ = 0;
+};
+
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/le_credit_based_channel_data_controller_test.cc b/gd/l2cap/internal/le_credit_based_channel_data_controller_test.cc
new file mode 100644
index 0000000..071e976
--- /dev/null
+++ b/gd/l2cap/internal/le_credit_based_channel_data_controller_test.cc
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2019 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 "l2cap/internal/le_credit_based_channel_data_controller.h"
+
+#include <gtest/gtest.h>
+
+#include "l2cap/internal/scheduler_mock.h"
+#include "l2cap/l2cap_packets.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+namespace {
+
+std::unique_ptr<packet::BasePacketBuilder> CreateSdu(std::vector<uint8_t> payload) {
+ auto raw_builder = std::make_unique<packet::RawBuilder>();
+ raw_builder->AddOctets(payload);
+ return raw_builder;
+}
+
+PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+ auto bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter i(*bytes);
+ bytes->reserve(packet->size());
+ packet->Serialize(i);
+ return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+void sync_handler(os::Handler* handler) {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+ auto status = future.wait_for(std::chrono::milliseconds(300));
+ EXPECT_EQ(status, std::future_status::ready);
+}
+
+class LeCreditBasedDataControllerTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+ user_handler_ = new os::Handler(thread_);
+ queue_handler_ = new os::Handler(thread_);
+ }
+
+ void TearDown() override {
+ queue_handler_->Clear();
+ user_handler_->Clear();
+ delete queue_handler_;
+ delete user_handler_;
+ delete thread_;
+ }
+
+ os::Thread* thread_ = nullptr;
+ os::Handler* user_handler_ = nullptr;
+ os::Handler* queue_handler_ = nullptr;
+};
+
+TEST_F(LeCreditBasedDataControllerTest, transmit_unsegmented) {
+ common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10};
+ testing::MockScheduler scheduler;
+ LeCreditBasedDataController controller{0x41, 0x41, channel_queue.GetDownEnd(), queue_handler_, &scheduler};
+ EXPECT_CALL(scheduler, OnPacketsReady(0x41, 1));
+ controller.OnSdu(CreateSdu({'a', 'b', 'c', 'd'}));
+ auto next_packet = controller.GetNextPacket();
+ EXPECT_NE(next_packet, nullptr);
+ auto view = GetPacketView(std::move(next_packet));
+ auto pdu_view = BasicFrameView::Create(view);
+ EXPECT_TRUE(pdu_view.IsValid());
+ auto first_le_info_view = FirstLeInformationFrameView::Create(pdu_view);
+ EXPECT_TRUE(first_le_info_view.IsValid());
+ auto payload = first_le_info_view.GetPayload();
+ std::string data = std::string(payload.begin(), payload.end());
+ EXPECT_EQ(data, "abcd");
+}
+
+TEST_F(LeCreditBasedDataControllerTest, transmit_segmented) {
+ common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10};
+ testing::MockScheduler scheduler;
+ LeCreditBasedDataController controller{0x41, 0x41, channel_queue.GetDownEnd(), queue_handler_, &scheduler};
+ controller.SetMps(4);
+ EXPECT_CALL(scheduler, OnPacketsReady(0x41, 2));
+ // Should be divided into 'ab', and 'cd'
+ controller.OnSdu(CreateSdu({'a', 'b', 'c', 'd'}));
+ auto next_packet = controller.GetNextPacket();
+ EXPECT_NE(next_packet, nullptr);
+ auto view = GetPacketView(std::move(next_packet));
+ auto pdu_view = BasicFrameView::Create(view);
+ EXPECT_TRUE(pdu_view.IsValid());
+ auto first_le_info_view = FirstLeInformationFrameView::Create(pdu_view);
+ EXPECT_TRUE(first_le_info_view.IsValid());
+ auto payload = first_le_info_view.GetPayload();
+ std::string data = std::string(payload.begin(), payload.end());
+ EXPECT_EQ(data, "ab");
+ EXPECT_EQ(first_le_info_view.GetL2capSduLength(), 4);
+
+ next_packet = controller.GetNextPacket();
+ EXPECT_NE(next_packet, nullptr);
+ view = GetPacketView(std::move(next_packet));
+ pdu_view = BasicFrameView::Create(view);
+ EXPECT_TRUE(pdu_view.IsValid());
+ payload = pdu_view.GetPayload();
+ data = std::string(payload.begin(), payload.end());
+ EXPECT_EQ(data, "cd");
+}
+
+TEST_F(LeCreditBasedDataControllerTest, receive_unsegmented) {
+ common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10};
+ testing::MockScheduler scheduler;
+ LeCreditBasedDataController controller{0x41, 0x41, channel_queue.GetDownEnd(), queue_handler_, &scheduler};
+ auto segment = CreateSdu({'a', 'b', 'c', 'd'});
+ auto builder = FirstLeInformationFrameBuilder::Create(0x41, 4, std::move(segment));
+ auto base_view = GetPacketView(std::move(builder));
+ controller.OnPdu(base_view);
+ sync_handler(queue_handler_);
+ auto payload = channel_queue.GetUpEnd()->TryDequeue();
+ EXPECT_NE(payload, nullptr);
+ std::string data = std::string(payload->begin(), payload->end());
+ EXPECT_EQ(data, "abcd");
+}
+
+TEST_F(LeCreditBasedDataControllerTest, receive_segmented) {
+ common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10};
+ testing::MockScheduler scheduler;
+ LeCreditBasedDataController controller{0x41, 0x41, channel_queue.GetDownEnd(), queue_handler_, &scheduler};
+ auto segment1 = CreateSdu({'a', 'b', 'c', 'd'});
+ auto builder1 = FirstLeInformationFrameBuilder::Create(0x41, 7, std::move(segment1));
+ auto base_view = GetPacketView(std::move(builder1));
+ controller.OnPdu(base_view);
+ auto segment2 = CreateSdu({'e', 'f', 'g'});
+ auto builder2 = BasicFrameBuilder::Create(0x41, std::move(segment2));
+ base_view = GetPacketView(std::move(builder2));
+ controller.OnPdu(base_view);
+ sync_handler(queue_handler_);
+ auto payload = channel_queue.GetUpEnd()->TryDequeue();
+ EXPECT_NE(payload, nullptr);
+ std::string data = std::string(payload->begin(), payload->end());
+ EXPECT_EQ(data, "abcdefg");
+}
+
+TEST_F(LeCreditBasedDataControllerTest, receive_segmented_with_wrong_sdu_length) {
+ common::BidiQueue<Scheduler::UpperEnqueue, Scheduler::UpperDequeue> channel_queue{10};
+ testing::MockScheduler scheduler;
+ LeCreditBasedDataController controller{0x41, 0x41, channel_queue.GetDownEnd(), queue_handler_, &scheduler};
+ auto segment1 = CreateSdu({'a', 'b', 'c', 'd'});
+ auto builder1 = FirstLeInformationFrameBuilder::Create(0x41, 5, std::move(segment1));
+ auto base_view = GetPacketView(std::move(builder1));
+ controller.OnPdu(base_view);
+ auto segment2 = CreateSdu({'e', 'f', 'g'});
+ auto builder2 = BasicFrameBuilder::Create(0x41, std::move(segment2));
+ base_view = GetPacketView(std::move(builder2));
+ controller.OnPdu(base_view);
+ sync_handler(queue_handler_);
+ auto payload = channel_queue.GetUpEnd()->TryDequeue();
+ EXPECT_EQ(payload, nullptr);
+}
+
+} // namespace
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/parameter_provider.h b/gd/l2cap/internal/parameter_provider.h
new file mode 100644
index 0000000..e1db944
--- /dev/null
+++ b/gd/l2cap/internal/parameter_provider.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <chrono>
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+/**
+ * A class that provide constant parameters to the L2CAP stack
+ *
+ * All methods are virtual so that they can be override in unit tests
+ */
+class ParameterProvider {
+ public:
+ virtual ~ParameterProvider() = default;
+ virtual std::chrono::milliseconds GetClassicLinkIdleDisconnectTimeout() {
+ return std::chrono::seconds(20);
+ }
+ virtual std::chrono::milliseconds GetLeLinkIdleDisconnectTimeout() {
+ return std::chrono::seconds(20);
+ }
+};
+
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/parameter_provider_mock.h b/gd/l2cap/internal/parameter_provider_mock.h
new file mode 100644
index 0000000..823cf8a
--- /dev/null
+++ b/gd/l2cap/internal/parameter_provider_mock.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include "l2cap/internal/parameter_provider.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+namespace testing {
+
+class MockParameterProvider : public ParameterProvider {
+ public:
+ MOCK_METHOD(std::chrono::milliseconds, GetClassicLinkIdleDisconnectTimeout, (), (override));
+ MOCK_METHOD(std::chrono::milliseconds, GetLeLinkIdleDisconnectTimeout, (), (override));
+};
+
+} // namespace testing
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/internal/receiver.cc b/gd/l2cap/internal/receiver.cc
new file mode 100644
index 0000000..86f43ae
--- /dev/null
+++ b/gd/l2cap/internal/receiver.cc
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2019 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 "l2cap/internal/receiver.h"
+
+#include "common/bidi_queue.h"
+#include "l2cap/cid.h"
+#include "l2cap/internal/data_pipeline_manager.h"
+#include "l2cap/l2cap_packets.h"
+#include "packet/packet_view.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+Receiver::Receiver(LowerQueueUpEnd* link_queue_up_end, os::Handler* handler,
+ DataPipelineManager* data_pipeline_manager_)
+ : link_queue_up_end_(link_queue_up_end), handler_(handler), data_pipeline_manager_(data_pipeline_manager_) {
+ ASSERT(link_queue_up_end_ != nullptr && handler_ != nullptr);
+ link_queue_up_end_->RegisterDequeue(handler_,
+ common::Bind(&Receiver::link_queue_dequeue_callback, common::Unretained(this)));
+}
+
+Receiver::~Receiver() {
+ link_queue_up_end_->UnregisterDequeue();
+}
+
+void Receiver::link_queue_dequeue_callback() {
+ auto packet = link_queue_up_end_->TryDequeue();
+ auto basic_frame_view = BasicFrameView::Create(*packet);
+ if (!basic_frame_view.IsValid()) {
+ LOG_WARN("Received an invalid basic frame");
+ return;
+ }
+ Cid cid = static_cast<Cid>(basic_frame_view.GetChannelId());
+ auto* data_controller = data_pipeline_manager_->GetDataController(cid);
+ if (data_controller == nullptr) {
+ LOG_WARN("Received a packet with invalid cid: %d", cid);
+ return;
+ }
+ data_controller->OnPdu(*packet);
+}
+
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/receiver.h b/gd/l2cap/internal/receiver.h
new file mode 100644
index 0000000..f757319
--- /dev/null
+++ b/gd/l2cap/internal/receiver.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <unordered_map>
+#include <utility>
+
+#include "common/bidi_queue.h"
+#include "l2cap/cid.h"
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/internal/scheduler.h"
+#include "l2cap/l2cap_packets.h"
+#include "l2cap/mtu.h"
+#include "os/queue.h"
+#include "packet/base_packet_builder.h"
+#include "packet/packet_view.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+class DataPipelineManager;
+
+/**
+ * Handle receiving L2CAP PDUs from link queue and distribute them into into channel data controllers.
+ * Dequeue incoming packets from LinkQueueUpEnd, and enqueue it to ChannelQueueDownEnd. Note: If a channel
+ * cannot dequeue from ChannelQueueDownEnd so that the buffer for incoming packet is full, further incoming packets will
+ * be dropped.
+ * The Reassembler keeps the reference to ChannelImpl objects, because it needs to check channel mode and parameters.
+ * The Reassembler also keeps the reference to Scheduler, to get Segmenter and send signals (Tx, Rx seq) to it.
+ */
+class Receiver {
+ public:
+ using UpperEnqueue = packet::PacketView<packet::kLittleEndian>;
+ using UpperDequeue = packet::BasePacketBuilder;
+ using UpperQueueDownEnd = common::BidiQueueEnd<UpperEnqueue, UpperDequeue>;
+ using LowerEnqueue = UpperDequeue;
+ using LowerDequeue = UpperEnqueue;
+ using LowerQueueUpEnd = common::BidiQueueEnd<LowerEnqueue, LowerDequeue>;
+
+ Receiver(LowerQueueUpEnd* link_queue_up_end, os::Handler* handler, DataPipelineManager* data_pipeline_manager);
+ ~Receiver();
+
+ private:
+ LowerQueueUpEnd* link_queue_up_end_;
+ os::Handler* handler_;
+ DataPipelineManager* data_pipeline_manager_;
+
+ void link_queue_dequeue_callback();
+};
+
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/receiver_test.cc b/gd/l2cap/internal/receiver_test.cc
new file mode 100644
index 0000000..a401d22
--- /dev/null
+++ b/gd/l2cap/internal/receiver_test.cc
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2019 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 "l2cap/internal/receiver.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <future>
+
+#include "l2cap/internal/channel_impl_mock.h"
+#include "l2cap/l2cap_packets.h"
+#include "os/handler.h"
+#include "os/queue.h"
+#include "os/thread.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+namespace {} // namespace
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/scheduler.h b/gd/l2cap/internal/scheduler.h
new file mode 100644
index 0000000..416c972
--- /dev/null
+++ b/gd/l2cap/internal/scheduler.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include "common/bidi_queue.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic/dynamic_channel_configuration_option.h"
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/internal/data_controller.h"
+#include "l2cap/internal/sender.h"
+#include "l2cap/l2cap_packets.h"
+#include "packet/base_packet_builder.h"
+#include "packet/packet_view.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+/**
+ * Handle the scheduling of packets through the l2cap stack.
+ * For each attached channel, dequeue its outgoing packets and enqueue it to the given LinkQueueUpEnd, according to some
+ * policy (cid).
+ *
+ * Note: If a channel cannot dequeue from ChannelQueueDownEnd so that the buffer for incoming packet is full, further
+ * incoming packets will be dropped.
+ */
+class Scheduler {
+ public:
+ using UpperEnqueue = packet::PacketView<packet::kLittleEndian>;
+ using UpperDequeue = packet::BasePacketBuilder;
+ using UpperQueueDownEnd = common::BidiQueueEnd<UpperEnqueue, UpperDequeue>;
+ using LowerEnqueue = UpperDequeue;
+ using LowerDequeue = UpperEnqueue;
+ using LowerQueueUpEnd = common::BidiQueueEnd<LowerEnqueue, LowerDequeue>;
+
+ /**
+ * Callback from the sender to indicate that the scheduler could dequeue number_packets from it
+ */
+ virtual void OnPacketsReady(Cid cid, int number_packets) {}
+
+ virtual ~Scheduler() = default;
+};
+
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/scheduler_fifo.cc b/gd/l2cap/internal/scheduler_fifo.cc
new file mode 100644
index 0000000..5e89c01
--- /dev/null
+++ b/gd/l2cap/internal/scheduler_fifo.cc
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2019 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 "l2cap/internal/scheduler_fifo.h"
+
+#include "l2cap/classic/internal/dynamic_channel_impl.h"
+#include "l2cap/internal/data_pipeline_manager.h"
+#include "l2cap/l2cap_packets.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+Fifo::Fifo(DataPipelineManager* data_pipeline_manager, LowerQueueUpEnd* link_queue_up_end, os::Handler* handler)
+ : data_pipeline_manager_(data_pipeline_manager), link_queue_up_end_(link_queue_up_end), handler_(handler) {
+ ASSERT(link_queue_up_end_ != nullptr && handler_ != nullptr);
+}
+
+Fifo::~Fifo() {
+ if (link_queue_enqueue_registered_) {
+ link_queue_up_end_->UnregisterEnqueue();
+ }
+}
+
+void Fifo::OnPacketsReady(Cid cid, int number_packets) {
+ next_to_dequeue_and_num_packets.push(std::make_pair(cid, number_packets));
+ try_register_link_queue_enqueue();
+}
+
+std::unique_ptr<Fifo::UpperDequeue> Fifo::link_queue_enqueue_callback() {
+ ASSERT(!next_to_dequeue_and_num_packets.empty());
+ auto& channel_id_and_number_packets = next_to_dequeue_and_num_packets.front();
+ auto channel_id = channel_id_and_number_packets.first;
+ channel_id_and_number_packets.second--;
+ if (channel_id_and_number_packets.second == 0) {
+ next_to_dequeue_and_num_packets.pop();
+ }
+ auto packet = data_pipeline_manager_->GetDataController(channel_id)->GetNextPacket();
+
+ data_pipeline_manager_->OnPacketSent(channel_id);
+ if (next_to_dequeue_and_num_packets.empty()) {
+ link_queue_up_end_->UnregisterEnqueue();
+ link_queue_enqueue_registered_ = false;
+ }
+ return packet;
+}
+
+void Fifo::try_register_link_queue_enqueue() {
+ if (link_queue_enqueue_registered_) {
+ return;
+ }
+ link_queue_up_end_->RegisterEnqueue(handler_,
+ common::Bind(&Fifo::link_queue_enqueue_callback, common::Unretained(this)));
+ link_queue_enqueue_registered_ = true;
+}
+
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/scheduler_fifo.h b/gd/l2cap/internal/scheduler_fifo.h
new file mode 100644
index 0000000..f6fcf7f
--- /dev/null
+++ b/gd/l2cap/internal/scheduler_fifo.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <string>
+#include <unordered_map>
+
+#include "common/bidi_queue.h"
+#include "common/bind.h"
+#include "l2cap/cid.h"
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/internal/scheduler.h"
+#include "l2cap/internal/sender.h"
+#include "os/handler.h"
+#include "os/queue.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+class DataPipelineManager;
+
+class Fifo : public Scheduler {
+ public:
+ Fifo(DataPipelineManager* data_pipeline_manager, LowerQueueUpEnd* link_queue_up_end, os::Handler* handler);
+ ~Fifo() override;
+ void OnPacketsReady(Cid cid, int number_packets) override;
+
+ private:
+ DataPipelineManager* data_pipeline_manager_;
+ LowerQueueUpEnd* link_queue_up_end_;
+ os::Handler* handler_;
+ std::queue<std::pair<Cid, int>> next_to_dequeue_and_num_packets;
+ bool link_queue_enqueue_registered_ = false;
+
+ void try_register_link_queue_enqueue();
+ std::unique_ptr<LowerEnqueue> link_queue_enqueue_callback();
+};
+
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/scheduler_fifo_test.cc b/gd/l2cap/internal/scheduler_fifo_test.cc
new file mode 100644
index 0000000..cafd3b6
--- /dev/null
+++ b/gd/l2cap/internal/scheduler_fifo_test.cc
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2019 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 "l2cap/internal/scheduler_fifo.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <future>
+
+#include "l2cap/internal/channel_impl_mock.h"
+#include "l2cap/internal/data_controller_mock.h"
+#include "l2cap/internal/data_pipeline_manager_mock.h"
+#include "os/handler.h"
+#include "os/queue.h"
+#include "os/thread.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+namespace {
+
+using ::testing::_;
+using ::testing::Return;
+
+std::unique_ptr<packet::BasePacketBuilder> CreateSdu(std::vector<uint8_t> payload) {
+ auto raw_builder = std::make_unique<packet::RawBuilder>();
+ raw_builder->AddOctets(payload);
+ return raw_builder;
+}
+
+PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+ auto bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter i(*bytes);
+ bytes->reserve(packet->size());
+ packet->Serialize(i);
+ return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+void sync_handler(os::Handler* handler) {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+ auto status = future.wait_for(std::chrono::milliseconds(300));
+ EXPECT_EQ(status, std::future_status::ready);
+}
+
+class MyDataController : public testing::MockDataController {
+ public:
+ std::unique_ptr<BasePacketBuilder> GetNextPacket() override {
+ return std::move(next_packet);
+ }
+
+ std::unique_ptr<BasePacketBuilder> next_packet;
+};
+
+class L2capSchedulerFifoTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+ user_handler_ = new os::Handler(thread_);
+ queue_handler_ = new os::Handler(thread_);
+ mock_data_pipeline_manager_ = new testing::MockDataPipelineManager(queue_handler_, link_queue_.GetUpEnd());
+ fifo_ = new Fifo(mock_data_pipeline_manager_, link_queue_.GetUpEnd(), queue_handler_);
+ }
+
+ void TearDown() override {
+ delete fifo_;
+ delete mock_data_pipeline_manager_;
+ queue_handler_->Clear();
+ user_handler_->Clear();
+ delete queue_handler_;
+ delete user_handler_;
+ delete thread_;
+ }
+
+ os::Thread* thread_ = nullptr;
+ os::Handler* user_handler_ = nullptr;
+ os::Handler* queue_handler_ = nullptr;
+ common::BidiQueue<Scheduler::LowerDequeue, Scheduler::LowerEnqueue> link_queue_{10};
+ testing::MockDataPipelineManager* mock_data_pipeline_manager_ = nullptr;
+ MyDataController data_controller_;
+ Fifo* fifo_ = nullptr;
+};
+
+TEST_F(L2capSchedulerFifoTest, send_packet) {
+ auto frame = BasicFrameBuilder::Create(1, CreateSdu({'a', 'b', 'c'}));
+ data_controller_.next_packet = std::move(frame);
+ EXPECT_CALL(*mock_data_pipeline_manager_, GetDataController(_)).WillOnce(Return(&data_controller_));
+ EXPECT_CALL(*mock_data_pipeline_manager_, OnPacketSent(1));
+ fifo_->OnPacketsReady(1, 1);
+ sync_handler(queue_handler_);
+ sync_handler(user_handler_);
+ auto packet = link_queue_.GetDownEnd()->TryDequeue();
+ auto packet_view = GetPacketView(std::move(packet));
+ auto basic_frame_view = BasicFrameView::Create(packet_view);
+ EXPECT_TRUE(basic_frame_view.IsValid());
+ EXPECT_EQ(basic_frame_view.GetChannelId(), 1);
+ auto payload = basic_frame_view.GetPayload();
+ EXPECT_EQ(std::string(payload.begin(), payload.end()), "abc");
+}
+
+} // namespace
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/scheduler_mock.h b/gd/l2cap/internal/scheduler_mock.h
new file mode 100644
index 0000000..c0ac4d7
--- /dev/null
+++ b/gd/l2cap/internal/scheduler_mock.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/internal/scheduler.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+namespace testing {
+
+class MockScheduler : public Scheduler {
+ public:
+ MOCK_METHOD(void, OnPacketsReady, (Cid cid, int number_packet), (override));
+};
+
+} // namespace testing
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/sender.cc b/gd/l2cap/internal/sender.cc
new file mode 100644
index 0000000..7fe1dd7
--- /dev/null
+++ b/gd/l2cap/internal/sender.cc
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2019 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 <string>
+#include <unordered_map>
+
+#include "common/bind.h"
+#include "l2cap/cid.h"
+#include "l2cap/classic/internal/dynamic_channel_impl.h"
+#include "l2cap/internal/basic_mode_channel_data_controller.h"
+#include "l2cap/internal/enhanced_retransmission_mode_channel_data_controller.h"
+#include "l2cap/internal/scheduler.h"
+#include "l2cap/internal/sender.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "os/queue.h"
+#include "packet/base_packet_builder.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+
+Sender::Sender(os::Handler* handler, Scheduler* scheduler, std::shared_ptr<ChannelImpl> channel)
+ : handler_(handler), queue_end_(channel->GetQueueDownEnd()), scheduler_(scheduler), channel_id_(channel->GetCid()),
+ remote_channel_id_(channel->GetRemoteCid()),
+ data_controller_(std::make_unique<BasicModeDataController>(channel_id_, remote_channel_id_, queue_end_, handler_,
+ scheduler_)) {
+ try_register_dequeue();
+}
+
+Sender::~Sender() {
+ if (is_dequeue_registered_) {
+ queue_end_->UnregisterDequeue();
+ }
+}
+
+void Sender::OnPacketSent() {
+ try_register_dequeue();
+}
+
+std::unique_ptr<Sender::UpperDequeue> Sender::GetNextPacket() {
+ return data_controller_->GetNextPacket();
+}
+
+void Sender::SetChannelRetransmissionFlowControlMode(const RetransmissionAndFlowControlConfigurationOption& option) {
+ if (mode_ == option.mode_) {
+ return;
+ }
+ if (option.mode_ == RetransmissionAndFlowControlModeOption::L2CAP_BASIC) {
+ data_controller_ =
+ std::make_unique<BasicModeDataController>(channel_id_, remote_channel_id_, queue_end_, handler_, scheduler_);
+ return;
+ }
+ if (option.mode_ == RetransmissionAndFlowControlModeOption::ENHANCED_RETRANSMISSION) {
+ data_controller_ =
+ std::make_unique<ErtmController>(channel_id_, remote_channel_id_, queue_end_, handler_, scheduler_);
+ data_controller_->SetRetransmissionAndFlowControlOptions(option);
+ return;
+ }
+}
+
+void Sender::SetFcsType(FcsType fcs_type) {
+ // TODO: FCS is enabled when "not both side explicitly disable it".
+ data_controller_->EnableFcs(fcs_type == FcsType::DEFAULT);
+}
+
+void Sender::SetIncomingMtu(Mtu mtu) {
+ // TODO: Enforce MTU
+}
+
+DataController* Sender::GetDataController() {
+ return data_controller_.get();
+}
+
+void Sender::try_register_dequeue() {
+ if (is_dequeue_registered_) {
+ return;
+ }
+ queue_end_->RegisterDequeue(handler_, common::Bind(&Sender::dequeue_callback, common::Unretained(this)));
+ is_dequeue_registered_ = true;
+}
+
+void Sender::dequeue_callback() {
+ auto packet = queue_end_->TryDequeue();
+ ASSERT(packet != nullptr);
+ data_controller_->OnSdu(std::move(packet));
+ queue_end_->UnregisterDequeue();
+ is_dequeue_registered_ = false;
+}
+
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/sender.h b/gd/l2cap/internal/sender.h
new file mode 100644
index 0000000..850a88d
--- /dev/null
+++ b/gd/l2cap/internal/sender.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <string>
+#include <unordered_map>
+
+#include "common/bidi_queue.h"
+#include "common/bind.h"
+#include "data_controller.h"
+#include "l2cap/cid.h"
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/internal/data_controller.h"
+#include "l2cap/l2cap_packets.h"
+#include "l2cap/mtu.h"
+#include "os/handler.h"
+#include "os/queue.h"
+#include "packet/base_packet_builder.h"
+#include "packet/packet_view.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+class Scheduler;
+
+/**
+ * A middle layer between L2CAP channel and outgoing packet scheduler.
+ * Fetches data (SDU) from an L2CAP channel queue end, handles L2CAP segmentation, and gives data to L2CAP scheduler.
+ */
+class Sender {
+ public:
+ using UpperEnqueue = packet::PacketView<packet::kLittleEndian>;
+ using UpperDequeue = packet::BasePacketBuilder;
+ using UpperQueueDownEnd = common::BidiQueueEnd<UpperEnqueue, UpperDequeue>;
+
+ Sender(os::Handler* handler, Scheduler* scheduler, std::shared_ptr<ChannelImpl> channel);
+ ~Sender();
+
+ /**
+ * Callback from scheduler to indicate that scheduler already dequeued a packet from sender's queue.
+ * Segmenter can continue dequeuing from channel queue end.
+ */
+ void OnPacketSent();
+
+ /**
+ * Called by the scheduler to return the next PDU to be sent
+ */
+ std::unique_ptr<UpperDequeue> GetNextPacket();
+
+ void SetChannelRetransmissionFlowControlMode(const RetransmissionAndFlowControlConfigurationOption& option);
+ void SetFcsType(FcsType fcs_type);
+ void SetIncomingMtu(Mtu mtu);
+
+ DataController* GetDataController();
+
+ private:
+ os::Handler* handler_;
+ UpperQueueDownEnd* queue_end_;
+ Scheduler* scheduler_;
+ const Cid channel_id_;
+ const Cid remote_channel_id_;
+ bool is_dequeue_registered_ = false;
+ RetransmissionAndFlowControlModeOption mode_ = RetransmissionAndFlowControlModeOption::L2CAP_BASIC;
+ std::unique_ptr<DataController> data_controller_;
+
+ void try_register_dequeue();
+ void dequeue_callback();
+};
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/internal/sender_test.cc b/gd/l2cap/internal/sender_test.cc
new file mode 100644
index 0000000..cecdfa4
--- /dev/null
+++ b/gd/l2cap/internal/sender_test.cc
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2019 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 "l2cap/internal/sender.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <future>
+
+#include "l2cap/internal/channel_impl_mock.h"
+#include "l2cap/internal/scheduler.h"
+#include "os/handler.h"
+#include "os/queue.h"
+#include "os/thread.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace internal {
+namespace {
+
+using ::testing::Return;
+
+std::unique_ptr<packet::BasePacketBuilder> CreateSdu(std::vector<uint8_t> payload) {
+ auto raw_builder = std::make_unique<packet::RawBuilder>();
+ raw_builder->AddOctets(payload);
+ return raw_builder;
+}
+
+PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+ auto bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter i(*bytes);
+ bytes->reserve(packet->size());
+ packet->Serialize(i);
+ return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+class FakeScheduler : public Scheduler {
+ public:
+ void OnPacketsReady(Cid cid, int number_packets) override {
+ on_packets_ready_(cid, number_packets);
+ }
+
+ void SetOnPacketsReady(std::function<void(Cid cid, int number_packets)> callback) {
+ on_packets_ready_ = callback;
+ }
+ std::function<void(Cid cid, int number_packets)> on_packets_ready_;
+};
+
+class L2capSenderTest : public ::testing::Test {
+ public:
+ std::unique_ptr<Sender::UpperDequeue> enqueue_callback() {
+ auto packet_one = CreateSdu({'a', 'b', 'c'});
+ channel_queue_.GetUpEnd()->UnregisterEnqueue();
+ return packet_one;
+ }
+
+ protected:
+ void SetUp() override {
+ thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+ user_handler_ = new os::Handler(thread_);
+ queue_handler_ = new os::Handler(thread_);
+ mock_channel_ = std::make_shared<testing::MockChannelImpl>();
+ EXPECT_CALL(*mock_channel_, GetQueueDownEnd()).WillRepeatedly(Return(channel_queue_.GetDownEnd()));
+ EXPECT_CALL(*mock_channel_, GetCid()).WillRepeatedly(Return(cid_));
+ EXPECT_CALL(*mock_channel_, GetRemoteCid()).WillRepeatedly(Return(cid_));
+ sender_ = new Sender(queue_handler_, &scheduler_, mock_channel_);
+ }
+
+ void TearDown() override {
+ queue_handler_->Clear();
+ user_handler_->Clear();
+ delete sender_;
+ delete queue_handler_;
+ delete user_handler_;
+ delete thread_;
+ }
+
+ os::Thread* thread_ = nullptr;
+ os::Handler* user_handler_ = nullptr;
+ os::Handler* queue_handler_ = nullptr;
+ common::BidiQueue<Sender::UpperEnqueue, Sender::UpperDequeue> channel_queue_{10};
+ std::shared_ptr<testing::MockChannelImpl> mock_channel_;
+ Sender* sender_ = nullptr;
+ Cid cid_ = 0x41;
+ FakeScheduler scheduler_;
+};
+
+TEST_F(L2capSenderTest, send_packet) {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ scheduler_.SetOnPacketsReady([&promise](Cid cid, int number_packets) { promise.set_value(); });
+ channel_queue_.GetUpEnd()->RegisterEnqueue(
+ queue_handler_, common::Bind(&L2capSenderTest::enqueue_callback, common::Unretained(this)));
+ auto status = future.wait_for(std::chrono::milliseconds(3));
+ EXPECT_EQ(status, std::future_status::ready);
+ auto packet = sender_->GetNextPacket();
+ EXPECT_NE(packet, nullptr);
+ auto packet_view = GetPacketView(std::move(packet));
+ auto basic_frame_view = BasicFrameView::Create(packet_view);
+ EXPECT_TRUE(basic_frame_view.IsValid());
+ EXPECT_EQ(basic_frame_view.GetChannelId(), cid_);
+ auto payload = basic_frame_view.GetPayload();
+ std::string payload_string(payload.begin(), payload.end());
+ EXPECT_EQ(payload_string, "abc");
+}
+
+} // namespace
+} // namespace internal
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/l2cap_packet_fuzz_test.cc b/gd/l2cap/l2cap_packet_fuzz_test.cc
new file mode 100644
index 0000000..6fecafc
--- /dev/null
+++ b/gd/l2cap/l2cap_packet_fuzz_test.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#define PACKET_FUZZ_TESTING
+#include "l2cap/l2cap_packets.h"
+
+#include <memory>
+
+#include "os/log.h"
+#include "packet/bit_inserter.h"
+#include "packet/raw_builder.h"
+
+using bluetooth::packet::BitInserter;
+using bluetooth::packet::RawBuilder;
+using std::vector;
+
+namespace bluetooth {
+namespace l2cap {
+
+std::vector<void (*)(const uint8_t*, size_t)> l2cap_packet_fuzz_tests;
+
+DEFINE_AND_REGISTER_ExtendedInformationStartFrameReflectionFuzzTest(l2cap_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_StandardInformationFrameWithFcsReflectionFuzzTest(l2cap_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_StandardSupervisoryFrameWithFcsReflectionFuzzTest(l2cap_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_GroupFrameReflectionFuzzTest(l2cap_packet_fuzz_tests);
+
+DEFINE_AND_REGISTER_ConfigurationRequestReflectionFuzzTest(l2cap_packet_fuzz_tests);
+
+} // namespace l2cap
+} // namespace bluetooth
+
+void RunL2capPacketFuzzTest(const uint8_t* data, size_t size) {
+ if (data == nullptr) return;
+ for (auto test_function : bluetooth::l2cap::l2cap_packet_fuzz_tests) {
+ test_function(data, size);
+ }
+}
\ No newline at end of file
diff --git a/gd/l2cap/l2cap_packet_test.cc b/gd/l2cap/l2cap_packet_test.cc
new file mode 100644
index 0000000..36b8791
--- /dev/null
+++ b/gd/l2cap/l2cap_packet_test.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#define PACKET_TESTING
+#include "l2cap/l2cap_packets.h"
+
+#include <gtest/gtest.h>
+#include <forward_list>
+#include <memory>
+
+#include "os/log.h"
+#include "packet/bit_inserter.h"
+#include "packet/raw_builder.h"
+
+using bluetooth::packet::BitInserter;
+using bluetooth::packet::RawBuilder;
+using std::vector;
+
+namespace bluetooth {
+namespace l2cap {
+
+std::vector<uint8_t> extended_information_start_frame = {
+ 0x0B, /* First size byte */
+ 0x00, /* Second size byte */
+ 0xc1, /* First ChannelId byte */
+ 0xc2, /**/
+ 0x4A, /* 0x12 ReqSeq, Final, IFrame */
+ 0xD0, /* 0x13 ReqSeq */
+ 0x89, /* 0x21 TxSeq sar = START */
+ 0x8C, /* 0x23 TxSeq */
+ 0x10, /* first length byte */
+ 0x11, /**/
+ 0x01, /* first payload byte */
+ 0x02, 0x03, 0x04, 0x05,
+};
+
+DEFINE_AND_INSTANTIATE_ExtendedInformationStartFrameReflectionTest(extended_information_start_frame);
+
+std::vector<uint8_t> i_frame_with_fcs = {0x0E, 0x00, 0x40, 0x00, 0x02, 0x00, 0x00, 0x01, 0x02,
+ 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x38, 0x61};
+DEFINE_AND_INSTANTIATE_StandardInformationFrameWithFcsReflectionTest(i_frame_with_fcs);
+
+std::vector<uint8_t> rr_frame_with_fcs = {0x04, 0x00, 0x40, 0x00, 0x01, 0x01, 0xD4, 0x14};
+DEFINE_AND_INSTANTIATE_StandardSupervisoryFrameWithFcsReflectionTest(rr_frame_with_fcs);
+
+std::vector<uint8_t> g_frame = {0x03, 0x00, 0x02, 0x00, 0x01, 0x02, 0x03};
+DEFINE_AND_INSTANTIATE_GroupFrameReflectionTest(g_frame);
+
+std::vector<uint8_t> config_mtu_request = {0x04, 0x05, 0x08, 0x00, 0x41, 0x00, 0x00, 0x00, 0x01, 0x02, 0xa0, 0x02};
+DEFINE_AND_INSTANTIATE_ConfigurationRequestReflectionTest(config_mtu_request);
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/l2cap_packets.pdl b/gd/l2cap/l2cap_packets.pdl
new file mode 100644
index 0000000..ae44cb1
--- /dev/null
+++ b/gd/l2cap/l2cap_packets.pdl
@@ -0,0 +1,631 @@
+little_endian_packets
+
+checksum Fcs : 16 "l2cap/"
+
+packet BasicFrame {
+ _size_(_payload_) : 16,
+ channel_id : 16,
+ _payload_,
+}
+
+packet BasicFrameWithFcs {
+ _checksum_start_(fcs),
+ _size_(_payload_) : 16,
+ channel_id : 16,
+ _payload_ : [+2*8], // Include Fcs in the _size_
+ fcs : Fcs,
+}
+
+enum Continuation : 1 {
+ END = 0,
+ CONTINUE = 1,
+}
+
+// ChannelId 2 is connectionless
+packet GroupFrame : BasicFrame (channel_id = 0x02) {
+ psm : 16,
+ _payload_,
+}
+
+enum FrameType : 1 {
+ I_FRAME = 0,
+ S_FRAME = 1,
+}
+
+enum SupervisoryFunction : 2 {
+ RECEIVER_READY = 0,
+ REJECT = 1,
+ RECEIVER_NOT_READY = 2,
+ SELECT_REJECT = 3,
+}
+
+enum RetransmissionDisable : 1 {
+ NORMAL = 0,
+ DISABLE = 1,
+}
+
+enum SegmentationAndReassembly : 2 {
+ UNSEGMENTED = 0,
+ START = 1,
+ END = 2,
+ CONTINUATION = 3,
+}
+
+packet StandardFrame : BasicFrame {
+ frame_type : FrameType,
+ _body_,
+}
+
+packet StandardFrameWithFcs : BasicFrameWithFcs {
+ frame_type : FrameType,
+ _body_,
+}
+
+group StandardSupervisoryControl {
+ _fixed_ = 0 : 1,
+ s : SupervisoryFunction,
+ _reserved_ : 3,
+ r : RetransmissionDisable,
+ req_seq : 6,
+ _reserved_ : 2,
+}
+
+group StandardInformationControl {
+ tx_seq : 6,
+ r : RetransmissionDisable,
+ req_seq : 6,
+ sar : SegmentationAndReassembly,
+}
+
+packet StandardSupervisoryFrame : StandardFrame (frame_type = S_FRAME) {
+ StandardSupervisoryControl,
+}
+
+packet StandardSupervisoryFrameWithFcs : StandardFrameWithFcs (frame_type = S_FRAME) {
+ StandardSupervisoryControl,
+}
+
+packet StandardInformationFrame : StandardFrame (frame_type = I_FRAME) {
+ StandardInformationControl,
+ _payload_,
+}
+
+packet StandardInformationFrameWithFcs : StandardFrameWithFcs (frame_type = I_FRAME) {
+ StandardInformationControl,
+ _payload_,
+}
+
+packet StandardInformationStartFrame : StandardInformationFrame (sar = START) {
+ l2cap_sdu_length : 16,
+ _payload_,
+}
+
+packet StandardInformationStartFrameWithFcs : StandardInformationFrameWithFcs (sar = START) {
+ l2cap_sdu_length : 16,
+ _payload_,
+}
+
+enum Poll : 1 {
+ NOT_SET = 0,
+ POLL = 1,
+}
+
+enum Final : 1 {
+ NOT_SET = 0,
+ POLL_RESPONSE = 1,
+}
+
+group EnhancedSupervisoryControl {
+ _fixed_ = 0 : 1,
+ s : SupervisoryFunction,
+ p : Poll,
+ _reserved_ : 2,
+ f : Final,
+ req_seq : 6,
+ _reserved_ : 2,
+}
+
+group EnhancedInformationControl {
+ tx_seq : 6,
+ f : Final,
+ req_seq : 6,
+ sar : SegmentationAndReassembly,
+}
+
+packet EnhancedSupervisoryFrame : StandardFrame (frame_type = S_FRAME) {
+ EnhancedSupervisoryControl,
+}
+
+packet EnhancedSupervisoryFrameWithFcs : StandardFrameWithFcs (frame_type = S_FRAME) {
+ EnhancedSupervisoryControl,
+}
+
+packet EnhancedInformationFrame : StandardFrame (frame_type = I_FRAME) {
+ EnhancedInformationControl,
+ _payload_,
+}
+
+packet EnhancedInformationFrameWithFcs : StandardFrameWithFcs (frame_type = I_FRAME) {
+ EnhancedInformationControl,
+ _payload_,
+}
+
+packet EnhancedInformationStartFrame : EnhancedInformationFrame (sar = START) {
+ l2cap_sdu_length : 16,
+ _payload_,
+}
+
+packet EnhancedInformationStartFrameWithFcs : EnhancedInformationFrameWithFcs (sar = START) {
+ l2cap_sdu_length : 16,
+ _payload_,
+}
+
+group ExtendedSupervisoryControl {
+ f : Final,
+ req_seq : 14,
+ s : SupervisoryFunction,
+ p : Poll,
+ _reserved_ : 5,
+ _reserved_ : 8,
+}
+
+group ExtendedInformationControl {
+ f : Final,
+ req_seq : 14,
+ sar : SegmentationAndReassembly,
+ tx_seq : 14,
+}
+
+packet ExtendedSupervisoryFrame : StandardFrame (frame_type = S_FRAME) {
+ ExtendedSupervisoryControl,
+}
+
+packet ExtendedSupervisoryFrameWithFcs : StandardFrameWithFcs (frame_type = S_FRAME) {
+ ExtendedSupervisoryControl,
+}
+
+packet ExtendedInformationFrame : StandardFrame (frame_type = I_FRAME) {
+ ExtendedInformationControl,
+ _payload_,
+}
+
+packet ExtendedInformationFrameWithFcs : StandardFrameWithFcs (frame_type = I_FRAME) {
+ ExtendedInformationControl,
+ _payload_,
+}
+
+packet ExtendedInformationStartFrame : ExtendedInformationFrame (sar = START) {
+ l2cap_sdu_length : 16,
+ _payload_,
+}
+
+packet ExtendedInformationStartFrameWithFcs : ExtendedInformationFrameWithFcs (sar = START) {
+ l2cap_sdu_length : 16,
+ _payload_,
+}
+
+packet FirstLeInformationFrame : BasicFrame {
+ l2cap_sdu_length : 16,
+ _payload_,
+}
+
+enum CommandCode : 8 {
+ COMMAND_REJECT = 0x01,
+ CONNECTION_REQUEST = 0x02,
+ CONNECTION_RESPONSE = 0x03,
+ CONFIGURATION_REQUEST = 0x04,
+ CONFIGURATION_RESPONSE = 0x05,
+ DISCONNECTION_REQUEST = 0x06,
+ DISCONNECTION_RESPONSE = 0x07,
+ ECHO_REQUEST = 0x08,
+ ECHO_RESPONSE = 0x09,
+ INFORMATION_REQUEST = 0x0A,
+ INFORMATION_RESPONSE = 0x0B,
+ CREATE_CHANNEL_REQUEST = 0x0C,
+ CREATE_CHANNEL_RESPONSE = 0x0D,
+ MOVE_CHANNEL_REQUEST = 0x0E,
+ MOVE_CHANNEL_RESPONSE = 0x0F,
+ MOVE_CHANNEL_CONFIRMATION_REQUEST = 0x10,
+ MOVE_CHANNEL_CONFIRMATION_RESPONSE = 0x11,
+}
+
+packet ControlFrame : BasicFrame (channel_id = 0x0001) {
+ _payload_,
+}
+
+packet Control {
+ code : CommandCode,
+ identifier : 8,
+ _size_(_payload_) : 16,
+ _payload_,
+}
+
+enum CommandRejectReason : 16 {
+ COMMAND_NOT_UNDERSTOOD = 0x0000,
+ SIGNALING_MTU_EXCEEDED = 0x0001,
+ INVALID_CID_IN_REQUEST = 0x0002,
+}
+
+packet CommandReject : Control (code = COMMAND_REJECT) {
+ reason : CommandRejectReason,
+ _body_,
+}
+
+packet CommandRejectNotUnderstood : CommandReject (reason = COMMAND_NOT_UNDERSTOOD) {
+}
+
+packet CommandRejectMtuExceeded : CommandReject (reason = SIGNALING_MTU_EXCEEDED) {
+ actual_mtu : 16,
+}
+
+packet CommandRejectInvalidCid : CommandReject (reason = INVALID_CID_IN_REQUEST) {
+ local_channel : 16, // Relative to the sender of the CommandReject
+ remote_channel : 16,
+}
+
+packet ConnectionRequest : Control (code = CONNECTION_REQUEST) {
+ psm : 16,
+ source_cid : 16,
+}
+
+enum ConnectionResponseResult : 16 {
+ SUCCESS = 0x0000,
+ PENDING = 0x0001,
+ PSM_NOT_SUPPORTED = 0x0002,
+ SECURITY_BLOCK = 0x0003,
+ NO_RESOURCES_AVAILABLE = 0x0004,
+ INVALID_CID = 0x0006,
+ SOURCE_CID_ALREADY_ALLOCATED = 0x0007,
+}
+
+enum ConnectionResponseStatus : 16 {
+ NO_FURTHER_INFORMATION_AVAILABLE = 0x0000,
+ AUTHENTICATION_PENDING = 0x0001,
+ AUTHORIZATION_PENDING = 0x0002,
+}
+
+packet ConnectionResponse : Control (code = CONNECTION_RESPONSE) {
+ destination_cid : 16,
+ source_cid : 16,
+ result : ConnectionResponseResult,
+ status : ConnectionResponseStatus,
+}
+
+enum ConfigurationOptionType : 7 {
+ MTU = 0x01,
+ FLUSH_TIMEOUT = 0x02,
+ QUALITY_OF_SERVICE = 0x03,
+ RETRANSMISSION_AND_FLOW_CONTROL = 0x04,
+ FRAME_CHECK_SEQUENCE = 0x05,
+ EXTENDED_FLOW_SPECIFICATION = 0x06,
+ EXTENDED_WINDOW_SIZE = 0x07,
+}
+
+enum ConfigurationOptionIsHint : 1 {
+ OPTION_MUST_BE_RECOGNIZED = 0,
+ OPTION_IS_A_HINT = 1,
+}
+
+struct ConfigurationOption {
+ type : ConfigurationOptionType,
+ is_hint : ConfigurationOptionIsHint,
+ length : 8,
+ _body_,
+}
+
+struct MtuConfigurationOption : ConfigurationOption (type = MTU, length = 2) {
+ mtu : 16,
+}
+
+struct FlushTimeoutConfigurationOption : ConfigurationOption (type = FLUSH_TIMEOUT, length = 2) {
+ flush_timeout : 16,
+}
+
+enum QosServiceType : 8 {
+ NO_TRAFFIC = 0x00,
+ BEST_EFFORT = 0x01, // Default
+ GUARANTEED = 0x02,
+}
+
+struct QualityOfServiceConfigurationOption : ConfigurationOption (type = QUALITY_OF_SERVICE, length = 22) {
+ _reserved_ : 8, // Flags
+ service_type : QosServiceType,
+ token_rate : 32, // 0 = ignore, 0xffffffff = max available
+ token_bucket_size : 32, // 0 = ignore, 0xffffffff = max available
+ peak_bandwidth : 32, // Octets/second 0 = ignore
+ latency : 32, // microseconds 0xffffffff = ignore
+ delay_variation : 32, // microseconds 0xffffffff = ignore
+}
+
+enum RetransmissionAndFlowControlModeOption : 8 {
+ L2CAP_BASIC = 0x00,
+ RETRANSMISSION = 0x01,
+ FLOW_CONTROL = 0x02,
+ ENHANCED_RETRANSMISSION = 0x03,
+ STREAMING = 0x04,
+}
+
+
+struct RetransmissionAndFlowControlConfigurationOption : ConfigurationOption (type = RETRANSMISSION_AND_FLOW_CONTROL, length = 9) {
+ mode : RetransmissionAndFlowControlModeOption,
+ tx_window_size : 8, // 1-32 for Flow Control and Retransmission, 1-63 for Enhanced
+ max_transmit : 8,
+ retransmission_time_out : 16,
+ monitor_time_out : 16,
+ maximum_pdu_size : 16,
+}
+
+enum FcsType : 8 {
+ NO_FCS = 0,
+ DEFAULT = 1, // 16-bit FCS
+}
+
+struct FrameCheckSequenceOption : ConfigurationOption (type = FRAME_CHECK_SEQUENCE, length = 1) {
+ fcs_type : FcsType,
+}
+
+
+struct ExtendedFlowSpecificationOption : ConfigurationOption (type = EXTENDED_FLOW_SPECIFICATION, length = 16) {
+ identifier : 8, // Default 0x01, must be 0x01 for Extended Flow-Best-Effort
+ service_type : QosServiceType,
+ maximum_sdu_size : 16, // Octets
+ sdu_interarrival_time : 32, // in microseconds
+ access_latency : 32, // in microseconds, without HCI and stack overheads
+ flush_timeout : 32, // in microseconds 0x0 = no retransmissions 0xFFFFFFFF = never flushed
+}
+
+struct ExtendedWindowSizeOption : ConfigurationOption (type = EXTENDED_WINDOW_SIZE, length = 2) {
+ max_window_size : 16, // 0x0000 = Valid for streaming, 0x0001-0x3FFF Valid for Enhanced Retransmission
+}
+
+packet ConfigurationRequest : Control (code = CONFIGURATION_REQUEST) {
+ destination_cid : 16,
+ continuation : Continuation,
+ _reserved_ : 15,
+ config : ConfigurationOption[],
+}
+
+enum ConfigurationResponseResult : 16 {
+ SUCCESS = 0x0000,
+ UNACCEPTABLE_PARAMETERS = 0x0001,
+ REJECTED = 0x0002,
+ UNKNOWN_OPTIONS = 0x0003,
+ PENDING = 0x0004,
+ FLOW_SPEC_REJECTED = 0x0005,
+}
+
+packet ConfigurationResponse : Control (code = CONFIGURATION_RESPONSE) {
+ source_cid : 16,
+ continuation : Continuation,
+ _reserved_ : 15,
+ result : ConfigurationResponseResult,
+ config : ConfigurationOption[],
+}
+
+packet DisconnectionRequest : Control (code = DISCONNECTION_REQUEST) {
+ destination_cid : 16,
+ source_cid : 16,
+}
+
+packet DisconnectionResponse : Control (code = DISCONNECTION_RESPONSE) {
+ destination_cid : 16,
+ source_cid : 16,
+}
+
+packet EchoRequest : Control (code = ECHO_REQUEST) {
+ _payload_, // Optional and implementation specific
+}
+
+packet EchoResponse : Control (code = ECHO_RESPONSE) {
+ _payload_, // Optional and implementation specific
+}
+
+enum InformationRequestInfoType : 16 {
+ CONNECTIONLESS_MTU = 0x0001,
+ EXTENDED_FEATURES_SUPPORTED = 0x0002,
+ FIXED_CHANNELS_SUPPORTED = 0x0003,
+}
+
+packet InformationRequest : Control (code = INFORMATION_REQUEST) {
+ info_type : InformationRequestInfoType,
+}
+
+enum InformationRequestResult : 16 {
+ SUCCESS = 0x0000,
+ NOT_SUPPORTED = 0x0001,
+}
+
+packet InformationResponse : Control (code = INFORMATION_RESPONSE) {
+ info_type : InformationRequestInfoType,
+ result : InformationRequestResult,
+ _body_,
+}
+
+packet InformationResponseConnectionlessMtu : InformationResponse (info_type = CONNECTIONLESS_MTU) {
+ connectionless_mtu : 16,
+}
+
+packet InformationResponseExtendedFeatures : InformationResponse (info_type = EXTENDED_FEATURES_SUPPORTED) {
+ // ExtendedFeatureMask : 32,
+ flow_control_mode : 1,
+ retransmission_mode : 1,
+ bi_directional_qoS : 1,
+ enhanced_retransmission_mode : 1,
+ streaming_mode : 1,
+ fcs_option : 1,
+ extended_flow_specification_for_br_edr : 1,
+ fixed_channels : 1,
+ extended_window_size : 1,
+ unicast_connectionless_data_reception : 1,
+ _reserved_ : 22,
+}
+
+packet InformationResponseFixedChannels : InformationResponse (info_type = FIXED_CHANNELS_SUPPORTED) {
+ fixed_channels : 64, // bit 0 must be 0, bit 1 must be 1, all others 1 = supported
+}
+
+packet CreateChannelRequest : Control (code = CREATE_CHANNEL_REQUEST) {
+ psm : 16,
+ source_cid : 16,
+ controller_id : 8,
+}
+
+enum CreateChannelResponseResult : 16 {
+ SUCCESS = 0x0000,
+ PENDING = 0x0001,
+ PSM_NOT_SUPPORTED = 0x0002,
+ SECURITY_BLOCK = 0x0003,
+ NO_RESOURCES_AVAILABLE = 0x0004,
+ CONTROLLER_ID_NOT_SUPPORTED = 0x0005,
+ INVALID_CID = 0x0006,
+ SOURCE_CID_ALREADY_ALLOCATED = 0x0007,
+}
+
+enum CreateChannelResponseStatus : 16 {
+ NO_FURTHER_INFORMATION_AVAILABLE = 0x0000,
+ AUTHENTICATION_PENDING = 0x0001,
+ AUTHORIZATION_PENDING = 0x0002,
+}
+
+packet CreateChannelResponse : Control (code = CREATE_CHANNEL_RESPONSE) {
+ destination_cid : 16,
+ source_cid : 16,
+ result : CreateChannelResponseResult,
+ status : CreateChannelResponseStatus,
+}
+
+// AMP Only ?
+packet MoveChannelRequest : Control (code = MOVE_CHANNEL_REQUEST) {
+ initiator_cid : 16,
+ dest_controller_id : 8,
+}
+
+enum MoveChannelResponseResult : 16 {
+ SUCCESS = 0x0000,
+ PENDING = 0x0001,
+ CONTROLLER_ID_NOT_SUPPORTED = 0x0002,
+ NEW_CONTROLLER_ID_IS_SAME = 0x0003,
+ CONFIGURATION_NOT_SUPPORTED = 0x0004,
+ CHANNEL_COLLISION = 0x0005,
+ CHANNEL_NOT_ALLOWED_TO_BE_MOVED = 0x0006,
+}
+
+packet MoveChannelResponse : Control (code = MOVE_CHANNEL_RESPONSE) {
+ initiator_cid : 16,
+ result : MoveChannelResponseResult,
+}
+
+enum MoveChannelConfirmationResult : 16 {
+ SUCCESS = 0x0000,
+ FAILURE = 0x0001,
+}
+
+packet MoveChannelConfirmationRequest : Control (code = MOVE_CHANNEL_CONFIRMATION_REQUEST) {
+ initiator_cid : 16,
+ result : MoveChannelConfirmationResult,
+}
+
+packet MoveChannelConfirmationResponse : Control (code = MOVE_CHANNEL_CONFIRMATION_RESPONSE) {
+ initiator_cid : 16,
+}
+
+enum LeCommandCode : 8 {
+ COMMAND_REJECT = 0x01,
+ DISCONNECTION_REQUEST = 0x06,
+ DISCONNECTION_RESPONSE = 0x07,
+ CONNECTION_PARAMETER_UPDATE_REQUEST = 0x12,
+ CONNECTION_PARAMETER_UPDATE_RESPONSE = 0x13,
+ LE_CREDIT_BASED_CONNECTION_REQUEST = 0x14,
+ LE_CREDIT_BASED_CONNECTION_RESPONSE = 0x15,
+ LE_FLOW_CONTROL_CREDIT = 0x16,
+}
+
+packet LeControlFrame : BasicFrame (channel_id = 0x0005) {
+ _payload_,
+}
+
+packet LeControl {
+ code : LeCommandCode,
+ identifier : 8, // Must be non-zero
+ _size_(_payload_) : 16,
+ _payload_,
+}
+
+
+packet LeCommandReject : LeControl (code = COMMAND_REJECT) {
+ reason : CommandRejectReason,
+ _payload_,
+}
+
+packet LeCommandRejectNotUnderstood : LeCommandReject (reason = COMMAND_NOT_UNDERSTOOD) {
+}
+
+packet LeCommandRejectMtuExceeded : LeCommandReject (reason = SIGNALING_MTU_EXCEEDED) {
+ actual_mtu : 16,
+}
+
+packet LeCommandRejectInvalidCid : LeCommandReject (reason = INVALID_CID_IN_REQUEST) {
+ local_channel : 16, // Relative to the sender of the CommandReject
+ remote_channel : 16,
+}
+
+packet LeDisconnectionRequest : LeControl (code = DISCONNECTION_REQUEST) {
+ destination_cid : 16,
+ source_cid : 16,
+}
+
+packet LeDisconnectionResponse : LeControl (code = DISCONNECTION_RESPONSE) {
+ destination_cid : 16,
+ source_cid : 16,
+}
+
+packet ConnectionParameterUpdateRequest : LeControl (code = CONNECTION_PARAMETER_UPDATE_REQUEST) {
+ interval_min : 16,
+ interval_max : 16,
+ slave_latency : 16,
+ timeout_multiplier : 16,
+}
+
+enum ConnectionParameterUpdateResponseResult : 16 {
+ ACCEPTED = 0,
+ REJECTED = 1,
+}
+
+packet ConnectionParameterUpdateResponse : LeControl (code = CONNECTION_PARAMETER_UPDATE_RESPONSE) {
+ result : ConnectionParameterUpdateResponseResult,
+}
+
+packet LeCreditBasedConnectionRequest : LeControl (code = LE_CREDIT_BASED_CONNECTION_REQUEST) {
+ le_psm : 16, // 0x0001-0x007F Fixed, 0x0080-0x00FF Dynamic
+ source_cid : 16,
+ mtu : 16,
+ mps : 16,
+ initial_credits : 16,
+}
+
+enum LeCreditBasedConnectionResponseResult : 16 {
+ SUCCESS = 0x0000,
+ LE_PSM_NOT_SUPPORTED = 0x0002,
+ NO_RESOURCES_AVAILABLE = 0x0004,
+ INSUFFICIENT_AUTHENTICATION = 0x0005,
+ INSUFFICIENT_AUTHORIZATION = 0x0006,
+ INSUFFICIENT_ENCRYPTION_KEY_SIZE = 0x0007,
+ INSUFFICIENT_ENCRYPTION = 0x0008,
+ INVALID_SOURCE_CID = 0x0009,
+ SOURCE_CID_ALREADY_ALLOCATED = 0x000A,
+ UNACCEPTABLE_PARAMETERS = 0x000B,
+}
+
+packet LeCreditBasedConnectionResponse : LeControl (code = LE_CREDIT_BASED_CONNECTION_RESPONSE) {
+ destination_cid : 16,
+ mtu : 16,
+ mps : 16,
+ initial_credits : 16,
+ result : LeCreditBasedConnectionResponseResult,
+}
+
+packet LeFlowControlCredit : LeControl (code = LE_FLOW_CONTROL_CREDIT) {
+ cid : 16, // Receiver's destination CID
+ credits : 16,
+}
+
diff --git a/gd/l2cap/le/fixed_channel.cc b/gd/l2cap/le/fixed_channel.cc
new file mode 100644
index 0000000..d02dad6
--- /dev/null
+++ b/gd/l2cap/le/fixed_channel.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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 "l2cap/le/fixed_channel.h"
+#include "common/bind.h"
+#include "l2cap/le/internal/fixed_channel_impl.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+
+hci::AddressWithType FixedChannel::GetDevice() const {
+ return impl_->GetDevice();
+}
+
+hci::Role FixedChannel::GetRole() const {
+ return impl_->GetRole();
+}
+
+void FixedChannel::RegisterOnCloseCallback(os::Handler* user_handler, FixedChannel::OnCloseCallback on_close_callback) {
+ l2cap_handler_->Post(common::BindOnce(&internal::FixedChannelImpl::RegisterOnCloseCallback, impl_, user_handler,
+ std::move(on_close_callback)));
+}
+
+void FixedChannel::Acquire() {
+ l2cap_handler_->Post(common::BindOnce(&internal::FixedChannelImpl::Acquire, impl_));
+}
+
+void FixedChannel::Release() {
+ l2cap_handler_->Post(common::BindOnce(&internal::FixedChannelImpl::Release, impl_));
+}
+
+common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>*
+FixedChannel::GetQueueUpEnd() const {
+ return impl_->GetQueueUpEnd();
+}
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/le/fixed_channel.h b/gd/l2cap/le/fixed_channel.h
new file mode 100644
index 0000000..ad4674b
--- /dev/null
+++ b/gd/l2cap/le/fixed_channel.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include "common/bidi_queue.h"
+#include "common/callback.h"
+#include "hci/acl_manager.h"
+#include "l2cap/cid.h"
+#include "os/handler.h"
+#include "packet/base_packet_builder.h"
+#include "packet/packet_view.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+
+namespace internal {
+class FixedChannelImpl;
+} // namespace internal
+
+/**
+ * L2CAP fixed channel object. When a new object is created, it must be
+ * acquired through calling {@link FixedChannel#Acquire()} within X seconds.
+ * Otherwise, {@link FixedChannel#Release()} will be called automatically.
+ *
+ */
+class FixedChannel {
+ public:
+ // Should only be constructed by modules that have access to LinkManager
+ FixedChannel(std::shared_ptr<internal::FixedChannelImpl> impl, os::Handler* l2cap_handler)
+ : impl_(std::move(impl)), l2cap_handler_(l2cap_handler) {
+ ASSERT(impl_ != nullptr);
+ ASSERT(l2cap_handler_ != nullptr);
+ }
+
+ hci::AddressWithType GetDevice() const;
+
+ /**
+ * Return the role we have in the associated link
+ */
+ hci::Role GetRole() const;
+
+ /**
+ * Register close callback. If close callback is registered, when a channel is closed, the channel's resource will
+ * only be freed after on_close callback is invoked. Otherwise, if no on_close callback is registered, the channel's
+ * resource will be freed immediately after closing.
+ *
+ * @param user_handler The handler used to invoke the callback on
+ * @param on_close_callback The callback invoked upon channel closing.
+ */
+ using OnCloseCallback = common::OnceCallback<void(hci::ErrorCode)>;
+ void RegisterOnCloseCallback(os::Handler* user_handler, OnCloseCallback on_close_callback);
+
+ /**
+ * Indicate that this Fixed Channel is being used. This will prevent ACL connection from being disconnected.
+ */
+ void Acquire();
+
+ /**
+ * Indicate that this Fixed Channel is no longer being used. ACL connection will be disconnected after
+ * kLinkIdleDisconnectTimeout if no other DynamicChannel is connected or no other Fixed Channel is using this
+ * ACL connection. However a module can still receive data on this channel as long as it remains open.
+ */
+ void Release();
+
+ /**
+ * This method will retrieve the data channel queue to send and receive packets.
+ *
+ * {@see BidiQueueEnd}
+ *
+ * @return The upper end of a bi-directional queue.
+ */
+ common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>* GetQueueUpEnd() const;
+
+ private:
+ std::shared_ptr<internal::FixedChannelImpl> impl_;
+ os::Handler* l2cap_handler_;
+};
+
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/le/fixed_channel_manager.cc b/gd/l2cap/le/fixed_channel_manager.cc
new file mode 100644
index 0000000..e36a7b4
--- /dev/null
+++ b/gd/l2cap/le/fixed_channel_manager.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 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 "l2cap/le/fixed_channel_manager.h"
+#include "l2cap/le/internal/fixed_channel_service_impl.h"
+#include "l2cap/le/internal/fixed_channel_service_manager_impl.h"
+#include "l2cap/le/internal/link_manager.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+
+bool FixedChannelManager::ConnectServices(hci::AddressWithType address_with_type,
+ OnConnectionFailureCallback on_fail_callback, os::Handler* handler) {
+ internal::LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+ .handler_ = handler,
+ .on_fail_callback_ = std::move(on_fail_callback),
+ };
+ l2cap_layer_handler_->Post(common::BindOnce(&internal::LinkManager::ConnectFixedChannelServices,
+ common::Unretained(link_manager_), address_with_type,
+ std::move(pending_fixed_channel_connection)));
+ return true;
+}
+
+bool FixedChannelManager::RegisterService(Cid cid, const SecurityPolicy& security_policy,
+ OnRegistrationCompleteCallback on_registration_complete,
+ OnConnectionOpenCallback on_connection_open, os::Handler* handler) {
+ internal::FixedChannelServiceImpl::PendingRegistration pending_registration{
+ .user_handler_ = handler,
+ .on_registration_complete_callback_ = std::move(on_registration_complete),
+ .on_connection_open_callback_ = std::move(on_connection_open)};
+ l2cap_layer_handler_->Post(common::BindOnce(&internal::FixedChannelServiceManagerImpl::Register,
+ common::Unretained(service_manager_), cid,
+ std::move(pending_registration)));
+ return true;
+}
+
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/le/fixed_channel_manager.h b/gd/l2cap/le/fixed_channel_manager.h
new file mode 100644
index 0000000..4583310
--- /dev/null
+++ b/gd/l2cap/le/fixed_channel_manager.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <string>
+
+#include "hci/acl_manager.h"
+#include "hci/address_with_type.h"
+#include "l2cap/cid.h"
+#include "l2cap/le/fixed_channel.h"
+#include "l2cap/le/fixed_channel_service.h"
+#include "l2cap/security_policy.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+
+class L2capLeModule;
+
+namespace internal {
+class LinkManager;
+class FixedChannelServiceManagerImpl;
+} // namespace internal
+
+class FixedChannelManager {
+ public:
+ enum class ConnectionResultCode {
+ SUCCESS = 0,
+ FAIL_NO_SERVICE_REGISTERED = 1, // No service is registered
+ FAIL_ALL_SERVICES_HAVE_CHANNEL = 2, // All registered services already have a channel
+ FAIL_HCI_ERROR = 3, // See hci_error
+ };
+
+ struct ConnectionResult {
+ ConnectionResultCode connection_result_code = ConnectionResultCode::SUCCESS;
+ hci::ErrorCode hci_error = hci::ErrorCode::SUCCESS;
+ };
+ /**
+ * OnConnectionFailureCallback(ConnectionResult failure_reason);
+ */
+ using OnConnectionFailureCallback = common::OnceCallback<void(ConnectionResult)>;
+
+ /**
+ * OnConnectionOpenCallback(FixedChannel channel);
+ */
+ using OnConnectionOpenCallback = common::Callback<void(std::unique_ptr<FixedChannel>)>;
+
+ enum class RegistrationResult {
+ SUCCESS = 0,
+ FAIL_DUPLICATE_SERVICE = 1, // Duplicate service registration for the same CID
+ FAIL_INVALID_SERVICE = 2, // Invalid CID
+ };
+
+ /**
+ * OnRegistrationFailureCallback(RegistrationResult result, FixedChannelService service);
+ */
+ using OnRegistrationCompleteCallback =
+ common::OnceCallback<void(RegistrationResult, std::unique_ptr<FixedChannelService>)>;
+
+ /**
+ * Connect to ALL fixed channels on a remote device
+ *
+ * - This method is asynchronous
+ * - When false is returned, the connection fails immediately
+ * - When true is returned, method caller should wait for on_fail_callback or on_open_callback registered through
+ * RegisterService() API.
+ * - If an ACL connection does not exist, this method will create an ACL connection. As a result, on_open_callback
+ * supplied through RegisterService() will be triggered to provide the actual FixedChannel objects
+ * - If HCI connection failed, on_fail_callback will be triggered with FAIL_HCI_ERROR
+ * - If fixed channel on a remote device is already reported as connected via on_open_callback and has been acquired
+ * via FixedChannel#Acquire() API, it won't be reported again
+ * - If no service is registered, on_fail_callback will be triggered with FAIL_NO_SERVICE_REGISTERED
+ * - If there is an ACL connection and channels for each service is allocated, on_fail_callback will be triggered with
+ * FAIL_ALL_SERVICES_HAVE_CHANNEL
+ *
+ * NOTE:
+ * This call will initiate an effort to connect all fixed channel services on a remote device.
+ * Due to the connectionless nature of fixed channels, all fixed channels will be connected together.
+ * If a fixed channel service does not need a particular fixed channel. It should release the received
+ * channel immediately after receiving on_open_callback via FixedChannel#Release()
+ *
+ * A module calling ConnectServices() must have called RegisterService() before.
+ * The callback will come back from on_open_callback in the service that is registered
+ *
+ * @param address_with_type: Remote device with type to make this connection.
+ * @param address_type: Address type of remote device
+ * @param on_fail_callback: A callback to indicate connection failure along with a status code.
+ * @param handler: The handler context in which to execute the @callback parameters.
+ *
+ * Returns: true if connection was able to be initiated, false otherwise.
+ */
+ bool ConnectServices(hci::AddressWithType address_with_type, OnConnectionFailureCallback on_fail_callback,
+ os::Handler* handler);
+
+ /**
+ * Register a service to receive incoming connections bound to a specific channel.
+ *
+ * - This method is asynchronous.
+ * - When false is returned, the registration fails immediately.
+ * - When true is returned, method caller should wait for on_service_registered callback that contains a
+ * FixedChannelService object. The registered service can be managed from that object.
+ * - If a CID is already registered or some other error happens, on_registration_complete will be triggered with a
+ * non-SUCCESS value
+ * - After a service is registered, any classic ACL connection will create a FixedChannel object that is
+ * delivered through on_open_callback
+ * - on_open_callback, will only be triggered after on_service_registered callback
+ *
+ * @param cid: cid used to receive incoming connections
+ * @param security_policy: The security policy used for the connection.
+ * @param on_registration_complete: A callback to indicate the service setup has completed. If the return status is
+ * not SUCCESS, it means service is not registered due to reasons like CID already take
+ * @param on_open_callback: A callback to indicate success of a connection initiated from a remote device.
+ * @param handler: The handler context in which to execute the @callback parameter.
+ */
+ bool RegisterService(Cid cid, const SecurityPolicy& security_policy,
+ OnRegistrationCompleteCallback on_registration_complete,
+ OnConnectionOpenCallback on_connection_open, os::Handler* handler);
+
+ friend class L2capLeModule;
+
+ private:
+ // The constructor is not to be used by user code
+ FixedChannelManager(internal::FixedChannelServiceManagerImpl* service_manager, internal::LinkManager* link_manager,
+ os::Handler* l2cap_layer_handler)
+ : service_manager_(service_manager), link_manager_(link_manager), l2cap_layer_handler_(l2cap_layer_handler) {}
+ internal::FixedChannelServiceManagerImpl* service_manager_ = nullptr;
+ internal::LinkManager* link_manager_ = nullptr;
+ os::Handler* l2cap_layer_handler_ = nullptr;
+ DISALLOW_COPY_AND_ASSIGN(FixedChannelManager);
+};
+
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/le/fixed_channel_service.cc b/gd/l2cap/le/fixed_channel_service.cc
new file mode 100644
index 0000000..888a741
--- /dev/null
+++ b/gd/l2cap/le/fixed_channel_service.cc
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2019 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 "l2cap/le/fixed_channel_service.h"
+#include "l2cap/le/internal/fixed_channel_service_manager_impl.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+
+void FixedChannelService::Unregister(OnUnregisteredCallback on_unregistered, os::Handler* on_unregistered_handler) {
+ ASSERT_LOG(manager_ != nullptr, "this service is invalid");
+ l2cap_layer_handler_->Post(common::BindOnce(&internal::FixedChannelServiceManagerImpl::Unregister,
+ common::Unretained(manager_), cid_, std::move(on_unregistered),
+ on_unregistered_handler));
+}
+
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/le/fixed_channel_service.h b/gd/l2cap/le/fixed_channel_service.h
new file mode 100644
index 0000000..0c4556e
--- /dev/null
+++ b/gd/l2cap/le/fixed_channel_service.h
@@ -0,0 +1,59 @@
+
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include "common/callback.h"
+#include "hci/address.h"
+#include "l2cap/cid.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+
+namespace internal {
+class FixedChannelServiceManagerImpl;
+}
+
+class FixedChannelService {
+ public:
+ FixedChannelService() = default;
+
+ using OnUnregisteredCallback = common::OnceCallback<void()>;
+
+ /**
+ * Unregister a service from L2CAP module. This operation cannot fail.
+ * All channels opened for this service will be invalidated.
+ *
+ * @param on_unregistered will be triggered when unregistration is complete
+ */
+ void Unregister(OnUnregisteredCallback on_unregistered, os::Handler* on_unregistered_handler);
+
+ friend internal::FixedChannelServiceManagerImpl;
+
+ private:
+ FixedChannelService(Cid cid, internal::FixedChannelServiceManagerImpl* manager, os::Handler* handler)
+ : cid_(cid), manager_(manager), l2cap_layer_handler_(handler) {}
+ Cid cid_ = kInvalidCid;
+ internal::FixedChannelServiceManagerImpl* manager_ = nullptr;
+ os::Handler* l2cap_layer_handler_;
+ DISALLOW_COPY_AND_ASSIGN(FixedChannelService);
+};
+
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/le/internal/fixed_channel_impl.cc b/gd/l2cap/le/internal/fixed_channel_impl.cc
new file mode 100644
index 0000000..9ae4e1f
--- /dev/null
+++ b/gd/l2cap/le/internal/fixed_channel_impl.cc
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2019 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 <unordered_map>
+
+#include "l2cap/cid.h"
+#include "l2cap/le/internal/fixed_channel_impl.h"
+#include "l2cap/le/internal/link.h"
+#include "l2cap/security_policy.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+hci::Role FixedChannelImpl::GetRole() const {
+ return link_->GetRole();
+}
+
+FixedChannelImpl::FixedChannelImpl(Cid cid, Link* link, os::Handler* l2cap_handler)
+ : cid_(cid), device_(link->GetDevice()), link_(link), l2cap_handler_(l2cap_handler) {
+ ASSERT_LOG(cid_ >= kFirstFixedChannel && cid_ <= kLastFixedChannel, "Invalid cid: %d", cid_);
+ ASSERT(!device_.GetAddress().IsEmpty());
+ ASSERT(link_ != nullptr);
+ ASSERT(l2cap_handler_ != nullptr);
+}
+
+void FixedChannelImpl::RegisterOnCloseCallback(os::Handler* user_handler,
+ FixedChannel::OnCloseCallback on_close_callback) {
+ ASSERT_LOG(user_handler_ == nullptr, "OnCloseCallback can only be registered once");
+ // If channel is already closed, call the callback immediately without saving it
+ if (closed_) {
+ user_handler->Post(common::BindOnce(std::move(on_close_callback), close_reason_));
+ return;
+ }
+ user_handler_ = user_handler;
+ on_close_callback_ = std::move(on_close_callback);
+}
+
+void FixedChannelImpl::OnClosed(hci::ErrorCode status) {
+ ASSERT_LOG(!closed_, "Device %s Cid 0x%x closed twice, old status 0x%x, new status 0x%x", device_.ToString().c_str(),
+ cid_, static_cast<int>(close_reason_), static_cast<int>(status));
+ closed_ = true;
+ close_reason_ = status;
+ acquired_ = false;
+ link_ = nullptr;
+ l2cap_handler_ = nullptr;
+ if (user_handler_ == nullptr) {
+ return;
+ }
+ // On close callback can only be called once
+ user_handler_->Post(common::BindOnce(std::move(on_close_callback_), status));
+ user_handler_ = nullptr;
+ on_close_callback_.Reset();
+}
+
+void FixedChannelImpl::Acquire() {
+ ASSERT_LOG(user_handler_ != nullptr, "Must register OnCloseCallback before calling any methods");
+ if (closed_) {
+ LOG_WARN("%s is already closed", ToString().c_str());
+ ASSERT(!acquired_);
+ return;
+ }
+ if (acquired_) {
+ LOG_DEBUG("%s was already acquired", ToString().c_str());
+ return;
+ }
+ acquired_ = true;
+ link_->RefreshRefCount();
+}
+
+void FixedChannelImpl::Release() {
+ ASSERT_LOG(user_handler_ != nullptr, "Must register OnCloseCallback before calling any methods");
+ if (closed_) {
+ LOG_WARN("%s is already closed", ToString().c_str());
+ ASSERT(!acquired_);
+ return;
+ }
+ if (!acquired_) {
+ LOG_DEBUG("%s was already released", ToString().c_str());
+ return;
+ }
+ acquired_ = false;
+ link_->RefreshRefCount();
+}
+
+Cid FixedChannelImpl::GetCid() const {
+ return cid_;
+}
+
+Cid FixedChannelImpl::GetRemoteCid() const {
+ return cid_;
+}
+
+void FixedChannelImpl::SetSender(l2cap::internal::Sender* sender) {
+ ASSERT_LOG(false, "Should not set sender for fixed channel");
+}
+
+} // namespace internal
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/le/internal/fixed_channel_impl.h b/gd/l2cap/le/internal/fixed_channel_impl.h
new file mode 100644
index 0000000..82a4125
--- /dev/null
+++ b/gd/l2cap/le/internal/fixed_channel_impl.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "common/bidi_queue.h"
+#include "l2cap/cid.h"
+#include "l2cap/internal/channel_impl.h"
+#include "l2cap/le/fixed_channel.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+class Link;
+
+class FixedChannelImpl : public l2cap::internal::ChannelImpl {
+ public:
+ FixedChannelImpl(Cid cid, Link* link, os::Handler* l2cap_handler);
+
+ virtual ~FixedChannelImpl() = default;
+
+ hci::AddressWithType GetDevice() const {
+ return device_;
+ }
+
+ /* Return the role we have in the associated link */
+ virtual hci::Role GetRole() const;
+
+ virtual void RegisterOnCloseCallback(os::Handler* user_handler, FixedChannel::OnCloseCallback on_close_callback);
+
+ virtual void Acquire();
+
+ virtual void Release();
+
+ virtual bool IsAcquired() const {
+ return acquired_;
+ }
+
+ Cid GetCid() const override;
+ Cid GetRemoteCid() const override;
+ void SetSender(l2cap::internal::Sender* sender) override;
+ virtual void OnClosed(hci::ErrorCode status);
+
+ virtual std::string ToString() {
+ std::ostringstream ss;
+ ss << "Device " << device_ << " Cid 0x" << std::hex << cid_;
+ return ss.str();
+ }
+
+ common::BidiQueueEnd<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>>* GetQueueUpEnd() {
+ return channel_queue_.GetUpEnd();
+ }
+
+ common::BidiQueueEnd<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>* GetQueueDownEnd() {
+ return channel_queue_.GetDownEnd();
+ }
+
+ private:
+ // Constructor states
+ // For logging purpose only
+ const Cid cid_;
+ // For logging purpose only
+ const hci::AddressWithType device_;
+ // Needed to handle Acquire() and Release()
+ Link* link_;
+ os::Handler* l2cap_handler_;
+
+ // User supported states
+ os::Handler* user_handler_ = nullptr;
+ FixedChannel::OnCloseCallback on_close_callback_{};
+
+ // Internal states
+ bool acquired_ = false;
+ bool closed_ = false;
+ hci::ErrorCode close_reason_ = hci::ErrorCode::SUCCESS;
+ static constexpr size_t kChannelQueueSize = 10;
+ common::BidiQueue<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder> channel_queue_{
+ kChannelQueueSize};
+
+ DISALLOW_COPY_AND_ASSIGN(FixedChannelImpl);
+};
+
+} // namespace internal
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/le/internal/fixed_channel_impl_mock.h b/gd/l2cap/le/internal/fixed_channel_impl_mock.h
new file mode 100644
index 0000000..5baa7e5
--- /dev/null
+++ b/gd/l2cap/le/internal/fixed_channel_impl_mock.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include "l2cap/le/internal/fixed_channel_impl.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+namespace testing {
+
+class MockFixedChannelImpl : public FixedChannelImpl {
+ public:
+ MOCK_METHOD(void, RegisterOnCloseCallback,
+ (os::Handler * user_handler, FixedChannel::OnCloseCallback on_close_callback), (override));
+ MOCK_METHOD(void, Acquire, (), (override));
+ MOCK_METHOD(void, Release, (), (override));
+ MOCK_METHOD(bool, IsAcquired, (), (override, const));
+ MOCK_METHOD(void, OnClosed, (hci::ErrorCode status), (override));
+};
+
+} // namespace testing
+} // namespace internal
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/le/internal/fixed_channel_impl_test.cc b/gd/l2cap/le/internal/fixed_channel_impl_test.cc
new file mode 100644
index 0000000..a4270b4
--- /dev/null
+++ b/gd/l2cap/le/internal/fixed_channel_impl_test.cc
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2019 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 "l2cap/le/internal/fixed_channel_impl.h"
+#include "common/testing/bind_test_util.h"
+#include "hci/address_with_type.h"
+#include "l2cap/cid.h"
+#include "l2cap/internal/parameter_provider_mock.h"
+#include "l2cap/le/internal/link_mock.h"
+#include "os/handler.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+using hci::Address;
+using hci::AddressWithType;
+using l2cap::internal::testing::MockParameterProvider;
+using testing::MockLink;
+using ::testing::Return;
+
+class L2capLeFixedChannelImplTest : public ::testing::Test {
+ public:
+ static void SyncHandler(os::Handler* handler) {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+ future.wait_for(std::chrono::milliseconds(3));
+ }
+
+ protected:
+ void SetUp() override {
+ thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+ l2cap_handler_ = new os::Handler(thread_);
+ }
+
+ void TearDown() override {
+ l2cap_handler_->Clear();
+ delete l2cap_handler_;
+ delete thread_;
+ }
+
+ os::Thread* thread_ = nullptr;
+ os::Handler* l2cap_handler_ = nullptr;
+};
+
+TEST_F(L2capLeFixedChannelImplTest, get_device) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_le_link(l2cap_handler_, &mock_parameter_provider);
+ AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_DEVICE_ADDRESS};
+ EXPECT_CALL(mock_le_link, GetDevice()).WillRepeatedly(Return(device));
+ FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_le_link, l2cap_handler_);
+ EXPECT_EQ(device, fixed_channel_impl.GetDevice());
+}
+
+TEST_F(L2capLeFixedChannelImplTest, close_triggers_callback) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_le_link(l2cap_handler_, &mock_parameter_provider);
+ AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_DEVICE_ADDRESS};
+ EXPECT_CALL(mock_le_link, GetDevice()).WillRepeatedly(Return(device));
+ FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_le_link, l2cap_handler_);
+
+ // Register on close callback
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+ hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+ fixed_channel_impl.RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+ // Channel closure should trigger such callback
+ fixed_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+ user_handler->Clear();
+}
+
+TEST_F(L2capLeFixedChannelImplTest, register_callback_after_close_should_call_immediately) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_le_link(l2cap_handler_, &mock_parameter_provider);
+ AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_DEVICE_ADDRESS};
+ EXPECT_CALL(mock_le_link, GetDevice()).WillRepeatedly(Return(device));
+ FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_le_link, l2cap_handler_);
+
+ // Channel closure should do nothing
+ fixed_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+
+ // Register on close callback should trigger callback immediately
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+ hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+ fixed_channel_impl.RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+ user_handler->Clear();
+}
+
+TEST_F(L2capLeFixedChannelImplTest, close_twice_should_fail) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_le_link(l2cap_handler_, &mock_parameter_provider);
+ AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_DEVICE_ADDRESS};
+ EXPECT_CALL(mock_le_link, GetDevice()).WillRepeatedly(Return(device));
+ FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_le_link, l2cap_handler_);
+
+ // Register on close callback
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+ hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+ fixed_channel_impl.RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+ // Channel closure should trigger such callback
+ fixed_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+ // 2nd OnClose() callback should fail
+ EXPECT_DEATH(fixed_channel_impl.OnClosed(hci::ErrorCode::PAGE_TIMEOUT), ".*OnClosed.*");
+
+ user_handler->Clear();
+}
+
+TEST_F(L2capLeFixedChannelImplTest, multiple_registeration_should_fail) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_le_link(l2cap_handler_, &mock_parameter_provider);
+ AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_DEVICE_ADDRESS};
+ EXPECT_CALL(mock_le_link, GetDevice()).WillRepeatedly(Return(device));
+ FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_le_link, l2cap_handler_);
+
+ // Register on close callback
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+ hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+ fixed_channel_impl.RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+ EXPECT_DEATH(fixed_channel_impl.RegisterOnCloseCallback(user_handler.get(),
+ common::BindOnce([](hci::ErrorCode status) { FAIL(); })),
+ ".*RegisterOnCloseCallback.*");
+
+ user_handler->Clear();
+}
+
+TEST_F(L2capLeFixedChannelImplTest, call_acquire_before_registeration_should_fail) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_le_link(l2cap_handler_, &mock_parameter_provider);
+ AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_DEVICE_ADDRESS};
+ EXPECT_CALL(mock_le_link, GetDevice()).WillRepeatedly(Return(device));
+ FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_le_link, l2cap_handler_);
+ EXPECT_DEATH(fixed_channel_impl.Acquire(), ".*Acquire.*");
+}
+
+TEST_F(L2capLeFixedChannelImplTest, call_release_before_registeration_should_fail) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_le_link(l2cap_handler_, &mock_parameter_provider);
+ AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_DEVICE_ADDRESS};
+ EXPECT_CALL(mock_le_link, GetDevice()).WillRepeatedly(Return(device));
+ FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_le_link, l2cap_handler_);
+ EXPECT_DEATH(fixed_channel_impl.Release(), ".*Release.*");
+}
+
+TEST_F(L2capLeFixedChannelImplTest, test_acquire_release_channel) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_le_link(l2cap_handler_, &mock_parameter_provider);
+ AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_DEVICE_ADDRESS};
+ EXPECT_CALL(mock_le_link, GetDevice()).WillRepeatedly(Return(device));
+ FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_le_link, l2cap_handler_);
+
+ // Register on close callback
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+ hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+ fixed_channel_impl.RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+ // Default should be false
+ EXPECT_FALSE(fixed_channel_impl.IsAcquired());
+
+ // Should be called 2 times after Acquire() and Release()
+ EXPECT_CALL(mock_le_link, RefreshRefCount()).Times(2);
+
+ fixed_channel_impl.Acquire();
+ EXPECT_TRUE(fixed_channel_impl.IsAcquired());
+
+ fixed_channel_impl.Release();
+ EXPECT_FALSE(fixed_channel_impl.IsAcquired());
+
+ user_handler->Clear();
+}
+
+TEST_F(L2capLeFixedChannelImplTest, test_acquire_after_close) {
+ MockParameterProvider mock_parameter_provider;
+ MockLink mock_le_link(l2cap_handler_, &mock_parameter_provider);
+ AddressWithType device{{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}}, hci::AddressType::PUBLIC_DEVICE_ADDRESS};
+ EXPECT_CALL(mock_le_link, GetDevice()).WillRepeatedly(Return(device));
+ FixedChannelImpl fixed_channel_impl(kSmpBrCid, &mock_le_link, l2cap_handler_);
+
+ // Register on close callback
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+ hci::ErrorCode my_status = hci::ErrorCode::SUCCESS;
+ fixed_channel_impl.RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { my_status = status; }));
+
+ // Channel closure should trigger such callback
+ fixed_channel_impl.OnClosed(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION);
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(hci::ErrorCode::REMOTE_USER_TERMINATED_CONNECTION, my_status);
+
+ // Release or Acquire after closing should crash
+ EXPECT_CALL(mock_le_link, RefreshRefCount()).Times(0);
+ EXPECT_FALSE(fixed_channel_impl.IsAcquired());
+ EXPECT_DEATH(fixed_channel_impl.Acquire(), ".*Acquire.*");
+
+ user_handler->Clear();
+}
+
+} // namespace internal
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/le/internal/fixed_channel_service_impl.h b/gd/l2cap/le/internal/fixed_channel_service_impl.h
new file mode 100644
index 0000000..5eed777
--- /dev/null
+++ b/gd/l2cap/le/internal/fixed_channel_service_impl.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "l2cap/le/fixed_channel.h"
+#include "l2cap/le/fixed_channel_manager.h"
+#include "l2cap/le/fixed_channel_service.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+class FixedChannelServiceImpl {
+ public:
+ virtual ~FixedChannelServiceImpl() = default;
+
+ struct PendingRegistration {
+ os::Handler* user_handler_ = nullptr;
+ FixedChannelManager::OnRegistrationCompleteCallback on_registration_complete_callback_;
+ FixedChannelManager::OnConnectionOpenCallback on_connection_open_callback_;
+ };
+
+ virtual void NotifyChannelCreation(std::unique_ptr<FixedChannel> channel) {
+ user_handler_->Post(common::BindOnce(on_connection_open_callback_, std::move(channel)));
+ }
+
+ friend class FixedChannelServiceManagerImpl;
+
+ protected:
+ // protected access for mocking
+ FixedChannelServiceImpl(os::Handler* user_handler,
+ FixedChannelManager::OnConnectionOpenCallback on_connection_open_callback)
+ : user_handler_(user_handler), on_connection_open_callback_(std::move(on_connection_open_callback)) {}
+
+ private:
+ os::Handler* user_handler_ = nullptr;
+ FixedChannelManager::OnConnectionOpenCallback on_connection_open_callback_;
+};
+
+} // namespace internal
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/le/internal/fixed_channel_service_impl_mock.h b/gd/l2cap/le/internal/fixed_channel_service_impl_mock.h
new file mode 100644
index 0000000..5a1b65d
--- /dev/null
+++ b/gd/l2cap/le/internal/fixed_channel_service_impl_mock.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include "l2cap/le/internal/fixed_channel_impl.h"
+#include "l2cap/le/internal/fixed_channel_service_manager_impl.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+namespace testing {
+
+class MockFixedChannelServiceImpl : public FixedChannelServiceImpl {
+ public:
+ MockFixedChannelServiceImpl() : FixedChannelServiceImpl(nullptr, FixedChannelManager::OnConnectionOpenCallback()) {}
+ MOCK_METHOD(void, NotifyChannelCreation, (std::unique_ptr<FixedChannel> channel), (override));
+};
+
+} // namespace testing
+} // namespace internal
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/le/internal/fixed_channel_service_manager_impl.cc b/gd/l2cap/le/internal/fixed_channel_service_manager_impl.cc
new file mode 100644
index 0000000..3a2de00
--- /dev/null
+++ b/gd/l2cap/le/internal/fixed_channel_service_manager_impl.cc
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2019 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 "l2cap/le/internal/fixed_channel_service_manager_impl.h"
+
+#include "common/bind.h"
+#include "l2cap/cid.h"
+#include "l2cap/le/internal/fixed_channel_service_impl.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+void FixedChannelServiceManagerImpl::Register(Cid cid,
+ FixedChannelServiceImpl::PendingRegistration pending_registration) {
+ if (cid < kFirstFixedChannel || cid > kLastFixedChannel || cid == kLeSignallingCid) {
+ std::unique_ptr<FixedChannelService> invalid_service(new FixedChannelService());
+ pending_registration.user_handler_->Post(
+ common::BindOnce(std::move(pending_registration.on_registration_complete_callback_),
+ FixedChannelManager::RegistrationResult::FAIL_INVALID_SERVICE, std::move(invalid_service)));
+ } else if (IsServiceRegistered(cid)) {
+ std::unique_ptr<FixedChannelService> invalid_service(new FixedChannelService());
+ pending_registration.user_handler_->Post(
+ common::BindOnce(std::move(pending_registration.on_registration_complete_callback_),
+ FixedChannelManager::RegistrationResult::FAIL_DUPLICATE_SERVICE, std::move(invalid_service)));
+ } else {
+ service_map_.try_emplace(cid,
+ FixedChannelServiceImpl(pending_registration.user_handler_,
+ std::move(pending_registration.on_connection_open_callback_)));
+ std::unique_ptr<FixedChannelService> user_service(new FixedChannelService(cid, this, l2cap_layer_handler_));
+ pending_registration.user_handler_->Post(
+ common::BindOnce(std::move(pending_registration.on_registration_complete_callback_),
+ FixedChannelManager::RegistrationResult::SUCCESS, std::move(user_service)));
+ }
+}
+
+void FixedChannelServiceManagerImpl::Unregister(Cid cid, FixedChannelService::OnUnregisteredCallback callback,
+ os::Handler* handler) {
+ if (IsServiceRegistered(cid)) {
+ service_map_.erase(cid);
+ handler->Post(std::move(callback));
+ } else {
+ LOG_ERROR("service not registered cid:%d", cid);
+ }
+}
+
+bool FixedChannelServiceManagerImpl::IsServiceRegistered(Cid cid) const {
+ return service_map_.find(cid) != service_map_.end();
+}
+
+FixedChannelServiceImpl* FixedChannelServiceManagerImpl::GetService(Cid cid) {
+ ASSERT(IsServiceRegistered(cid));
+ return &service_map_.find(cid)->second;
+}
+
+std::vector<std::pair<Cid, FixedChannelServiceImpl*>> FixedChannelServiceManagerImpl::GetRegisteredServices() {
+ std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+ for (auto& elem : service_map_) {
+ results.emplace_back(elem.first, &elem.second);
+ }
+ return results;
+}
+
+} // namespace internal
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/le/internal/fixed_channel_service_manager_impl.h b/gd/l2cap/le/internal/fixed_channel_service_manager_impl.h
new file mode 100644
index 0000000..d57c192
--- /dev/null
+++ b/gd/l2cap/le/internal/fixed_channel_service_manager_impl.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <unordered_map>
+
+#include "l2cap/cid.h"
+#include "l2cap/le/fixed_channel_service.h"
+#include "l2cap/le/internal/fixed_channel_service_impl.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+class FixedChannelServiceManagerImpl {
+ public:
+ explicit FixedChannelServiceManagerImpl(os::Handler* l2cap_layer_handler)
+ : l2cap_layer_handler_(l2cap_layer_handler) {}
+ virtual ~FixedChannelServiceManagerImpl() = default;
+
+ // All APIs must be invoked in L2CAP layer handler
+
+ virtual void Register(Cid cid, FixedChannelServiceImpl::PendingRegistration pending_registration);
+ virtual void Unregister(Cid cid, FixedChannelService::OnUnregisteredCallback callback, os::Handler* handler);
+ virtual bool IsServiceRegistered(Cid cid) const;
+ virtual FixedChannelServiceImpl* GetService(Cid cid);
+ virtual std::vector<std::pair<Cid, FixedChannelServiceImpl*>> GetRegisteredServices();
+
+ private:
+ os::Handler* l2cap_layer_handler_ = nullptr;
+ std::unordered_map<Cid, FixedChannelServiceImpl> service_map_;
+};
+} // namespace internal
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/le/internal/fixed_channel_service_manager_impl_mock.h b/gd/l2cap/le/internal/fixed_channel_service_manager_impl_mock.h
new file mode 100644
index 0000000..068599b
--- /dev/null
+++ b/gd/l2cap/le/internal/fixed_channel_service_manager_impl_mock.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include "l2cap/le/internal/fixed_channel_impl.h"
+#include "l2cap/le/internal/fixed_channel_service_manager_impl.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+namespace testing {
+
+class MockFixedChannelServiceManagerImpl : public FixedChannelServiceManagerImpl {
+ public:
+ MockFixedChannelServiceManagerImpl() : FixedChannelServiceManagerImpl(nullptr) {}
+ MOCK_METHOD(void, Register, (Cid cid, FixedChannelServiceImpl::PendingRegistration pending_registration), (override));
+ MOCK_METHOD(void, Unregister, (Cid cid, FixedChannelService::OnUnregisteredCallback callback, os::Handler* handler),
+ (override));
+ MOCK_METHOD(bool, IsServiceRegistered, (Cid cid), (const, override));
+ MOCK_METHOD(FixedChannelServiceImpl*, GetService, (Cid cid), (override));
+ MOCK_METHOD((std::vector<std::pair<Cid, FixedChannelServiceImpl*>>), GetRegisteredServices, (), (override));
+};
+
+} // namespace testing
+} // namespace internal
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/le/internal/fixed_channel_service_manager_test.cc b/gd/l2cap/le/internal/fixed_channel_service_manager_test.cc
new file mode 100644
index 0000000..030933c
--- /dev/null
+++ b/gd/l2cap/le/internal/fixed_channel_service_manager_test.cc
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2018 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 "l2cap/le/internal/fixed_channel_service_manager_impl.h"
+
+#include <future>
+
+#include "common/bind.h"
+#include "l2cap/cid.h"
+#include "l2cap/le/fixed_channel_manager.h"
+#include "l2cap/le/fixed_channel_service.h"
+#include "os/handler.h"
+#include "os/thread.h"
+
+#include <gtest/gtest.h>
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+class L2capLeServiceManagerTest : public ::testing::Test {
+ public:
+ ~L2capLeServiceManagerTest() override = default;
+
+ void OnServiceRegistered(bool expect_success, FixedChannelManager::RegistrationResult result,
+ std::unique_ptr<FixedChannelService> user_service) {
+ EXPECT_EQ(result == FixedChannelManager::RegistrationResult::SUCCESS, expect_success);
+ service_registered_ = expect_success;
+ }
+
+ protected:
+ void SetUp() override {
+ manager_ = new FixedChannelServiceManagerImpl{nullptr};
+ thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+ user_handler_ = new os::Handler(thread_);
+ }
+
+ void TearDown() override {
+ user_handler_->Clear();
+ delete user_handler_;
+ delete thread_;
+ delete manager_;
+ }
+
+ void sync_user_handler() {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ user_handler_->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+ future.wait_for(std::chrono::milliseconds(3));
+ }
+
+ FixedChannelServiceManagerImpl* manager_ = nullptr;
+ os::Thread* thread_ = nullptr;
+ os::Handler* user_handler_ = nullptr;
+
+ bool service_registered_ = false;
+};
+
+TEST_F(L2capLeServiceManagerTest, register_and_unregister_le_fixed_channel) {
+ FixedChannelServiceImpl::PendingRegistration pending_registration{
+ .user_handler_ = user_handler_,
+ .on_registration_complete_callback_ =
+ common::BindOnce(&L2capLeServiceManagerTest::OnServiceRegistered, common::Unretained(this), true)};
+ Cid cid = kSmpBrCid;
+ EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+ manager_->Register(cid, std::move(pending_registration));
+ EXPECT_TRUE(manager_->IsServiceRegistered(cid));
+ sync_user_handler();
+ EXPECT_TRUE(service_registered_);
+ manager_->Unregister(cid, common::BindOnce([] {}), user_handler_);
+ EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+}
+
+TEST_F(L2capLeServiceManagerTest, register_le_fixed_channel_bad_cid) {
+ FixedChannelServiceImpl::PendingRegistration pending_registration{
+ .user_handler_ = user_handler_,
+ .on_registration_complete_callback_ =
+ common::BindOnce(&L2capLeServiceManagerTest::OnServiceRegistered, common::Unretained(this), false)};
+ Cid cid = 0x1000;
+ EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+ manager_->Register(cid, std::move(pending_registration));
+ EXPECT_FALSE(manager_->IsServiceRegistered(cid));
+ sync_user_handler();
+ EXPECT_FALSE(service_registered_);
+}
+
+} // namespace internal
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/le/internal/link.h b/gd/l2cap/le/internal/link.h
new file mode 100644
index 0000000..3e75da6
--- /dev/null
+++ b/gd/l2cap/le/internal/link.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <chrono>
+#include <memory>
+
+#include "hci/acl_manager.h"
+#include "l2cap/internal/data_pipeline_manager.h"
+#include "l2cap/internal/fixed_channel_allocator.h"
+#include "l2cap/internal/parameter_provider.h"
+#include "l2cap/le/internal/fixed_channel_impl.h"
+#include "os/alarm.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+class Link {
+ public:
+ Link(os::Handler* l2cap_handler, std::unique_ptr<hci::AclConnection> acl_connection,
+ l2cap::internal::ParameterProvider* parameter_provider)
+ : l2cap_handler_(l2cap_handler), acl_connection_(std::move(acl_connection)),
+ data_pipeline_manager_(l2cap_handler, acl_connection_->GetAclQueueEnd()),
+ parameter_provider_(parameter_provider) {
+ ASSERT(l2cap_handler_ != nullptr);
+ ASSERT(acl_connection_ != nullptr);
+ ASSERT(parameter_provider_ != nullptr);
+ link_idle_disconnect_alarm_.Schedule(common::BindOnce(&Link::Disconnect, common::Unretained(this)),
+ parameter_provider_->GetLeLinkIdleDisconnectTimeout());
+ }
+
+ virtual ~Link() = default;
+
+ inline virtual hci::AddressWithType GetDevice() {
+ return {acl_connection_->GetAddress(), acl_connection_->GetAddressType()};
+ }
+
+ inline virtual hci::Role GetRole() {
+ return acl_connection_->GetRole();
+ }
+
+ // ACL methods
+
+ virtual void OnAclDisconnected(hci::ErrorCode status) {
+ fixed_channel_allocator_.OnAclDisconnected(status);
+ }
+
+ virtual void Disconnect() {
+ acl_connection_->Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION);
+ }
+
+ // FixedChannel methods
+
+ virtual std::shared_ptr<FixedChannelImpl> AllocateFixedChannel(Cid cid, SecurityPolicy security_policy) {
+ auto channel = fixed_channel_allocator_.AllocateChannel(cid, security_policy);
+ data_pipeline_manager_.AttachChannel(cid, channel);
+ return channel;
+ }
+
+ virtual bool IsFixedChannelAllocated(Cid cid) {
+ return fixed_channel_allocator_.IsChannelAllocated(cid);
+ }
+
+ // Check how many channels are acquired or in use, if zero, start tear down timer, if non-zero, cancel tear down timer
+ virtual void RefreshRefCount() {
+ int ref_count = 0;
+ ref_count += fixed_channel_allocator_.GetRefCount();
+ ASSERT_LOG(ref_count >= 0, "ref_count %d is less than 0", ref_count);
+ if (ref_count > 0) {
+ link_idle_disconnect_alarm_.Cancel();
+ } else {
+ link_idle_disconnect_alarm_.Schedule(common::BindOnce(&Link::Disconnect, common::Unretained(this)),
+ parameter_provider_->GetLeLinkIdleDisconnectTimeout());
+ }
+ }
+
+ virtual std::string ToString() {
+ return GetDevice().ToString();
+ }
+
+ private:
+ os::Handler* l2cap_handler_;
+ l2cap::internal::FixedChannelAllocator<FixedChannelImpl, Link> fixed_channel_allocator_{this, l2cap_handler_};
+ std::unique_ptr<hci::AclConnection> acl_connection_;
+ l2cap::internal::DataPipelineManager data_pipeline_manager_;
+ l2cap::internal::ParameterProvider* parameter_provider_;
+ os::Alarm link_idle_disconnect_alarm_{l2cap_handler_};
+ DISALLOW_COPY_AND_ASSIGN(Link);
+};
+
+} // namespace internal
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/le/internal/link_manager.cc b/gd/l2cap/le/internal/link_manager.cc
new file mode 100644
index 0000000..fac8cbc
--- /dev/null
+++ b/gd/l2cap/le/internal/link_manager.cc
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2019 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 <memory>
+#include <unordered_map>
+
+#include "hci/acl_manager.h"
+#include "hci/address.h"
+#include "l2cap/internal/scheduler_fifo.h"
+#include "l2cap/le/internal/link.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+#include "l2cap/le/internal/link_manager.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+void LinkManager::ConnectFixedChannelServices(hci::AddressWithType address_with_type,
+ PendingFixedChannelConnection pending_fixed_channel_connection) {
+ // Check if there is any service registered
+ auto fixed_channel_services = service_manager_->GetRegisteredServices();
+ if (fixed_channel_services.empty()) {
+ // If so, return error
+ pending_fixed_channel_connection.handler_->Post(common::BindOnce(
+ std::move(pending_fixed_channel_connection.on_fail_callback_),
+ FixedChannelManager::ConnectionResult{
+ .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_NO_SERVICE_REGISTERED}));
+ return;
+ }
+ // Otherwise, check if device has an ACL connection
+ auto* link = GetLink(address_with_type);
+ if (link != nullptr) {
+ // If device already have an ACL connection
+ // Check if all registered services have an allocated channel and allocate one if not already allocated
+ int num_new_channels = 0;
+ for (auto& fixed_channel_service : fixed_channel_services) {
+ if (link->IsFixedChannelAllocated(fixed_channel_service.first)) {
+ // This channel is already allocated for this link, do not allocated twice
+ continue;
+ }
+ // Allocate channel for newly registered fixed channels
+ auto fixed_channel_impl = link->AllocateFixedChannel(fixed_channel_service.first, SecurityPolicy());
+ fixed_channel_service.second->NotifyChannelCreation(
+ std::make_unique<FixedChannel>(fixed_channel_impl, l2cap_handler_));
+ num_new_channels++;
+ }
+ // Declare connection failure if no new channels are created
+ if (num_new_channels == 0) {
+ pending_fixed_channel_connection.handler_->Post(common::BindOnce(
+ std::move(pending_fixed_channel_connection.on_fail_callback_),
+ FixedChannelManager::ConnectionResult{
+ .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_ALL_SERVICES_HAVE_CHANNEL}));
+ }
+ // No need to create ACL connection, return without saving any pending connections
+ return;
+ }
+ // If not, create new ACL connection
+ // Add request to pending link list first
+ auto pending_link = pending_links_.find(address_with_type);
+ if (pending_link == pending_links_.end()) {
+ // Create pending link if not exist
+ pending_links_.try_emplace(address_with_type);
+ pending_link = pending_links_.find(address_with_type);
+ }
+ pending_link->second.pending_fixed_channel_connections_.push_back(std::move(pending_fixed_channel_connection));
+ // Then create new ACL connection
+ acl_manager_->CreateLeConnection(address_with_type);
+}
+
+Link* LinkManager::GetLink(hci::AddressWithType address_with_type) {
+ if (links_.find(address_with_type) == links_.end()) {
+ return nullptr;
+ }
+ return &links_.find(address_with_type)->second;
+}
+
+void LinkManager::OnLeConnectSuccess(hci::AddressWithType connecting_address_with_type,
+ std::unique_ptr<hci::AclConnection> acl_connection) {
+ // Same link should not be connected twice
+ hci::AddressWithType connected_address_with_type(acl_connection->GetAddress(), acl_connection->GetAddressType());
+ ASSERT_LOG(GetLink(connected_address_with_type) == nullptr, "%s is connected twice without disconnection",
+ acl_connection->GetAddress().ToString().c_str());
+ // Register ACL disconnection callback in LinkManager so that we can clean up link resource properly
+ acl_connection->RegisterDisconnectCallback(
+ common::BindOnce(&LinkManager::OnDisconnect, common::Unretained(this), connected_address_with_type),
+ l2cap_handler_);
+ links_.try_emplace(connected_address_with_type, l2cap_handler_, std::move(acl_connection), parameter_provider_);
+ auto* link = GetLink(connected_address_with_type);
+ // Allocate and distribute channels for all registered fixed channel services
+ auto fixed_channel_services = service_manager_->GetRegisteredServices();
+ for (auto& fixed_channel_service : fixed_channel_services) {
+ auto fixed_channel_impl = link->AllocateFixedChannel(fixed_channel_service.first, SecurityPolicy());
+ fixed_channel_service.second->NotifyChannelCreation(
+ std::make_unique<FixedChannel>(fixed_channel_impl, l2cap_handler_));
+ }
+ // Remove device from pending links list, if any
+ auto pending_link = pending_links_.find(connecting_address_with_type);
+ if (pending_link == pending_links_.end()) {
+ // This an incoming connection, exit
+ return;
+ }
+ // This is an outgoing connection, remove entry in pending link list
+ pending_links_.erase(pending_link);
+}
+
+void LinkManager::OnLeConnectFail(hci::AddressWithType address_with_type, hci::ErrorCode reason) {
+ // Notify all pending links for this device
+ auto pending_link = pending_links_.find(address_with_type);
+ if (pending_link == pending_links_.end()) {
+ // There is no pending link, exit
+ LOG_DEBUG("Connection to %s failed without a pending link", address_with_type.ToString().c_str());
+ return;
+ }
+ for (auto& pending_fixed_channel_connection : pending_link->second.pending_fixed_channel_connections_) {
+ pending_fixed_channel_connection.handler_->Post(common::BindOnce(
+ std::move(pending_fixed_channel_connection.on_fail_callback_),
+ FixedChannelManager::ConnectionResult{
+ .connection_result_code = FixedChannelManager::ConnectionResultCode::FAIL_HCI_ERROR, .hci_error = reason}));
+ }
+ // Remove entry in pending link list
+ pending_links_.erase(pending_link);
+}
+
+void LinkManager::OnDisconnect(hci::AddressWithType address_with_type, hci::ErrorCode status) {
+ auto* link = GetLink(address_with_type);
+ ASSERT_LOG(link != nullptr, "Device %s is disconnected with reason 0x%x, but not in local database",
+ address_with_type.ToString().c_str(), static_cast<uint8_t>(status));
+ link->OnAclDisconnected(status);
+ links_.erase(address_with_type);
+}
+
+} // namespace internal
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/le/internal/link_manager.h b/gd/l2cap/le/internal/link_manager.h
new file mode 100644
index 0000000..f318b83
--- /dev/null
+++ b/gd/l2cap/le/internal/link_manager.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <memory>
+#include <unordered_map>
+#include <utility>
+
+#include "os/handler.h"
+
+#include "hci/acl_manager.h"
+#include "hci/address.h"
+#include "hci/address_with_type.h"
+#include "l2cap/internal/parameter_provider.h"
+#include "l2cap/internal/scheduler.h"
+#include "l2cap/le/fixed_channel_manager.h"
+#include "l2cap/le/internal/fixed_channel_service_manager_impl.h"
+#include "l2cap/le/internal/link.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+class LinkManager : public hci::LeConnectionCallbacks {
+ public:
+ LinkManager(os::Handler* l2cap_handler, hci::AclManager* acl_manager, FixedChannelServiceManagerImpl* service_manager,
+ l2cap::internal::ParameterProvider* parameter_provider)
+ : l2cap_handler_(l2cap_handler), acl_manager_(acl_manager), service_manager_(service_manager),
+ parameter_provider_(parameter_provider) {
+ acl_manager_->RegisterLeCallbacks(this, l2cap_handler_);
+ }
+
+ struct PendingFixedChannelConnection {
+ os::Handler* handler_;
+ FixedChannelManager::OnConnectionFailureCallback on_fail_callback_;
+ };
+
+ struct PendingLink {
+ std::vector<PendingFixedChannelConnection> pending_fixed_channel_connections_;
+ };
+
+ // ACL methods
+
+ Link* GetLink(hci::AddressWithType address_with_type);
+ void OnLeConnectSuccess(hci::AddressWithType connecting_address_with_type,
+ std::unique_ptr<hci::AclConnection> acl_connection) override;
+ void OnLeConnectFail(hci::AddressWithType address_with_type, hci::ErrorCode reason) override;
+ void OnDisconnect(hci::AddressWithType address_with_type, hci::ErrorCode status);
+
+ // FixedChannelManager methods
+
+ void ConnectFixedChannelServices(hci::AddressWithType address_with_type,
+ PendingFixedChannelConnection pending_fixed_channel_connection);
+
+ private:
+ // Dependencies
+ os::Handler* l2cap_handler_;
+ hci::AclManager* acl_manager_;
+ FixedChannelServiceManagerImpl* service_manager_;
+ l2cap::internal::ParameterProvider* parameter_provider_;
+
+ // Internal states
+ std::unordered_map<hci::AddressWithType, PendingLink> pending_links_;
+ std::unordered_map<hci::AddressWithType, Link> links_;
+ DISALLOW_COPY_AND_ASSIGN(LinkManager);
+};
+
+} // namespace internal
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/le/internal/link_manager_test.cc b/gd/l2cap/le/internal/link_manager_test.cc
new file mode 100644
index 0000000..59d8d6c
--- /dev/null
+++ b/gd/l2cap/le/internal/link_manager_test.cc
@@ -0,0 +1,472 @@
+/*
+ * Copyright 2018 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 "l2cap/le/internal/link_manager.h"
+
+#include <future>
+#include <thread>
+
+#include "common/bind.h"
+#include "common/testing/bind_test_util.h"
+#include "hci/acl_manager_mock.h"
+#include "hci/address.h"
+#include "l2cap/cid.h"
+#include "l2cap/internal/parameter_provider_mock.h"
+#include "l2cap/le/fixed_channel_manager.h"
+#include "l2cap/le/internal/fixed_channel_service_impl_mock.h"
+#include "l2cap/le/internal/fixed_channel_service_manager_impl_mock.h"
+#include "os/handler.h"
+#include "os/thread.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+
+using hci::testing::MockAclConnection;
+using hci::testing::MockAclManager;
+using l2cap::internal::testing::MockParameterProvider;
+using ::testing::_; // Matcher to any value
+using ::testing::ByMove;
+using ::testing::DoAll;
+using testing::MockFixedChannelServiceImpl;
+using testing::MockFixedChannelServiceManagerImpl;
+using ::testing::Return;
+using ::testing::SaveArg;
+
+constexpr static auto kTestIdleDisconnectTimeoutLong = std::chrono::milliseconds(1000);
+constexpr static auto kTestIdleDisconnectTimeoutShort = std::chrono::milliseconds(30);
+
+class L2capLeLinkManagerTest : public ::testing::Test {
+ public:
+ static void SyncHandler(os::Handler* handler) {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+ future.wait_for(std::chrono::milliseconds(3));
+ }
+
+ protected:
+ void SetUp() override {
+ thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+ l2cap_handler_ = new os::Handler(thread_);
+ mock_parameter_provider_ = new MockParameterProvider;
+ EXPECT_CALL(*mock_parameter_provider_, GetLeLinkIdleDisconnectTimeout)
+ .WillRepeatedly(Return(kTestIdleDisconnectTimeoutLong));
+ }
+
+ void TearDown() override {
+ delete mock_parameter_provider_;
+ l2cap_handler_->Clear();
+ delete l2cap_handler_;
+ delete thread_;
+ }
+
+ os::Thread* thread_ = nullptr;
+ os::Handler* l2cap_handler_ = nullptr;
+ MockParameterProvider* mock_parameter_provider_ = nullptr;
+};
+
+TEST_F(L2capLeLinkManagerTest, connect_fixed_channel_service_without_acl) {
+ MockFixedChannelServiceManagerImpl mock_le_fixed_channel_service_manager;
+ MockAclManager mock_acl_manager;
+ hci::AddressWithType address_with_type({{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
+ hci::AddressType::RANDOM_DEVICE_ADDRESS);
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+
+ // Step 1: Verify callback registration with HCI
+ hci::LeConnectionCallbacks* hci_le_connection_callbacks = nullptr;
+ os::Handler* hci_callback_handler = nullptr;
+ EXPECT_CALL(mock_acl_manager, RegisterLeCallbacks(_, _))
+ .WillOnce(DoAll(SaveArg<0>(&hci_le_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+ LinkManager le_link_manager(l2cap_handler_, &mock_acl_manager, &mock_le_fixed_channel_service_manager,
+ mock_parameter_provider_);
+ EXPECT_EQ(hci_le_connection_callbacks, &le_link_manager);
+ EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+ // Register fake services
+ MockFixedChannelServiceImpl mock_service_1, mock_service_2;
+ std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+ results.emplace_back(kSmpBrCid, &mock_service_1);
+ results.emplace_back(kConnectionlessCid, &mock_service_2);
+ EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+ // Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
+ EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type)).Times(1);
+ LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+ .handler_ = user_handler.get(),
+ .on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
+ le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection));
+
+ // Step 3: ACL connection success event should trigger channel creation for all registered services
+
+ std::unique_ptr<MockAclConnection> acl_connection = std::make_unique<MockAclConnection>();
+ EXPECT_CALL(*acl_connection, RegisterDisconnectCallback(_, l2cap_handler_)).Times(1);
+ EXPECT_CALL(*acl_connection, GetAddress()).WillRepeatedly(Return(address_with_type.GetAddress()));
+ EXPECT_CALL(*acl_connection, GetAddressType()).WillRepeatedly(Return(address_with_type.GetAddressType()));
+ std::unique_ptr<FixedChannel> channel_1, channel_2;
+ EXPECT_CALL(mock_service_1, NotifyChannelCreation(_)).WillOnce([&channel_1](std::unique_ptr<FixedChannel> channel) {
+ channel_1 = std::move(channel);
+ });
+ EXPECT_CALL(mock_service_2, NotifyChannelCreation(_)).WillOnce([&channel_2](std::unique_ptr<FixedChannel> channel) {
+ channel_2 = std::move(channel);
+ });
+ hci_callback_handler->Post(common::BindOnce(&hci::LeConnectionCallbacks::OnLeConnectSuccess,
+ common::Unretained(hci_le_connection_callbacks), address_with_type,
+ std::move(acl_connection)));
+ SyncHandler(hci_callback_handler);
+ EXPECT_NE(channel_1, nullptr);
+ EXPECT_NE(channel_2, nullptr);
+
+ // Step 4: Calling ConnectServices() to the same device will no trigger another connection attempt
+ FixedChannelManager::ConnectionResult my_result;
+ LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection_2{
+ .handler_ = user_handler.get(),
+ .on_fail_callback_ = common::testing::BindLambdaForTesting(
+ [&my_result](FixedChannelManager::ConnectionResult result) { my_result = result; })};
+ le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection_2));
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(my_result.connection_result_code,
+ FixedChannelManager::ConnectionResultCode::FAIL_ALL_SERVICES_HAVE_CHANNEL);
+
+ // Step 5: Register new service will cause new channels to be created during ConnectServices()
+ MockFixedChannelServiceImpl mock_service_3;
+ results.emplace_back(kSmpBrCid + 1, &mock_service_3);
+ EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+ LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection_3{
+ .handler_ = user_handler.get(),
+ .on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
+ std::unique_ptr<FixedChannel> channel_3;
+ EXPECT_CALL(mock_service_3, NotifyChannelCreation(_)).WillOnce([&channel_3](std::unique_ptr<FixedChannel> channel) {
+ channel_3 = std::move(channel);
+ });
+ le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection_3));
+ EXPECT_NE(channel_3, nullptr);
+
+ user_handler->Clear();
+
+ le_link_manager.OnDisconnect(address_with_type, hci::ErrorCode::SUCCESS);
+}
+
+TEST_F(L2capLeLinkManagerTest, connect_fixed_channel_service_without_acl_with_no_service) {
+ MockFixedChannelServiceManagerImpl mock_le_fixed_channel_service_manager;
+ MockAclManager mock_acl_manager;
+ hci::AddressWithType address_with_type({{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
+ hci::AddressType::PUBLIC_DEVICE_ADDRESS);
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+
+ // Step 1: Verify callback registration with HCI
+ hci::LeConnectionCallbacks* hci_le_connection_callbacks = nullptr;
+ os::Handler* hci_callback_handler = nullptr;
+ EXPECT_CALL(mock_acl_manager, RegisterLeCallbacks(_, _))
+ .WillOnce(DoAll(SaveArg<0>(&hci_le_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+ LinkManager le_link_manager(l2cap_handler_, &mock_acl_manager, &mock_le_fixed_channel_service_manager,
+ mock_parameter_provider_);
+ EXPECT_EQ(hci_le_connection_callbacks, &le_link_manager);
+ EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+ // Make sure no service is registered
+ std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+ EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+ // Step 2: Connect to fixed channel without any service registered will result in failure
+ EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type)).Times(0);
+ FixedChannelManager::ConnectionResult my_result;
+ LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+ .handler_ = user_handler.get(),
+ .on_fail_callback_ = common::testing::BindLambdaForTesting(
+ [&my_result](FixedChannelManager::ConnectionResult result) { my_result = result; })};
+ le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection));
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(my_result.connection_result_code, FixedChannelManager::ConnectionResultCode::FAIL_NO_SERVICE_REGISTERED);
+
+ user_handler->Clear();
+}
+
+TEST_F(L2capLeLinkManagerTest, connect_fixed_channel_service_without_acl_with_hci_failure) {
+ MockFixedChannelServiceManagerImpl mock_le_fixed_channel_service_manager;
+ MockAclManager mock_acl_manager;
+ hci::AddressWithType address_with_type({{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
+ hci::AddressType::RANDOM_DEVICE_ADDRESS);
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+
+ // Step 1: Verify callback registration with HCI
+ hci::LeConnectionCallbacks* hci_le_connection_callbacks = nullptr;
+ os::Handler* hci_callback_handler = nullptr;
+ EXPECT_CALL(mock_acl_manager, RegisterLeCallbacks(_, _))
+ .WillOnce(DoAll(SaveArg<0>(&hci_le_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+ LinkManager le_link_manager(l2cap_handler_, &mock_acl_manager, &mock_le_fixed_channel_service_manager,
+ mock_parameter_provider_);
+ EXPECT_EQ(hci_le_connection_callbacks, &le_link_manager);
+ EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+ // Register fake services
+ MockFixedChannelServiceImpl mock_service_1;
+ std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+ results.emplace_back(kSmpBrCid, &mock_service_1);
+ EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+ // Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
+ EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type)).Times(1);
+ FixedChannelManager::ConnectionResult my_result;
+ LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+ .handler_ = user_handler.get(),
+ .on_fail_callback_ = common::testing::BindLambdaForTesting(
+ [&my_result](FixedChannelManager::ConnectionResult result) { my_result = result; })};
+ le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection));
+
+ // Step 3: ACL connection failure event should trigger connection failure callback
+ EXPECT_CALL(mock_service_1, NotifyChannelCreation(_)).Times(0);
+ hci_callback_handler->Post(common::BindOnce(&hci::LeConnectionCallbacks::OnLeConnectFail,
+ common::Unretained(hci_le_connection_callbacks), address_with_type,
+ hci::ErrorCode::PAGE_TIMEOUT));
+ SyncHandler(hci_callback_handler);
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(my_result.connection_result_code, FixedChannelManager::ConnectionResultCode::FAIL_HCI_ERROR);
+ EXPECT_EQ(my_result.hci_error, hci::ErrorCode::PAGE_TIMEOUT);
+
+ user_handler->Clear();
+}
+
+TEST_F(L2capLeLinkManagerTest, not_acquiring_channels_should_disconnect_acl_after_timeout) {
+ EXPECT_CALL(*mock_parameter_provider_, GetLeLinkIdleDisconnectTimeout)
+ .WillRepeatedly(Return(kTestIdleDisconnectTimeoutShort));
+ MockFixedChannelServiceManagerImpl mock_le_fixed_channel_service_manager;
+ MockAclManager mock_acl_manager;
+ hci::AddressWithType address_with_type({{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
+ hci::AddressType::RANDOM_DEVICE_ADDRESS);
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+
+ // Step 1: Verify callback registration with HCI
+ hci::LeConnectionCallbacks* hci_le_connection_callbacks = nullptr;
+ os::Handler* hci_callback_handler = nullptr;
+ EXPECT_CALL(mock_acl_manager, RegisterLeCallbacks(_, _))
+ .WillOnce(DoAll(SaveArg<0>(&hci_le_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+ LinkManager le_link_manager(l2cap_handler_, &mock_acl_manager, &mock_le_fixed_channel_service_manager,
+ mock_parameter_provider_);
+ EXPECT_EQ(hci_le_connection_callbacks, &le_link_manager);
+ EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+ // Register fake services
+ MockFixedChannelServiceImpl mock_service_1, mock_service_2;
+ std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+ results.emplace_back(kSmpBrCid, &mock_service_1);
+ results.emplace_back(kConnectionlessCid, &mock_service_2);
+ EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+ // Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
+ EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type)).Times(1);
+ LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+ .handler_ = user_handler.get(),
+ .on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
+ le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection));
+
+ // Step 3: ACL connection success event should trigger channel creation for all registered services
+ auto* raw_acl_connection = new MockAclConnection();
+ std::unique_ptr<MockAclConnection> acl_connection(raw_acl_connection);
+ EXPECT_CALL(*acl_connection, GetAddress()).WillRepeatedly(Return(address_with_type.GetAddress()));
+ EXPECT_CALL(*acl_connection, GetAddressType()).WillRepeatedly(Return(address_with_type.GetAddressType()));
+ std::unique_ptr<FixedChannel> channel_1, channel_2;
+ EXPECT_CALL(mock_service_1, NotifyChannelCreation(_)).WillOnce([&channel_1](std::unique_ptr<FixedChannel> channel) {
+ channel_1 = std::move(channel);
+ });
+ EXPECT_CALL(mock_service_2, NotifyChannelCreation(_)).WillOnce([&channel_2](std::unique_ptr<FixedChannel> channel) {
+ channel_2 = std::move(channel);
+ });
+ hci_callback_handler->Post(common::BindOnce(&hci::LeConnectionCallbacks::OnLeConnectSuccess,
+ common::Unretained(hci_le_connection_callbacks), address_with_type,
+ std::move(acl_connection)));
+ SyncHandler(hci_callback_handler);
+ EXPECT_NE(channel_1, nullptr);
+ EXPECT_NE(channel_2, nullptr);
+ hci::ErrorCode status_1 = hci::ErrorCode::SUCCESS;
+ channel_1->RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_1 = status; }));
+ hci::ErrorCode status_2 = hci::ErrorCode::SUCCESS;
+ channel_2->RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_2 = status; }));
+
+ // Step 4: ave channel IDLE long enough, they will disconnect
+ EXPECT_CALL(*raw_acl_connection, Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION)).Times(1);
+ std::this_thread::sleep_for(kTestIdleDisconnectTimeoutShort * 1.2);
+
+ // Step 5: Link disconnect will trigger all callbacks
+ le_link_manager.OnDisconnect(address_with_type, hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST);
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_1);
+ EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_2);
+
+ user_handler->Clear();
+}
+
+TEST_F(L2capLeLinkManagerTest, acquiring_channels_should_not_disconnect_acl_after_timeout) {
+ EXPECT_CALL(*mock_parameter_provider_, GetLeLinkIdleDisconnectTimeout)
+ .WillRepeatedly(Return(kTestIdleDisconnectTimeoutShort));
+ MockFixedChannelServiceManagerImpl mock_le_fixed_channel_service_manager;
+ MockAclManager mock_acl_manager;
+ hci::AddressWithType address_with_type({{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
+ hci::AddressType::RANDOM_DEVICE_ADDRESS);
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+
+ // Step 1: Verify callback registration with HCI
+ hci::LeConnectionCallbacks* hci_le_connection_callbacks = nullptr;
+ os::Handler* hci_callback_handler = nullptr;
+ EXPECT_CALL(mock_acl_manager, RegisterLeCallbacks(_, _))
+ .WillOnce(DoAll(SaveArg<0>(&hci_le_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+ LinkManager le_link_manager(l2cap_handler_, &mock_acl_manager, &mock_le_fixed_channel_service_manager,
+ mock_parameter_provider_);
+ EXPECT_EQ(hci_le_connection_callbacks, &le_link_manager);
+ EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+ // Register fake services
+ MockFixedChannelServiceImpl mock_service_1, mock_service_2;
+ std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+ results.emplace_back(kSmpBrCid, &mock_service_1);
+ results.emplace_back(kConnectionlessCid, &mock_service_2);
+ EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+ // Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
+ EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type)).Times(1);
+ LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+ .handler_ = user_handler.get(),
+ .on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
+ le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection));
+
+ // Step 3: ACL connection success event should trigger channel creation for all registered services
+ auto* raw_acl_connection = new MockAclConnection();
+ std::unique_ptr<MockAclConnection> acl_connection(raw_acl_connection);
+ EXPECT_CALL(*acl_connection, GetAddress()).WillRepeatedly(Return(address_with_type.GetAddress()));
+ EXPECT_CALL(*acl_connection, GetAddressType()).WillRepeatedly(Return(address_with_type.GetAddressType()));
+ std::unique_ptr<FixedChannel> channel_1, channel_2;
+ EXPECT_CALL(mock_service_1, NotifyChannelCreation(_)).WillOnce([&channel_1](std::unique_ptr<FixedChannel> channel) {
+ channel_1 = std::move(channel);
+ });
+ EXPECT_CALL(mock_service_2, NotifyChannelCreation(_)).WillOnce([&channel_2](std::unique_ptr<FixedChannel> channel) {
+ channel_2 = std::move(channel);
+ });
+ hci_callback_handler->Post(common::BindOnce(&hci::LeConnectionCallbacks::OnLeConnectSuccess,
+ common::Unretained(hci_le_connection_callbacks), address_with_type,
+ std::move(acl_connection)));
+ SyncHandler(hci_callback_handler);
+ EXPECT_NE(channel_1, nullptr);
+ EXPECT_NE(channel_2, nullptr);
+ hci::ErrorCode status_1 = hci::ErrorCode::SUCCESS;
+ channel_1->RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_1 = status; }));
+ hci::ErrorCode status_2 = hci::ErrorCode::SUCCESS;
+ channel_2->RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_2 = status; }));
+
+ channel_1->Acquire();
+
+ // Step 4: ave channel IDLE, it won't disconnect to due acquired channel 1
+ EXPECT_CALL(*raw_acl_connection, Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION)).Times(0);
+ std::this_thread::sleep_for(kTestIdleDisconnectTimeoutShort * 2);
+
+ // Step 5: Link disconnect will trigger all callbacks
+ le_link_manager.OnDisconnect(address_with_type, hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST);
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_1);
+ EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_2);
+
+ user_handler->Clear();
+}
+
+TEST_F(L2capLeLinkManagerTest, acquiring_and_releasing_channels_should_eventually_disconnect_acl) {
+ EXPECT_CALL(*mock_parameter_provider_, GetLeLinkIdleDisconnectTimeout)
+ .WillRepeatedly(Return(kTestIdleDisconnectTimeoutShort));
+ MockFixedChannelServiceManagerImpl mock_le_fixed_channel_service_manager;
+ MockAclManager mock_acl_manager;
+ hci::AddressWithType address_with_type({{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}},
+ hci::AddressType::PUBLIC_IDENTITY_ADDRESS);
+ auto user_handler = std::make_unique<os::Handler>(thread_);
+
+ // Step 1: Verify callback registration with HCI
+ hci::LeConnectionCallbacks* hci_le_connection_callbacks = nullptr;
+ os::Handler* hci_callback_handler = nullptr;
+ EXPECT_CALL(mock_acl_manager, RegisterLeCallbacks(_, _))
+ .WillOnce(DoAll(SaveArg<0>(&hci_le_connection_callbacks), SaveArg<1>(&hci_callback_handler)));
+ LinkManager le_link_manager(l2cap_handler_, &mock_acl_manager, &mock_le_fixed_channel_service_manager,
+ mock_parameter_provider_);
+ EXPECT_EQ(hci_le_connection_callbacks, &le_link_manager);
+ EXPECT_EQ(hci_callback_handler, l2cap_handler_);
+
+ // Register fake services
+ MockFixedChannelServiceImpl mock_service_1, mock_service_2;
+ std::vector<std::pair<Cid, FixedChannelServiceImpl*>> results;
+ results.emplace_back(kSmpBrCid, &mock_service_1);
+ results.emplace_back(kConnectionlessCid, &mock_service_2);
+ EXPECT_CALL(mock_le_fixed_channel_service_manager, GetRegisteredServices()).WillRepeatedly(Return(results));
+
+ // Step 2: Connect to fixed channel without ACL connection should trigger ACL connection process
+ EXPECT_CALL(mock_acl_manager, CreateLeConnection(address_with_type)).Times(1);
+ LinkManager::PendingFixedChannelConnection pending_fixed_channel_connection{
+ .handler_ = user_handler.get(),
+ .on_fail_callback_ = common::BindOnce([](FixedChannelManager::ConnectionResult result) { FAIL(); })};
+ le_link_manager.ConnectFixedChannelServices(address_with_type, std::move(pending_fixed_channel_connection));
+
+ // Step 3: ACL connection success event should trigger channel creation for all registered services
+ auto* raw_acl_connection = new MockAclConnection();
+ std::unique_ptr<MockAclConnection> acl_connection(raw_acl_connection);
+ EXPECT_CALL(*acl_connection, GetAddress()).WillRepeatedly(Return(address_with_type.GetAddress()));
+ EXPECT_CALL(*acl_connection, GetAddressType()).WillRepeatedly(Return(address_with_type.GetAddressType()));
+ std::unique_ptr<FixedChannel> channel_1, channel_2;
+ EXPECT_CALL(mock_service_1, NotifyChannelCreation(_)).WillOnce([&channel_1](std::unique_ptr<FixedChannel> channel) {
+ channel_1 = std::move(channel);
+ });
+ EXPECT_CALL(mock_service_2, NotifyChannelCreation(_)).WillOnce([&channel_2](std::unique_ptr<FixedChannel> channel) {
+ channel_2 = std::move(channel);
+ });
+ hci_callback_handler->Post(common::BindOnce(&hci::LeConnectionCallbacks::OnLeConnectSuccess,
+ common::Unretained(hci_le_connection_callbacks), address_with_type,
+ std::move(acl_connection)));
+ SyncHandler(hci_callback_handler);
+ EXPECT_NE(channel_1, nullptr);
+ EXPECT_NE(channel_2, nullptr);
+ hci::ErrorCode status_1 = hci::ErrorCode::SUCCESS;
+ channel_1->RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_1 = status; }));
+ hci::ErrorCode status_2 = hci::ErrorCode::SUCCESS;
+ channel_2->RegisterOnCloseCallback(
+ user_handler.get(), common::testing::BindLambdaForTesting([&](hci::ErrorCode status) { status_2 = status; }));
+
+ channel_1->Acquire();
+
+ // Step 4: ave channel IDLE, it won't disconnect to due acquired channel 1
+ EXPECT_CALL(*raw_acl_connection, Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION)).Times(0);
+ std::this_thread::sleep_for(kTestIdleDisconnectTimeoutShort * 2);
+
+ // Step 5: ave channel IDLE long enough, they will disconnect
+ channel_1->Release();
+ EXPECT_CALL(*raw_acl_connection, Disconnect(hci::DisconnectReason::REMOTE_USER_TERMINATED_CONNECTION)).Times(1);
+ std::this_thread::sleep_for(kTestIdleDisconnectTimeoutShort * 1.2);
+
+ // Step 6: Link disconnect will trigger all callbacks
+ le_link_manager.OnDisconnect(address_with_type, hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST);
+ SyncHandler(user_handler.get());
+ EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_1);
+ EXPECT_EQ(hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST, status_2);
+
+ user_handler->Clear();
+}
+
+} // namespace internal
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/le/internal/link_mock.h b/gd/l2cap/le/internal/link_mock.h
new file mode 100644
index 0000000..5d537b3
--- /dev/null
+++ b/gd/l2cap/le/internal/link_mock.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include "hci/acl_manager_mock.h"
+#include "hci/address_with_type.h"
+#include "l2cap/internal/scheduler_mock.h"
+#include "l2cap/le/internal/link.h"
+
+#include <gmock/gmock.h>
+
+// Unit test interfaces
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+namespace internal {
+namespace testing {
+
+using hci::testing::MockAclConnection;
+
+class MockLink : public Link {
+ public:
+ explicit MockLink(os::Handler* handler, l2cap::internal::ParameterProvider* parameter_provider)
+ : Link(handler, std::make_unique<MockAclConnection>(), parameter_provider){};
+ MOCK_METHOD(hci::AddressWithType, GetDevice, (), (override));
+ MOCK_METHOD(hci::Role, GetRole, (), (override));
+ MOCK_METHOD(void, OnAclDisconnected, (hci::ErrorCode status), (override));
+ MOCK_METHOD(void, Disconnect, (), (override));
+ MOCK_METHOD(std::shared_ptr<FixedChannelImpl>, AllocateFixedChannel, (Cid cid, SecurityPolicy security_policy),
+ (override));
+ MOCK_METHOD(bool, IsFixedChannelAllocated, (Cid cid), (override));
+ MOCK_METHOD(void, RefreshRefCount, (), (override));
+};
+
+} // namespace testing
+} // namespace internal
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/le/l2cap_le_module.cc b/gd/l2cap/le/l2cap_le_module.cc
new file mode 100644
index 0000000..781843d
--- /dev/null
+++ b/gd/l2cap/le/l2cap_le_module.cc
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2019 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.
+ */
+#define LOG_TAG "l2cap2"
+
+#include <memory>
+
+#include "common/bidi_queue.h"
+#include "hci/acl_manager.h"
+#include "hci/address.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "l2cap/internal/parameter_provider.h"
+#include "l2cap/le/internal/fixed_channel_service_manager_impl.h"
+#include "l2cap/le/internal/link_manager.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+#include "l2cap/le/l2cap_le_module.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+
+const ModuleFactory L2capLeModule::Factory = ModuleFactory([]() { return new L2capLeModule(); });
+
+struct L2capLeModule::impl {
+ impl(os::Handler* l2cap_handler, hci::AclManager* acl_manager)
+ : l2cap_handler_(l2cap_handler), acl_manager_(acl_manager) {}
+ os::Handler* l2cap_handler_;
+ hci::AclManager* acl_manager_;
+ l2cap::internal::ParameterProvider parameter_provider_;
+ internal::FixedChannelServiceManagerImpl fixed_channel_service_manager_impl_{l2cap_handler_};
+ internal::LinkManager link_manager_{l2cap_handler_, acl_manager_, &fixed_channel_service_manager_impl_,
+ ¶meter_provider_};
+};
+
+void L2capLeModule::ListDependencies(ModuleList* list) {
+ list->add<hci::AclManager>();
+}
+
+void L2capLeModule::Start() {
+ pimpl_ = std::make_unique<impl>(GetHandler(), GetDependency<hci::AclManager>());
+}
+
+void L2capLeModule::Stop() {
+ pimpl_.reset();
+}
+
+std::string L2capLeModule::ToString() const {
+ return "L2cap Le Module";
+}
+
+std::unique_ptr<FixedChannelManager> L2capLeModule::GetFixedChannelManager() {
+ return std::unique_ptr<FixedChannelManager>(new FixedChannelManager(&pimpl_->fixed_channel_service_manager_impl_,
+ &pimpl_->link_manager_, pimpl_->l2cap_handler_));
+}
+
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/le/l2cap_le_module.h b/gd/l2cap/le/l2cap_le_module.h
new file mode 100644
index 0000000..3ee6acf
--- /dev/null
+++ b/gd/l2cap/le/l2cap_le_module.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <memory>
+
+#include "l2cap/le/fixed_channel_manager.h"
+#include "module.h"
+
+namespace bluetooth {
+namespace l2cap {
+namespace le {
+
+class L2capLeModule : public bluetooth::Module {
+ public:
+ L2capLeModule() = default;
+ ~L2capLeModule() = default;
+
+ /**
+ * Get the api to the LE fixed channel l2cap module
+ */
+ std::unique_ptr<FixedChannelManager> GetFixedChannelManager();
+
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override;
+
+ void Start() override;
+
+ void Stop() override;
+
+ std::string ToString() const override;
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+ DISALLOW_COPY_AND_ASSIGN(L2capLeModule);
+};
+
+} // namespace le
+} // namespace l2cap
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/mtu.h b/gd/l2cap/mtu.h
new file mode 100644
index 0000000..fa9bc64
--- /dev/null
+++ b/gd/l2cap/mtu.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <cstdint>
+
+namespace bluetooth {
+namespace l2cap {
+
+using Mtu = uint16_t;
+
+constexpr Mtu kMinimumClassicMtu = 48;
+constexpr Mtu kMinimumLeMtu = 23;
+constexpr Mtu kDefaultClassicMtu = 672;
+
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/psm.h b/gd/l2cap/psm.h
new file mode 100644
index 0000000..0e89e62
--- /dev/null
+++ b/gd/l2cap/psm.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+namespace bluetooth {
+namespace l2cap {
+
+using Psm = uint16_t;
+constexpr Psm kDefaultPsm = 0; // Invalid Psm as a default value
+
+constexpr bool IsPsmValid(Psm psm) {
+ // See Core spec 5.1 Vol 3 Part A 4.2 for definition
+ return (psm & 0x0101u) == 0x0001u;
+}
+
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/security_policy.h b/gd/l2cap/security_policy.h
new file mode 100644
index 0000000..5a06401
--- /dev/null
+++ b/gd/l2cap/security_policy.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+namespace bluetooth {
+namespace l2cap {
+
+class SecurityPolicy {};
+
+} // namespace l2cap
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/l2cap/signal_id.h b/gd/l2cap/signal_id.h
new file mode 100644
index 0000000..24372b1
--- /dev/null
+++ b/gd/l2cap/signal_id.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+namespace bluetooth {
+namespace l2cap {
+
+struct SignalId {
+ public:
+ constexpr SignalId(uint8_t value) : value_(value) {}
+ constexpr SignalId() : value_(1) {}
+ ~SignalId() = default;
+
+ uint8_t Value() const {
+ return value_;
+ }
+
+ bool IsValid() const {
+ return value_ != 0;
+ }
+
+ friend bool operator==(const SignalId& lhs, const SignalId& rhs);
+ friend bool operator!=(const SignalId& lhs, const SignalId& rhs);
+
+ struct SignalId& operator++(); // Prefix increment operator.
+ struct SignalId operator++(int); // Postfix increment operator.
+ struct SignalId& operator--(); // Prefix decrement operator.
+ struct SignalId operator--(int); // Postfix decrement operator.
+
+ private:
+ uint8_t value_;
+};
+
+constexpr SignalId kInvalidSignalId{0};
+constexpr SignalId kInitialSignalId{1};
+
+inline bool operator==(const SignalId& lhs, const SignalId& rhs) {
+ return lhs.value_ == rhs.value_;
+}
+
+inline bool operator!=(const SignalId& lhs, const SignalId& rhs) {
+ return !(lhs == rhs);
+}
+
+inline struct SignalId& SignalId::operator++() {
+ value_++;
+ if (value_ == 0) value_++;
+ return *this;
+}
+
+inline struct SignalId SignalId::operator++(int) {
+ struct SignalId tmp = *this;
+ ++*this;
+ return tmp;
+}
+
+inline struct SignalId& SignalId::operator--() {
+ value_--;
+ if (value_ == 0) value_ = 0xff;
+ return *this;
+}
+
+inline struct SignalId SignalId::operator--(int) {
+ struct SignalId tmp = *this;
+ --*this;
+ return tmp;
+}
+
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/l2cap/signal_id_test.cc b/gd/l2cap/signal_id_test.cc
new file mode 100644
index 0000000..cd95425
--- /dev/null
+++ b/gd/l2cap/signal_id_test.cc
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2019 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 <gtest/gtest.h>
+#include <cstdint>
+
+#include "l2cap/signal_id.h"
+
+namespace bluetooth {
+namespace l2cap {
+
+TEST(L2capSignalIdTest, valid_values) {
+ int valid = 0;
+ uint8_t i = 0;
+ while (++i != 0) {
+ SignalId signal_id(i);
+ if (signal_id.IsValid()) {
+ valid++;
+ }
+ }
+ ASSERT_TRUE(valid == 255);
+}
+
+TEST(L2capSignalIdTest, zero_invalid) {
+ SignalId signal_id(0);
+ ASSERT_FALSE(signal_id.IsValid());
+}
+
+TEST(L2capSignalIdTest, pre_increment) {
+ SignalId signal_id(0);
+ ASSERT_FALSE(signal_id.IsValid());
+
+ for (uint8_t i = 0; i != 0xff; ++i, ++signal_id) {
+ ASSERT_TRUE(i == signal_id.Value());
+ }
+}
+
+TEST(L2capSignalIdTest, post_increment) {
+ SignalId signal_id(0);
+ ASSERT_FALSE(signal_id.IsValid());
+
+ for (uint8_t i = 0; i != 0xff; i++, signal_id++) {
+ ASSERT_TRUE(i == signal_id.Value());
+ }
+}
+
+TEST(L2capSignalIdTest, almost_wrap_up) {
+ SignalId signal_id(0);
+ ASSERT_FALSE(signal_id.IsValid());
+
+ for (int i = 0; i < 255; i++) {
+ signal_id++;
+ }
+ ASSERT_EQ(0xff, signal_id.Value());
+}
+
+TEST(L2capSignalIdTest, wrap_up) {
+ SignalId signal_id(0);
+ ASSERT_FALSE(signal_id.IsValid());
+
+ for (int i = 0; i < 256; i++) {
+ signal_id++;
+ }
+ ASSERT_EQ(1, signal_id.Value());
+}
+
+TEST(L2capSignalIdTest, pre_decrement) {
+ SignalId signal_id(0);
+ ASSERT_FALSE(signal_id.IsValid());
+
+ for (uint8_t i = 0; i != 0xff; --i, --signal_id) {
+ ASSERT_TRUE(i == signal_id.Value());
+ }
+}
+
+TEST(L2capSignalIdTest, post_decrement) {
+ SignalId signal_id(0);
+ ASSERT_FALSE(signal_id.IsValid());
+
+ for (uint8_t i = 0; i != 0xff; i--, signal_id--) {
+ ASSERT_TRUE(i == signal_id.Value());
+ }
+}
+
+TEST(L2capSignalIdTest, almost_wrap_down) {
+ SignalId signal_id(0);
+ ASSERT_FALSE(signal_id.IsValid());
+
+ for (int i = 0; i < 255; i++) {
+ signal_id--;
+ }
+ ASSERT_EQ(1, signal_id.Value());
+}
+
+TEST(L2capSignalIdTest, wrap_down) {
+ SignalId signal_id(0);
+ ASSERT_FALSE(signal_id.IsValid());
+
+ for (int i = 0; i < 256; i++) {
+ signal_id--;
+ }
+ ASSERT_EQ(0xff, signal_id.Value());
+}
+
+} // namespace l2cap
+} // namespace bluetooth
diff --git a/gd/module.cc b/gd/module.cc
new file mode 100644
index 0000000..f12da97
--- /dev/null
+++ b/gd/module.cc
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2019 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 "module.h"
+
+using ::bluetooth::os::Handler;
+using ::bluetooth::os::Thread;
+
+namespace bluetooth {
+
+constexpr std::chrono::milliseconds kModuleStopTimeout = std::chrono::milliseconds(20);
+
+ModuleFactory::ModuleFactory(std::function<Module*()> ctor) : ctor_(ctor) {
+}
+
+std::string Module::ToString() const {
+ return "Module";
+}
+
+Handler* Module::GetHandler() const {
+ ASSERT_LOG(handler_ != nullptr, "Can't get handler when it's not started");
+ return handler_;
+}
+
+const ModuleRegistry* Module::GetModuleRegistry() const {
+ return registry_;
+}
+
+Module* Module::GetDependency(const ModuleFactory* module) const {
+ for (auto& dependency : dependencies_.list_) {
+ if (dependency == module) {
+ return registry_->Get(module);
+ }
+ }
+
+ ASSERT_LOG(false, "Module was not listed as a dependency in ListDependencies");
+}
+
+Module* ModuleRegistry::Get(const ModuleFactory* module) const {
+ auto instance = started_modules_.find(module);
+ ASSERT(instance != started_modules_.end());
+ return instance->second;
+}
+
+bool ModuleRegistry::IsStarted(const ModuleFactory* module) const {
+ return started_modules_.find(module) != started_modules_.end();
+}
+
+void ModuleRegistry::Start(ModuleList* modules, Thread* thread) {
+ for (auto it = modules->list_.begin(); it != modules->list_.end(); it++) {
+ Start(*it, thread);
+ }
+}
+
+void ModuleRegistry::set_registry_and_handler(Module* instance, Thread* thread) const {
+ instance->registry_ = this;
+ instance->handler_ = new Handler(thread);
+}
+
+Module* ModuleRegistry::Start(const ModuleFactory* module, Thread* thread) {
+ auto started_instance = started_modules_.find(module);
+ if (started_instance != started_modules_.end()) {
+ return started_instance->second;
+ }
+
+ Module* instance = module->ctor_();
+ set_registry_and_handler(instance, thread);
+
+ instance->ListDependencies(&instance->dependencies_);
+ Start(&instance->dependencies_, thread);
+
+ instance->Start();
+ start_order_.push_back(module);
+ started_modules_[module] = instance;
+ return instance;
+}
+
+void ModuleRegistry::StopAll() {
+ // Since modules were brought up in dependency order, it is safe to tear down by going in reverse order.
+ for (auto it = start_order_.rbegin(); it != start_order_.rend(); it++) {
+ auto instance = started_modules_.find(*it);
+ ASSERT(instance != started_modules_.end());
+
+ // Clear the handler before stopping the module to allow it to shut down gracefully.
+ instance->second->handler_->Clear();
+ instance->second->handler_->WaitUntilStopped(kModuleStopTimeout);
+ instance->second->Stop();
+
+ delete instance->second->handler_;
+ delete instance->second;
+ started_modules_.erase(instance);
+ }
+
+ ASSERT(started_modules_.empty());
+ start_order_.clear();
+}
+
+os::Handler* ModuleRegistry::GetModuleHandler(const ModuleFactory* module) const {
+ auto started_instance = started_modules_.find(module);
+ if (started_instance != started_modules_.end()) {
+ return started_instance->second->GetHandler();
+ }
+ return nullptr;
+}
+} // namespace bluetooth
diff --git a/gd/module.h b/gd/module.h
new file mode 100644
index 0000000..045865d
--- /dev/null
+++ b/gd/module.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <functional>
+#include <future>
+#include <map>
+#include <string>
+#include <vector>
+
+#include "common/bind.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "os/thread.h"
+
+namespace bluetooth {
+
+class Module;
+class ModuleRegistry;
+
+class ModuleFactory {
+ friend ModuleRegistry;
+ public:
+ ModuleFactory(std::function<Module*()> ctor);
+
+ private:
+ std::function<Module*()> ctor_;
+};
+
+class ModuleList {
+ friend ModuleRegistry;
+ friend Module;
+ public:
+ template <class T>
+ void add() {
+ list_.push_back(&T::Factory);
+ }
+
+ private:
+ std::vector<const ModuleFactory*> list_;
+};
+
+// Each leaf node module must have a factory like so:
+//
+// static const ModuleFactory Factory;
+//
+// which will provide a constructor for the module registry to call.
+// The module registry will also use the factory as the identifier
+// for that module.
+class Module {
+ friend ModuleRegistry;
+ public:
+ virtual ~Module() = default;
+ protected:
+ // Populate the provided list with modules that must start before yours
+ virtual void ListDependencies(ModuleList* list) = 0;
+
+ // You can grab your started dependencies during or after this call
+ // using GetDependency(), or access the module registry via GetModuleRegistry()
+ virtual void Start() = 0;
+
+ // Release all resources, you're about to be deleted
+ virtual void Stop() = 0;
+
+ virtual std::string ToString() const;
+
+ ::bluetooth::os::Handler* GetHandler() const;
+
+ const ModuleRegistry* GetModuleRegistry() const;
+
+ template <class T>
+ T* GetDependency() const {
+ return static_cast<T*>(GetDependency(&T::Factory));
+ }
+
+ private:
+ Module* GetDependency(const ModuleFactory* module) const;
+
+ ::bluetooth::os::Handler* handler_ = nullptr;
+ ModuleList dependencies_;
+ const ModuleRegistry* registry_;
+};
+
+class ModuleRegistry {
+ friend Module;
+ friend class StackManager;
+ public:
+ template <class T>
+ bool IsStarted() const {
+ return IsStarted(&T::Factory);
+ }
+
+ bool IsStarted(const ModuleFactory* factory) const;
+
+ // Start all the modules on this list and their dependencies
+ // in dependency order
+ void Start(ModuleList* modules, ::bluetooth::os::Thread* thread);
+
+ template <class T>
+ T* Start(::bluetooth::os::Thread* thread) {
+ return static_cast<T*>(Start(&T::Factory, thread));
+ }
+
+ Module* Start(const ModuleFactory* id, ::bluetooth::os::Thread* thread);
+
+ // Stop all running modules in reverse order of start
+ void StopAll();
+
+ protected:
+ Module* Get(const ModuleFactory* module) const;
+
+ void set_registry_and_handler(Module* instance, ::bluetooth::os::Thread* thread) const;
+
+ os::Handler* GetModuleHandler(const ModuleFactory* module) const;
+
+ std::map<const ModuleFactory*, Module*> started_modules_;
+ std::vector<const ModuleFactory*> start_order_;
+};
+
+class TestModuleRegistry : public ModuleRegistry {
+ public:
+ void InjectTestModule(const ModuleFactory* module, Module* instance) {
+ start_order_.push_back(module);
+ started_modules_[module] = instance;
+ set_registry_and_handler(instance, &test_thread);
+ }
+
+ Module* GetModuleUnderTest(const ModuleFactory* module) const {
+ return Get(module);
+ }
+
+ os::Handler* GetTestModuleHandler(const ModuleFactory* module) const {
+ return GetModuleHandler(module);
+ }
+
+ os::Thread& GetTestThread() {
+ return test_thread;
+ }
+
+ bool SynchronizeModuleHandler(const ModuleFactory* module, std::chrono::milliseconds timeout) const {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ os::Handler* handler = GetTestModuleHandler(module);
+ handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+ return future.wait_for(timeout) == std::future_status::ready;
+ }
+
+ private:
+ os::Thread test_thread{"test_thread", os::Thread::Priority::NORMAL};
+};
+
+} // namespace bluetooth
diff --git a/gd/module_unittest.cc b/gd/module_unittest.cc
new file mode 100644
index 0000000..d0efb5d
--- /dev/null
+++ b/gd/module_unittest.cc
@@ -0,0 +1,203 @@
+/*
+ * Copyright 2019 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 "module.h"
+
+#include "gtest/gtest.h"
+
+using ::bluetooth::os::Thread;
+
+namespace bluetooth {
+namespace {
+
+class ModuleTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ thread_ = new Thread("test_thread", Thread::Priority::NORMAL);
+ registry_ = new ModuleRegistry();
+ }
+
+ void TearDown() override {
+ delete registry_;
+ delete thread_;
+ }
+
+ ModuleRegistry* registry_;
+ Thread* thread_;
+};
+
+class TestModuleNoDependency : public Module {
+ public:
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override {
+ }
+
+ void Start() override {
+ // A module is not considered started until Start() finishes
+ EXPECT_FALSE(GetModuleRegistry()->IsStarted<TestModuleNoDependency>());
+ }
+
+ void Stop() override {
+ // A module is not considered stopped until after Stop() finishes
+ EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependency>());
+ }
+};
+
+const ModuleFactory TestModuleNoDependency::Factory = ModuleFactory([]() {
+ return new TestModuleNoDependency();
+});
+
+class TestModuleOneDependency : public Module {
+ public:
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override {
+ list->add<TestModuleNoDependency>();
+ }
+
+ void Start() override {
+ EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependency>());
+
+ // A module is not considered started until Start() finishes
+ EXPECT_FALSE(GetModuleRegistry()->IsStarted<TestModuleOneDependency>());
+ }
+
+ void Stop() override {
+ EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependency>());
+
+ // A module is not considered stopped until after Stop() finishes
+ EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleOneDependency>());
+ }
+};
+
+const ModuleFactory TestModuleOneDependency::Factory = ModuleFactory([]() {
+ return new TestModuleOneDependency();
+});
+
+
+class TestModuleNoDependencyTwo : public Module {
+ public:
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override {
+ }
+
+ void Start() override {
+ // A module is not considered started until Start() finishes
+ EXPECT_FALSE(GetModuleRegistry()->IsStarted<TestModuleNoDependencyTwo>());
+ }
+
+ void Stop() override {
+ // A module is not considered stopped until after Stop() finishes
+ EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependencyTwo>());
+ }
+};
+
+const ModuleFactory TestModuleNoDependencyTwo::Factory = ModuleFactory([]() {
+ return new TestModuleNoDependencyTwo();
+});
+
+class TestModuleTwoDependencies : public Module {
+ public:
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override {
+ list->add<TestModuleOneDependency>();
+ list->add<TestModuleNoDependencyTwo>();
+ }
+
+ void Start() override {
+ EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleOneDependency>());
+ EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependencyTwo>());
+
+ // A module is not considered started until Start() finishes
+ EXPECT_FALSE(GetModuleRegistry()->IsStarted<TestModuleTwoDependencies>());
+ }
+
+ void Stop() override {
+ EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleOneDependency>());
+ EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleNoDependencyTwo>());
+
+ // A module is not considered stopped until after Stop() finishes
+ EXPECT_TRUE(GetModuleRegistry()->IsStarted<TestModuleTwoDependencies>());
+ }
+};
+
+const ModuleFactory TestModuleTwoDependencies::Factory = ModuleFactory([]() {
+ return new TestModuleTwoDependencies();
+});
+
+TEST_F(ModuleTest, no_dependency) {
+ ModuleList list;
+ list.add<TestModuleNoDependency>();
+ registry_->Start(&list, thread_);
+
+ EXPECT_TRUE(registry_->IsStarted<TestModuleNoDependency>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleOneDependency>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependencyTwo>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleTwoDependencies>());
+
+ registry_->StopAll();
+
+ EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependency>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleOneDependency>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependencyTwo>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleTwoDependencies>());
+}
+
+TEST_F(ModuleTest, one_dependency) {
+ ModuleList list;
+ list.add<TestModuleOneDependency>();
+ registry_->Start(&list, thread_);
+
+ EXPECT_TRUE(registry_->IsStarted<TestModuleNoDependency>());
+ EXPECT_TRUE(registry_->IsStarted<TestModuleOneDependency>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependencyTwo>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleTwoDependencies>());
+
+ registry_->StopAll();
+
+ EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependency>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleOneDependency>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependencyTwo>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleTwoDependencies>());
+}
+
+TEST_F(ModuleTest, two_dependencies) {
+ ModuleList list;
+ list.add<TestModuleTwoDependencies>();
+ registry_->Start(&list, thread_);
+
+ EXPECT_TRUE(registry_->IsStarted<TestModuleNoDependency>());
+ EXPECT_TRUE(registry_->IsStarted<TestModuleOneDependency>());
+ EXPECT_TRUE(registry_->IsStarted<TestModuleNoDependencyTwo>());
+ EXPECT_TRUE(registry_->IsStarted<TestModuleTwoDependencies>());
+
+ registry_->StopAll();
+
+ EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependency>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleOneDependency>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleNoDependencyTwo>());
+ EXPECT_FALSE(registry_->IsStarted<TestModuleTwoDependencies>());
+}
+
+} // namespace
+} // namespace bluetooth
diff --git a/gd/neighbor/Android.bp b/gd/neighbor/Android.bp
new file mode 100644
index 0000000..bd69a3e
--- /dev/null
+++ b/gd/neighbor/Android.bp
@@ -0,0 +1,19 @@
+filegroup {
+ name: "BluetoothNeighborSources",
+ srcs: [
+ "connectability.cc",
+ "discoverability.cc",
+ "inquiry.cc",
+ "name.cc",
+ "page.cc",
+ "scan.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothNeighborTestSources",
+ srcs: [
+ "inquiry_test.cc",
+ ],
+}
+
diff --git a/gd/neighbor/connectability.cc b/gd/neighbor/connectability.cc
new file mode 100644
index 0000000..8a60bdd
--- /dev/null
+++ b/gd/neighbor/connectability.cc
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2019 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.
+ */
+#define LOG_TAG "neighbor2"
+
+#include <memory>
+
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "neighbor/connectability.h"
+#include "neighbor/scan.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace neighbor {
+
+struct ConnectabilityModule::impl {
+ void StartConnectability();
+ void StopConnectability();
+ bool IsConnectable() const;
+
+ void Start();
+ void Stop();
+
+ impl(ConnectabilityModule& connectability_module);
+
+ private:
+ ConnectabilityModule& module_;
+
+ neighbor::ScanModule* scan_module_;
+};
+
+const ModuleFactory neighbor::ConnectabilityModule::Factory =
+ ModuleFactory([]() { return new ConnectabilityModule(); });
+
+neighbor::ConnectabilityModule::impl::impl(neighbor::ConnectabilityModule& module) : module_(module) {}
+
+void neighbor::ConnectabilityModule::impl::StartConnectability() {
+ scan_module_->SetPageScan();
+}
+
+void neighbor::ConnectabilityModule::impl::StopConnectability() {
+ scan_module_->ClearPageScan();
+}
+
+bool neighbor::ConnectabilityModule::impl::IsConnectable() const {
+ return scan_module_->IsPageEnabled();
+}
+
+void neighbor::ConnectabilityModule::impl::Start() {
+ scan_module_ = module_.GetDependency<neighbor::ScanModule>();
+}
+
+void neighbor::ConnectabilityModule::impl::Stop() {}
+
+neighbor::ConnectabilityModule::ConnectabilityModule() : pimpl_(std::make_unique<impl>(*this)) {}
+
+neighbor::ConnectabilityModule::~ConnectabilityModule() {
+ pimpl_.reset();
+}
+
+void neighbor::ConnectabilityModule::StartConnectability() {
+ pimpl_->StartConnectability();
+}
+
+void neighbor::ConnectabilityModule::StopConnectability() {
+ pimpl_->StopConnectability();
+}
+
+bool neighbor::ConnectabilityModule::IsConnectable() const {
+ return pimpl_->IsConnectable();
+}
+
+/**
+ * Module stuff
+ */
+void neighbor::ConnectabilityModule::ListDependencies(ModuleList* list) {
+ list->add<neighbor::ScanModule>();
+}
+
+void neighbor::ConnectabilityModule::Start() {
+ pimpl_->Start();
+}
+
+void neighbor::ConnectabilityModule::Stop() {
+ pimpl_->Stop();
+}
+
+} // namespace neighbor
+} // namespace bluetooth
diff --git a/gd/neighbor/connectability.h b/gd/neighbor/connectability.h
new file mode 100644
index 0000000..8cdd643
--- /dev/null
+++ b/gd/neighbor/connectability.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <memory>
+
+#include "module.h"
+
+namespace bluetooth {
+namespace neighbor {
+
+class ConnectabilityModule : public bluetooth::Module {
+ public:
+ void StartConnectability();
+ void StopConnectability();
+ bool IsConnectable() const;
+
+ ConnectabilityModule();
+ ~ConnectabilityModule();
+
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override;
+ void Start() override;
+ void Stop() override;
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+
+ DISALLOW_COPY_AND_ASSIGN(ConnectabilityModule);
+};
+
+} // namespace neighbor
+} // namespace bluetooth
diff --git a/gd/neighbor/discoverability.cc b/gd/neighbor/discoverability.cc
new file mode 100644
index 0000000..3514caf
--- /dev/null
+++ b/gd/neighbor/discoverability.cc
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2019 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.
+ */
+#define LOG_TAG "bt_gd_neigh"
+
+#include <memory>
+
+#include "common/bind.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "neighbor/discoverability.h"
+#include "neighbor/scan.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace neighbor {
+
+static constexpr uint8_t kGeneralInquiryAccessCode = 0x33;
+static constexpr uint8_t kLimitedInquiryAccessCode = 0x00;
+
+struct DiscoverabilityModule::impl {
+ void StartDiscoverability(std::vector<hci::Lap>& laps);
+ void StopDiscoverability();
+
+ bool IsGeneralDiscoverabilityEnabled() const;
+ bool IsLimitedDiscoverabilityEnabled() const;
+
+ void Start();
+
+ impl(DiscoverabilityModule& discoverability_module);
+
+ private:
+ uint8_t num_supported_iac_;
+ std::vector<hci::Lap> laps_;
+
+ void OnCommandComplete(hci::CommandCompleteView status);
+
+ hci::HciLayer* hci_layer_;
+ neighbor::ScanModule* scan_module_;
+ os::Handler* handler_;
+
+ DiscoverabilityModule& module_;
+ void Dump() const;
+};
+
+const ModuleFactory neighbor::DiscoverabilityModule::Factory =
+ ModuleFactory([]() { return new neighbor::DiscoverabilityModule(); });
+
+neighbor::DiscoverabilityModule::impl::impl(neighbor::DiscoverabilityModule& module) : module_(module) {}
+
+void neighbor::DiscoverabilityModule::impl::OnCommandComplete(hci::CommandCompleteView status) {
+ switch (status.GetCommandOpCode()) {
+ case hci::OpCode::READ_CURRENT_IAC_LAP: {
+ auto packet = hci::ReadCurrentIacLapCompleteView::Create(status);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ laps_ = packet.GetLapsToRead();
+ } break;
+
+ case hci::OpCode::WRITE_CURRENT_IAC_LAP: {
+ auto packet = hci::WriteCurrentIacLapCompleteView::Create(status);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ } break;
+
+ case hci::OpCode::READ_NUMBER_OF_SUPPORTED_IAC: {
+ auto packet = hci::ReadNumberOfSupportedIacCompleteView::Create(status);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ num_supported_iac_ = packet.GetNumSupportIac();
+ } break;
+ default:
+ LOG_WARN("Unhandled command:%s", hci::OpCodeText(status.GetCommandOpCode()).c_str());
+ break;
+ }
+}
+
+void neighbor::DiscoverabilityModule::impl::StartDiscoverability(std::vector<hci::Lap>& laps) {
+ ASSERT(laps.size() <= num_supported_iac_);
+ hci_layer_->EnqueueCommand(hci::WriteCurrentIacLapBuilder::Create(laps),
+ common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+ hci_layer_->EnqueueCommand(hci::ReadCurrentIacLapBuilder::Create(),
+ common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+ scan_module_->SetInquiryScan();
+}
+
+void neighbor::DiscoverabilityModule::impl::StopDiscoverability() {
+ scan_module_->ClearInquiryScan();
+}
+
+bool neighbor::DiscoverabilityModule::impl::IsGeneralDiscoverabilityEnabled() const {
+ return scan_module_->IsInquiryEnabled() && laps_.size() == 1;
+}
+
+bool neighbor::DiscoverabilityModule::impl::IsLimitedDiscoverabilityEnabled() const {
+ return scan_module_->IsInquiryEnabled() && laps_.size() == 2;
+}
+
+void neighbor::DiscoverabilityModule::impl::Start() {
+ hci_layer_ = module_.GetDependency<hci::HciLayer>();
+ scan_module_ = module_.GetDependency<neighbor::ScanModule>();
+ handler_ = module_.GetHandler();
+
+ hci_layer_->EnqueueCommand(hci::ReadCurrentIacLapBuilder::Create(),
+ common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+
+ hci_layer_->EnqueueCommand(hci::ReadNumberOfSupportedIacBuilder::Create(),
+ common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+ LOG_DEBUG("Started discoverability module");
+}
+
+void neighbor::DiscoverabilityModule::impl::Dump() const {
+ LOG_DEBUG("Number of supported iacs:%hhd", num_supported_iac_);
+ LOG_DEBUG("Number of current iacs:%zd", laps_.size());
+ for (auto it : laps_) {
+ LOG_DEBUG(" discoverability lap:%x", it.lap_);
+ }
+}
+
+neighbor::DiscoverabilityModule::DiscoverabilityModule() : pimpl_(std::make_unique<impl>(*this)) {}
+
+neighbor::DiscoverabilityModule::~DiscoverabilityModule() {
+ pimpl_.reset();
+}
+
+void neighbor::DiscoverabilityModule::StartGeneralDiscoverability() {
+ std::vector<hci::Lap> laps;
+ {
+ hci::Lap lap;
+ lap.lap_ = kGeneralInquiryAccessCode;
+ laps.push_back(lap);
+ }
+ pimpl_->StartDiscoverability(laps);
+}
+
+void neighbor::DiscoverabilityModule::StartLimitedDiscoverability() {
+ std::vector<hci::Lap> laps;
+ {
+ hci::Lap lap;
+ lap.lap_ = kGeneralInquiryAccessCode;
+ laps.push_back(lap);
+ }
+
+ {
+ hci::Lap lap;
+ lap.lap_ = kLimitedInquiryAccessCode;
+ laps.push_back(lap);
+ }
+ pimpl_->StartDiscoverability(laps);
+}
+
+void neighbor::DiscoverabilityModule::StopDiscoverability() {
+ pimpl_->StopDiscoverability();
+}
+
+bool neighbor::DiscoverabilityModule::IsGeneralDiscoverabilityEnabled() const {
+ return pimpl_->IsGeneralDiscoverabilityEnabled();
+}
+
+bool neighbor::DiscoverabilityModule::IsLimitedDiscoverabilityEnabled() const {
+ return pimpl_->IsLimitedDiscoverabilityEnabled();
+}
+
+/**
+ * Module stuff
+ */
+void neighbor::DiscoverabilityModule::ListDependencies(ModuleList* list) {
+ list->add<hci::HciLayer>();
+ list->add<neighbor::ScanModule>();
+}
+
+void neighbor::DiscoverabilityModule::Start() {
+ pimpl_->Start();
+}
+
+void neighbor::DiscoverabilityModule::Stop() {}
+
+} // namespace neighbor
+} // namespace bluetooth
diff --git a/gd/neighbor/discoverability.h b/gd/neighbor/discoverability.h
new file mode 100644
index 0000000..124716c
--- /dev/null
+++ b/gd/neighbor/discoverability.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <memory>
+
+#include "module.h"
+
+namespace bluetooth {
+namespace neighbor {
+
+class DiscoverabilityModule : public bluetooth::Module {
+ public:
+ void StartGeneralDiscoverability();
+ void StartLimitedDiscoverability();
+ void StopDiscoverability();
+
+ bool IsGeneralDiscoverabilityEnabled() const;
+ bool IsLimitedDiscoverabilityEnabled() const;
+
+ static const ModuleFactory Factory;
+
+ DiscoverabilityModule();
+ ~DiscoverabilityModule();
+
+ protected:
+ void ListDependencies(ModuleList* list) override;
+ void Start() override;
+ void Stop() override;
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+
+ DISALLOW_COPY_AND_ASSIGN(DiscoverabilityModule);
+};
+
+} // namespace neighbor
+} // namespace bluetooth
diff --git a/gd/neighbor/inquiry.cc b/gd/neighbor/inquiry.cc
new file mode 100644
index 0000000..eb94701
--- /dev/null
+++ b/gd/neighbor/inquiry.cc
@@ -0,0 +1,528 @@
+/*
+ * Copyright 2019 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.
+ */
+#define LOG_TAG "bt_gd_neigh"
+
+#include "neighbor/inquiry.h"
+
+#include <memory>
+
+#include "common/bind.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace neighbor {
+
+static constexpr uint8_t kGeneralInquiryAccessCode = 0x33;
+static constexpr uint8_t kLimitedInquiryAccessCode = 0x00;
+
+static inline std::string LapText(uint8_t lap) {
+ switch (lap) {
+ case kGeneralInquiryAccessCode:
+ return "General Lap";
+ case kLimitedInquiryAccessCode:
+ return "Limited Lap";
+ default:
+ return "Unknown Lap";
+ }
+}
+
+static hci::Lap general_lap_;
+static hci::Lap limited_lap_;
+
+struct InquiryModule::impl {
+ void RegisterCallbacks(InquiryCallbacks inquiry_callbacks);
+ void UnregisterCallbacks();
+
+ void StartOneShotInquiry(hci::Lap& lap, InquiryLength inquiry_length, NumResponses num_responses);
+ void StopOneShotInquiry();
+
+ void StartPeriodicInquiry(hci::Lap& lap, InquiryLength inquiry_length, NumResponses num_responses,
+ PeriodLength max_delay, PeriodLength min_delay);
+ void StopPeriodicInquiry();
+
+ bool IsInquiryActive() const;
+ bool IsOneShotInquiryActive(hci::Lap& lap) const;
+ bool IsPeriodicInquiryActive(hci::Lap& lap) const;
+
+ void SetScanActivity(ScanParameters params);
+ ScanParameters GetScanActivity() const;
+
+ void SetScanType(hci::InquiryScanType scan_type);
+
+ void SetInquiryMode(hci::InquiryMode mode);
+
+ void Start();
+ void Stop();
+
+ bool HasCallbacks() const;
+
+ impl(InquiryModule& inquiry_module);
+
+ private:
+ InquiryCallbacks inquiry_callbacks_;
+
+ InquiryModule& module_;
+
+ hci::Lap* active_one_shot_{nullptr};
+ hci::Lap* active_periodic_{nullptr};
+
+ ScanParameters inquiry_scan_;
+ hci::InquiryMode inquiry_mode_;
+ hci::InquiryScanType inquiry_scan_type_;
+ int8_t inquiry_response_tx_power_;
+
+ void EnqueueCommandComplete(std::unique_ptr<hci::CommandPacketBuilder> command);
+ void EnqueueCommandStatus(std::unique_ptr<hci::CommandPacketBuilder> command);
+ void OnCommandComplete(hci::CommandCompleteView view);
+ void OnCommandStatus(hci::CommandStatusView status);
+
+ void EnqueueCommandCompleteSync(std::unique_ptr<hci::CommandPacketBuilder> command);
+ void OnCommandCompleteSync(hci::CommandCompleteView view);
+
+ void OnEvent(hci::EventPacketView view);
+
+ std::promise<void>* command_sync_{nullptr};
+
+ hci::HciLayer* hci_layer_;
+ os::Handler* handler_;
+};
+
+const ModuleFactory neighbor::InquiryModule::Factory = ModuleFactory([]() { return new neighbor::InquiryModule(); });
+
+neighbor::InquiryModule::impl::impl(neighbor::InquiryModule& module) : module_(module) {
+ general_lap_.lap_ = kGeneralInquiryAccessCode;
+ limited_lap_.lap_ = kLimitedInquiryAccessCode;
+}
+
+void neighbor::InquiryModule::impl::OnCommandCompleteSync(hci::CommandCompleteView view) {
+ OnCommandComplete(view);
+ ASSERT(command_sync_ != nullptr);
+ command_sync_->set_value();
+}
+
+void neighbor::InquiryModule::impl::OnCommandComplete(hci::CommandCompleteView view) {
+ switch (view.GetCommandOpCode()) {
+ case hci::OpCode::INQUIRY_CANCEL: {
+ auto packet = hci::InquiryCancelCompleteView::Create(view);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ } break;
+
+ case hci::OpCode::PERIODIC_INQUIRY_MODE: {
+ auto packet = hci::PeriodicInquiryModeCompleteView::Create(view);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ if (active_periodic_ != nullptr) {
+ LOG_DEBUG("Periodic inquiry started lap:%s", LapText(active_periodic_->lap_).c_str());
+ }
+ } break;
+
+ case hci::OpCode::EXIT_PERIODIC_INQUIRY_MODE: {
+ auto packet = hci::ExitPeriodicInquiryModeCompleteView::Create(view);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ } break;
+
+ case hci::OpCode::WRITE_INQUIRY_MODE: {
+ auto packet = hci::WriteInquiryModeCompleteView::Create(view);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ } break;
+
+ case hci::OpCode::READ_INQUIRY_MODE: {
+ auto packet = hci::ReadInquiryModeCompleteView::Create(view);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ inquiry_mode_ = packet.GetInquiryMode();
+ } break;
+
+ case hci::OpCode::READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL: {
+ auto packet = hci::ReadInquiryResponseTransmitPowerLevelCompleteView::Create(view);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ inquiry_response_tx_power_ = packet.GetTxPower();
+ } break;
+
+ case hci::OpCode::WRITE_INQUIRY_SCAN_ACTIVITY: {
+ auto packet = hci::WriteInquiryScanActivityCompleteView::Create(view);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ } break;
+
+ case hci::OpCode::READ_INQUIRY_SCAN_ACTIVITY: {
+ auto packet = hci::ReadInquiryScanActivityCompleteView::Create(view);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ inquiry_scan_.interval = packet.GetInquiryScanInterval();
+ inquiry_scan_.window = packet.GetInquiryScanWindow();
+ } break;
+
+ case hci::OpCode::WRITE_INQUIRY_SCAN_TYPE: {
+ auto packet = hci::WriteInquiryScanTypeCompleteView::Create(view);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ } break;
+
+ case hci::OpCode::READ_INQUIRY_SCAN_TYPE: {
+ auto packet = hci::ReadInquiryScanTypeCompleteView::Create(view);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ inquiry_scan_type_ = packet.GetInquiryScanType();
+ } break;
+
+ default:
+ LOG_WARN("Unhandled command:%s", hci::OpCodeText(view.GetCommandOpCode()).c_str());
+ break;
+ }
+}
+
+void neighbor::InquiryModule::impl::OnCommandStatus(hci::CommandStatusView status) {
+ ASSERT(status.GetStatus() == hci::ErrorCode::SUCCESS);
+
+ switch (status.GetCommandOpCode()) {
+ case hci::OpCode::INQUIRY: {
+ auto packet = hci::InquiryStatusView::Create(status);
+ ASSERT(packet.IsValid());
+ if (active_one_shot_ != nullptr) {
+ LOG_DEBUG("Inquiry started lap:%s", LapText(active_one_shot_->lap_).c_str());
+ }
+ } break;
+
+ default:
+ LOG_WARN("Unhandled command:%s", hci::OpCodeText(status.GetCommandOpCode()).c_str());
+ break;
+ }
+}
+
+void neighbor::InquiryModule::impl::OnEvent(hci::EventPacketView view) {
+ switch (view.GetEventCode()) {
+ case hci::EventCode::INQUIRY_COMPLETE: {
+ auto packet = hci::InquiryCompleteView::Create(view);
+ ASSERT(packet.IsValid());
+ LOG_DEBUG("inquiry complete");
+ active_one_shot_ = nullptr;
+ inquiry_callbacks_.complete(packet.GetStatus());
+ } break;
+
+ case hci::EventCode::INQUIRY_RESULT: {
+ auto packet = hci::InquiryResultView::Create(view);
+ ASSERT(packet.IsValid());
+ LOG_DEBUG("Inquiry result size:%zd num_responses:%d addr:%s repetition_mode:%s cod:%s clock_offset:%d",
+ packet.size(), packet.GetNumResponses(), packet.GetBdAddr().ToString().c_str(),
+ hci::PageScanRepetitionModeText(packet.GetPageScanRepetitionMode()).c_str(),
+ packet.GetClassOfDevice().ToString().c_str(), packet.GetClockOffset());
+ inquiry_callbacks_.result(packet);
+ } break;
+
+ case hci::EventCode::INQUIRY_RESULT_WITH_RSSI: {
+ auto packet = hci::InquiryResultWithRssiView::Create(view);
+ ASSERT(packet.IsValid());
+ LOG_DEBUG("Inquiry result with rssi num_responses:%d addr:%s repetition_mode:%s cod:%s clock_offset:%d",
+ packet.GetNumResponses(), packet.GetAddress().ToString().c_str(),
+ hci::PageScanRepetitionModeText(packet.GetPageScanRepetitionMode()).c_str(),
+ packet.GetClassOfDevice().ToString().c_str(), packet.GetClockOffset());
+ inquiry_callbacks_.result_with_rssi(packet);
+ } break;
+
+ case hci::EventCode::EXTENDED_INQUIRY_RESULT: {
+ auto packet = hci::ExtendedInquiryResultView::Create(view);
+ ASSERT(packet.IsValid());
+ LOG_DEBUG("Extended inquiry result addr:%s repetition_mode:%s cod:%s clock_offset:%d rssi:%hhd",
+ packet.GetAddress().ToString().c_str(),
+ hci::PageScanRepetitionModeText(packet.GetPageScanRepetitionMode()).c_str(),
+ packet.GetClassOfDevice().ToString().c_str(), packet.GetClockOffset(), packet.GetRssi());
+ inquiry_callbacks_.extended_result(packet);
+ } break;
+
+ default:
+ LOG_ERROR("Unhandled event:%s", hci::EventCodeText(view.GetEventCode()).c_str());
+ break;
+ }
+}
+
+/**
+ * impl
+ */
+void neighbor::InquiryModule::impl::RegisterCallbacks(InquiryCallbacks callbacks) {
+ inquiry_callbacks_ = callbacks;
+
+ hci_layer_->RegisterEventHandler(hci::EventCode::INQUIRY_RESULT,
+ common::Bind(&InquiryModule::impl::OnEvent, common::Unretained(this)), handler_);
+ hci_layer_->RegisterEventHandler(hci::EventCode::INQUIRY_RESULT_WITH_RSSI,
+ common::Bind(&InquiryModule::impl::OnEvent, common::Unretained(this)), handler_);
+ hci_layer_->RegisterEventHandler(hci::EventCode::EXTENDED_INQUIRY_RESULT,
+ common::Bind(&InquiryModule::impl::OnEvent, common::Unretained(this)), handler_);
+ hci_layer_->RegisterEventHandler(hci::EventCode::INQUIRY_COMPLETE,
+ common::Bind(&InquiryModule::impl::OnEvent, common::Unretained(this)), handler_);
+}
+
+void neighbor::InquiryModule::impl::UnregisterCallbacks() {
+ hci_layer_->UnregisterEventHandler(hci::EventCode::INQUIRY_COMPLETE);
+ hci_layer_->UnregisterEventHandler(hci::EventCode::EXTENDED_INQUIRY_RESULT);
+ hci_layer_->UnregisterEventHandler(hci::EventCode::INQUIRY_RESULT_WITH_RSSI);
+ hci_layer_->UnregisterEventHandler(hci::EventCode::INQUIRY_RESULT);
+
+ inquiry_callbacks_ = {nullptr, nullptr, nullptr, nullptr};
+}
+
+void neighbor::InquiryModule::impl::EnqueueCommandComplete(std::unique_ptr<hci::CommandPacketBuilder> command) {
+ hci_layer_->EnqueueCommand(std::move(command), common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)),
+ handler_);
+}
+
+void neighbor::InquiryModule::impl::EnqueueCommandStatus(std::unique_ptr<hci::CommandPacketBuilder> command) {
+ hci_layer_->EnqueueCommand(std::move(command), common::BindOnce(&impl::OnCommandStatus, common::Unretained(this)),
+ handler_);
+}
+
+void neighbor::InquiryModule::impl::EnqueueCommandCompleteSync(std::unique_ptr<hci::CommandPacketBuilder> command) {
+ ASSERT(command_sync_ == nullptr);
+ command_sync_ = new std::promise<void>();
+ auto command_received = command_sync_->get_future();
+ hci_layer_->EnqueueCommand(std::move(command),
+ common::BindOnce(&impl::OnCommandCompleteSync, common::Unretained(this)), handler_);
+ command_received.wait();
+ delete command_sync_;
+ command_sync_ = nullptr;
+}
+
+void neighbor::InquiryModule::impl::StartOneShotInquiry(hci::Lap& lap, InquiryLength inquiry_length,
+ NumResponses num_responses) {
+ ASSERT(HasCallbacks());
+ ASSERT(active_one_shot_ == nullptr);
+ active_one_shot_ = ⪅
+ EnqueueCommandStatus(hci::InquiryBuilder::Create(lap, inquiry_length, num_responses));
+}
+
+void neighbor::InquiryModule::impl::StopOneShotInquiry() {
+ ASSERT(active_one_shot_ != nullptr);
+ active_one_shot_ = nullptr;
+ EnqueueCommandComplete(hci::InquiryCancelBuilder::Create());
+}
+
+bool neighbor::InquiryModule::impl::IsOneShotInquiryActive(hci::Lap& lap) const {
+ return active_one_shot_ == ⪅
+}
+
+void neighbor::InquiryModule::impl::StartPeriodicInquiry(hci::Lap& lap, InquiryLength inquiry_length,
+ NumResponses num_responses, PeriodLength max_delay,
+ PeriodLength min_delay) {
+ ASSERT(HasCallbacks());
+ ASSERT(active_periodic_ == nullptr);
+ active_periodic_ = ⪅
+ EnqueueCommandComplete(
+ hci::PeriodicInquiryModeBuilder::Create(inquiry_length, num_responses, lap, max_delay, min_delay));
+}
+
+void neighbor::InquiryModule::impl::StopPeriodicInquiry() {
+ ASSERT(active_periodic_ != nullptr);
+ active_periodic_ = nullptr;
+ EnqueueCommandComplete(hci::ExitPeriodicInquiryModeBuilder::Create());
+}
+
+bool neighbor::InquiryModule::impl::IsPeriodicInquiryActive(hci::Lap& lap) const {
+ return active_periodic_ == ⪅
+}
+
+bool neighbor::InquiryModule::impl::IsInquiryActive() const {
+ return active_one_shot_ != nullptr || active_periodic_ != nullptr;
+}
+
+void neighbor::InquiryModule::impl::Start() {
+ hci_layer_ = module_.GetDependency<hci::HciLayer>();
+ handler_ = module_.GetHandler();
+
+ EnqueueCommandComplete(hci::ReadInquiryResponseTransmitPowerLevelBuilder::Create());
+ EnqueueCommandComplete(hci::ReadInquiryScanActivityBuilder::Create());
+ EnqueueCommandComplete(hci::ReadInquiryScanTypeBuilder::Create());
+ EnqueueCommandCompleteSync(hci::ReadInquiryModeBuilder::Create());
+
+ LOG_DEBUG("Started inquiry module");
+}
+
+void neighbor::InquiryModule::impl::Stop() {
+ LOG_INFO("Inquiry scan interval:%hu window:%hu", inquiry_scan_.interval, inquiry_scan_.window);
+ LOG_INFO("Inquiry mode:%s scan_type:%s", hci::InquiryModeText(inquiry_mode_).c_str(),
+ hci::InquiryScanTypeText(inquiry_scan_type_).c_str());
+ LOG_INFO("Inquiry response tx power:%hhd", inquiry_response_tx_power_);
+ LOG_DEBUG("Stopped inquiry module");
+}
+
+void neighbor::InquiryModule::impl::SetInquiryMode(hci::InquiryMode mode) {
+ EnqueueCommandComplete(hci::WriteInquiryModeBuilder::Create(mode));
+ inquiry_mode_ = mode;
+ LOG_DEBUG("Set inquiry mode:%s", hci::InquiryModeText(mode).c_str());
+}
+
+void neighbor::InquiryModule::impl::SetScanActivity(ScanParameters params) {
+ EnqueueCommandComplete(hci::WriteInquiryScanActivityBuilder::Create(params.interval, params.window));
+ inquiry_scan_ = params;
+ LOG_DEBUG("Set scan activity interval:0x%x/%.02fms window:0x%x/%.02fms", params.interval,
+ ScanIntervalTimeMs(params.interval), params.window, ScanWindowTimeMs(params.window));
+}
+
+ScanParameters neighbor::InquiryModule::impl::GetScanActivity() const {
+ return inquiry_scan_;
+}
+
+void neighbor::InquiryModule::impl::SetScanType(hci::InquiryScanType scan_type) {
+ EnqueueCommandComplete(hci::WriteInquiryScanTypeBuilder::Create(scan_type));
+ LOG_DEBUG("Set scan type:%s", hci::InquiryScanTypeText(scan_type).c_str());
+}
+
+bool neighbor::InquiryModule::impl::HasCallbacks() const {
+ return inquiry_callbacks_.result != nullptr && inquiry_callbacks_.result_with_rssi != nullptr &&
+ inquiry_callbacks_.extended_result != nullptr && inquiry_callbacks_.complete != nullptr;
+}
+
+/**
+ * General API here
+ */
+neighbor::InquiryModule::InquiryModule() : pimpl_(std::make_unique<impl>(*this)) {}
+
+neighbor::InquiryModule::~InquiryModule() {
+ pimpl_.reset();
+}
+
+void neighbor::InquiryModule::RegisterCallbacks(InquiryCallbacks callbacks) {
+ pimpl_->RegisterCallbacks(callbacks);
+}
+
+void neighbor::InquiryModule::UnregisterCallbacks() {
+ pimpl_->UnregisterCallbacks();
+}
+
+void neighbor::InquiryModule::StartGeneralInquiry(InquiryLength inquiry_length, NumResponses num_responses) {
+ if (pimpl_->IsInquiryActive()) {
+ LOG_WARN("Ignoring start general one shot inquiry as an inquiry is already active");
+ return;
+ }
+ pimpl_->StartOneShotInquiry(general_lap_, inquiry_length, num_responses);
+ LOG_DEBUG("Started general one shot inquiry");
+}
+
+void neighbor::InquiryModule::StartLimitedInquiry(InquiryLength inquiry_length, NumResponses num_responses) {
+ if (pimpl_->IsInquiryActive()) {
+ LOG_WARN("Ignoring start limited one shot inquiry as an inquiry is already active");
+ return;
+ }
+ pimpl_->StartOneShotInquiry(limited_lap_, inquiry_length, num_responses);
+ LOG_DEBUG("Started limited one shot inquiry");
+}
+
+void neighbor::InquiryModule::StopInquiry() {
+ if (!pimpl_->IsInquiryActive()) {
+ LOG_WARN("Ignoring stop one shot inquiry as an inquiry is not active");
+ return;
+ }
+ pimpl_->StopOneShotInquiry();
+ LOG_DEBUG("Stopped one shot inquiry");
+}
+
+bool neighbor::InquiryModule::IsGeneralInquiryActive() const {
+ return pimpl_->IsOneShotInquiryActive(general_lap_);
+}
+
+bool neighbor::InquiryModule::IsLimitedInquiryActive() const {
+ return pimpl_->IsOneShotInquiryActive(limited_lap_);
+}
+
+void neighbor::InquiryModule::StartGeneralPeriodicInquiry(InquiryLength inquiry_length, NumResponses num_responses,
+ PeriodLength max_delay, PeriodLength min_delay) {
+ if (pimpl_->IsInquiryActive()) {
+ LOG_WARN("Ignoring start general periodic inquiry as an inquiry is already active");
+ return;
+ }
+ pimpl_->StartPeriodicInquiry(general_lap_, inquiry_length, num_responses, max_delay, min_delay);
+ LOG_DEBUG("Started general periodic inquiry");
+}
+
+void neighbor::InquiryModule::StartLimitedPeriodicInquiry(InquiryLength inquiry_length, NumResponses num_responses,
+ PeriodLength max_delay, PeriodLength min_delay) {
+ if (pimpl_->IsInquiryActive()) {
+ LOG_WARN("Ignoring start limited periodic inquiry as an inquiry is already active");
+ return;
+ }
+ pimpl_->StartPeriodicInquiry(limited_lap_, inquiry_length, num_responses, max_delay, min_delay);
+ LOG_DEBUG("Started limited periodic inquiry");
+}
+
+void neighbor::InquiryModule::StopPeriodicInquiry() {
+ if (!pimpl_->IsInquiryActive()) {
+ LOG_WARN("Ignoring stop periodic inquiry as an inquiry is not active");
+ return;
+ }
+ pimpl_->StopPeriodicInquiry();
+ LOG_DEBUG("Stopped periodic inquiry");
+}
+
+bool neighbor::InquiryModule::IsGeneralPeriodicInquiryActive() const {
+ return pimpl_->IsPeriodicInquiryActive(general_lap_);
+}
+
+bool neighbor::InquiryModule::IsLimitedPeriodicInquiryActive() const {
+ return pimpl_->IsPeriodicInquiryActive(limited_lap_);
+}
+
+void neighbor::InquiryModule::SetScanActivity(ScanParameters params) {
+ pimpl_->SetScanActivity(params);
+}
+
+ScanParameters neighbor::InquiryModule::GetScanActivity() const {
+ return pimpl_->GetScanActivity();
+}
+
+void neighbor::InquiryModule::SetInterlacedScan() {
+ pimpl_->SetScanType(hci::InquiryScanType::INTERLACED);
+}
+
+void neighbor::InquiryModule::SetStandardScan() {
+ pimpl_->SetScanType(hci::InquiryScanType::STANDARD);
+}
+
+void neighbor::InquiryModule::SetStandardInquiryResultMode() {
+ pimpl_->SetInquiryMode(hci::InquiryMode::STANDARD);
+}
+
+void neighbor::InquiryModule::SetInquiryWithRssiResultMode() {
+ pimpl_->SetInquiryMode(hci::InquiryMode::RSSI);
+}
+
+void neighbor::InquiryModule::SetExtendedInquiryResultMode() {
+ pimpl_->SetInquiryMode(hci::InquiryMode::RSSI_OR_EXTENDED);
+}
+
+/**
+ * Module methods here
+ */
+void neighbor::InquiryModule::ListDependencies(ModuleList* list) {
+ list->add<hci::HciLayer>();
+}
+
+void neighbor::InquiryModule::Start() {
+ pimpl_->Start();
+}
+
+void neighbor::InquiryModule::Stop() {
+ pimpl_->Stop();
+}
+
+} // namespace neighbor
+} // namespace bluetooth
diff --git a/gd/neighbor/inquiry.h b/gd/neighbor/inquiry.h
new file mode 100644
index 0000000..2da2a56
--- /dev/null
+++ b/gd/neighbor/inquiry.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <memory>
+
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "neighbor/scan_parameters.h"
+
+namespace bluetooth {
+namespace neighbor {
+
+using InquiryLength = uint8_t; // Range: 0x01 to 0x30, 1.28 to 61.44s
+using NumResponses = uint8_t; // Range: 0x01 to 0xff, 0x00 is unlimited
+using PeriodLength = uint16_t; // Time = N * 1.28 s
+
+using InquiryResultCallback = std::function<void(hci::InquiryResultView view)>;
+using InquiryResultWithRssiCallback = std::function<void(hci::InquiryResultWithRssiView view)>;
+using ExtendedInquiryResultCallback = std::function<void(hci::ExtendedInquiryResultView view)>;
+using InquiryCompleteCallback = std::function<void(hci::ErrorCode status)>;
+
+using InquiryCallbacks = struct {
+ InquiryResultCallback result;
+ InquiryResultWithRssiCallback result_with_rssi;
+ ExtendedInquiryResultCallback extended_result;
+ InquiryCompleteCallback complete;
+};
+
+class InquiryModule : public bluetooth::Module {
+ public:
+ void RegisterCallbacks(InquiryCallbacks inquiry_callbacks);
+ void UnregisterCallbacks();
+
+ void StartGeneralInquiry(InquiryLength inquiry_length, NumResponses num_responses);
+ void StartLimitedInquiry(InquiryLength inquiry_length, NumResponses num_responses);
+ void StopInquiry();
+ bool IsGeneralInquiryActive() const;
+ bool IsLimitedInquiryActive() const;
+
+ void StartGeneralPeriodicInquiry(InquiryLength inquiry_length, NumResponses num_responses, PeriodLength max_delay,
+ PeriodLength min_delay);
+ void StartLimitedPeriodicInquiry(InquiryLength inquiry_length, NumResponses num_responses, PeriodLength max_delay,
+ PeriodLength min_delay);
+ void StopPeriodicInquiry();
+ bool IsGeneralPeriodicInquiryActive() const;
+ bool IsLimitedPeriodicInquiryActive() const;
+
+ void SetScanActivity(ScanParameters parms);
+ ScanParameters GetScanActivity() const;
+
+ void SetInterlacedScan();
+ void SetStandardScan();
+
+ void SetStandardInquiryResultMode();
+ void SetInquiryWithRssiResultMode();
+ void SetExtendedInquiryResultMode();
+
+ static const ModuleFactory Factory;
+
+ InquiryModule();
+ ~InquiryModule();
+
+ protected:
+ void ListDependencies(ModuleList* list) override;
+ void Start() override;
+ void Stop() override;
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+
+ DISALLOW_COPY_AND_ASSIGN(InquiryModule);
+};
+
+} // namespace neighbor
+} // namespace bluetooth
diff --git a/gd/neighbor/inquiry_test.cc b/gd/neighbor/inquiry_test.cc
new file mode 100644
index 0000000..05d1a70
--- /dev/null
+++ b/gd/neighbor/inquiry_test.cc
@@ -0,0 +1,490 @@
+/*
+ * Copyright 2019 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 "neighbor/inquiry.h"
+
+#include <algorithm>
+#include <chrono>
+#include <future>
+#include <map>
+#include <memory>
+
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+#include "common/bind.h"
+#include "common/callback.h"
+#include "hci/address.h"
+#include "hci/class_of_device.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "os/thread.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace neighbor {
+namespace {
+
+static const uint8_t kNumberPacketsReadyToReceive = 1;
+
+/**
+ * This structure reflects the current state of the bluetooth chip
+ * at any given time.
+ */
+static const int8_t kInitialInquiryResponseTransmitPowerLevel = 123;
+static const uint16_t kInitialInquiryScanInterval = 1111;
+static const uint16_t kInitialInquiryScanWindow = 2222;
+
+struct HciRegister {
+ bool one_shot_inquiry_active;
+ bool periodic_inquiry_active;
+ int8_t inquiry_response_transmit_power_level;
+ uint16_t inquiry_scan_interval;
+ uint16_t inquiry_scan_window;
+ hci::InquiryScanType inquiry_scan_type;
+ hci::InquiryMode inquiry_mode;
+} hci_register_{
+ .one_shot_inquiry_active = false,
+ .periodic_inquiry_active = false,
+ .inquiry_response_transmit_power_level = kInitialInquiryResponseTransmitPowerLevel,
+ .inquiry_scan_interval = kInitialInquiryScanInterval,
+ .inquiry_scan_window = kInitialInquiryScanWindow,
+ .inquiry_scan_type = hci::InquiryScanType::STANDARD,
+ .inquiry_mode = hci::InquiryMode::STANDARD,
+};
+
+hci::PacketView<hci::kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+ auto bytes = std::make_shared<std::vector<uint8_t>>();
+ hci::BitInserter i(*bytes);
+ bytes->reserve(packet->size());
+ packet->Serialize(i);
+ return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+class TestHciLayer : public hci::HciLayer {
+ public:
+ void EnqueueCommand(std::unique_ptr<hci::CommandPacketBuilder> command,
+ common::OnceCallback<void(hci::CommandCompleteView)> on_complete, os::Handler* handler) override {
+ GetHandler()->Post(common::BindOnce(&TestHciLayer::HandleCommand, common::Unretained(this), std::move(command),
+ std::move(on_complete), common::Unretained(handler)));
+ }
+
+ void EnqueueCommand(std::unique_ptr<hci::CommandPacketBuilder> command,
+ common::OnceCallback<void(hci::CommandStatusView)> on_status, os::Handler* handler) override {
+ GetHandler()->Post(common::BindOnce(&TestHciLayer::HandleStatus, common::Unretained(this), std::move(command),
+ std::move(on_status), common::Unretained(handler)));
+ }
+
+ void HandleCommand(std::unique_ptr<hci::CommandPacketBuilder> command_builder,
+ common::OnceCallback<void(hci::CommandCompleteView)> on_complete, os::Handler* handler) {
+ hci::CommandPacketView command = hci::CommandPacketView::Create(GetPacketView(std::move(command_builder)));
+ ASSERT(command.IsValid());
+
+ std::unique_ptr<packet::BasePacketBuilder> event_builder;
+ switch (command.GetOpCode()) {
+ case hci::OpCode::INQUIRY_CANCEL:
+ event_builder =
+ hci::InquiryCancelCompleteBuilder::Create(kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS);
+ hci_register_.one_shot_inquiry_active = false;
+ break;
+
+ case hci::OpCode::PERIODIC_INQUIRY_MODE:
+ event_builder =
+ hci::PeriodicInquiryModeCompleteBuilder::Create(kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS);
+ hci_register_.periodic_inquiry_active = true;
+ break;
+
+ case hci::OpCode::EXIT_PERIODIC_INQUIRY_MODE:
+ event_builder =
+ hci::ExitPeriodicInquiryModeCompleteBuilder::Create(kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS);
+ hci_register_.periodic_inquiry_active = false;
+ break;
+
+ case hci::OpCode::WRITE_INQUIRY_MODE:
+ event_builder =
+ hci::WriteInquiryModeCompleteBuilder::Create(kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS);
+ {
+ auto view = hci::WriteInquiryModeView::Create(hci::DiscoveryCommandView::Create(command));
+ ASSERT(view.IsValid());
+ hci_register_.inquiry_mode = view.GetInquiryMode();
+ }
+ break;
+
+ case hci::OpCode::READ_INQUIRY_MODE:
+ event_builder = hci::ReadInquiryModeCompleteBuilder::Create(
+ kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS, hci_register_.inquiry_mode);
+ break;
+
+ case hci::OpCode::WRITE_INQUIRY_SCAN_ACTIVITY:
+ event_builder =
+ hci::WriteInquiryScanActivityCompleteBuilder::Create(kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS);
+ {
+ auto view = hci::WriteInquiryScanActivityView::Create(hci::DiscoveryCommandView::Create(command));
+ ASSERT(view.IsValid());
+ hci_register_.inquiry_scan_interval = view.GetInquiryScanInterval();
+ hci_register_.inquiry_scan_window = view.GetInquiryScanWindow();
+ }
+ break;
+
+ case hci::OpCode::READ_INQUIRY_SCAN_ACTIVITY:
+ event_builder = hci::ReadInquiryScanActivityCompleteBuilder::Create(
+ kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS, hci_register_.inquiry_scan_interval,
+ hci_register_.inquiry_scan_window);
+ break;
+
+ case hci::OpCode::WRITE_INQUIRY_SCAN_TYPE:
+ event_builder =
+ hci::WriteInquiryScanTypeCompleteBuilder::Create(kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS);
+ {
+ auto view = hci::WriteInquiryScanTypeView::Create(hci::DiscoveryCommandView::Create(command));
+ ASSERT(view.IsValid());
+ hci_register_.inquiry_scan_type = view.GetInquiryScanType();
+ }
+ break;
+
+ case hci::OpCode::READ_INQUIRY_SCAN_TYPE:
+ event_builder = hci::ReadInquiryScanTypeCompleteBuilder::Create(
+ kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS, hci_register_.inquiry_scan_type);
+ break;
+
+ case hci::OpCode::READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL:
+ event_builder = hci::ReadInquiryResponseTransmitPowerLevelCompleteBuilder::Create(
+ kNumberPacketsReadyToReceive, hci::ErrorCode::SUCCESS, hci_register_.inquiry_response_transmit_power_level);
+ break;
+
+ default:
+ LOG_INFO("Dropping unhandled command:%s", hci::OpCodeText(command.GetOpCode()).c_str());
+ return;
+ }
+ hci::EventPacketView event = hci::EventPacketView::Create(GetPacketView(std::move(event_builder)));
+ ASSERT(event.IsValid());
+ hci::CommandCompleteView command_complete = hci::CommandCompleteView::Create(event);
+ ASSERT(command_complete.IsValid());
+ handler->Post(common::BindOnce(std::move(on_complete), std::move(command_complete)));
+
+ if (promise_sync_complete_ != nullptr) {
+ promise_sync_complete_->set_value(true);
+ }
+ }
+
+ void HandleStatus(std::unique_ptr<hci::CommandPacketBuilder> command_builder,
+ common::OnceCallback<void(hci::CommandStatusView)> on_status, os::Handler* handler) {
+ hci::CommandPacketView command = hci::CommandPacketView::Create(GetPacketView(std::move(command_builder)));
+ ASSERT(command.IsValid());
+
+ std::unique_ptr<packet::BasePacketBuilder> event_builder;
+ switch (command.GetOpCode()) {
+ case hci::OpCode::INQUIRY:
+ event_builder = hci::InquiryStatusBuilder::Create(hci::ErrorCode::SUCCESS, kNumberPacketsReadyToReceive);
+ hci_register_.one_shot_inquiry_active = true;
+ break;
+ default:
+ LOG_INFO("Dropping unhandled status expecting command:%s", hci::OpCodeText(command.GetOpCode()).c_str());
+ return;
+ }
+ hci::EventPacketView event = hci::EventPacketView::Create(GetPacketView(std::move(event_builder)));
+ ASSERT(event.IsValid());
+ hci::CommandStatusView command_status = hci::CommandStatusView::Create(event);
+ ASSERT(command_status.IsValid());
+ handler->Post(common::BindOnce(std::move(on_status), std::move(command_status)));
+
+ if (promise_sync_complete_ != nullptr) {
+ promise_sync_complete_->set_value(true);
+ }
+ }
+
+ void RegisterEventHandler(hci::EventCode event_code, common::Callback<void(hci::EventPacketView)> event_handler,
+ os::Handler* handler) override {
+ switch (event_code) {
+ case hci::EventCode::INQUIRY_RESULT:
+ inquiry_result_handler_ = handler;
+ inquiry_result_callback_ = event_handler;
+ break;
+ case hci::EventCode::INQUIRY_RESULT_WITH_RSSI:
+ inquiry_result_with_rssi_handler_ = handler;
+ inquiry_result_with_rssi_callback_ = event_handler;
+ break;
+ case hci::EventCode::EXTENDED_INQUIRY_RESULT:
+ extended_inquiry_result_handler_ = handler;
+ extended_inquiry_result_callback_ = event_handler;
+ break;
+ case hci::EventCode::INQUIRY_COMPLETE:
+ inquiry_complete_handler_ = handler;
+ inquiry_complete_callback_ = event_handler;
+ break;
+ default:
+ ASSERT_TRUE(false) << "Unexpected event handler being registered";
+ break;
+ }
+ }
+
+ void UnregisterEventHandler(hci::EventCode event_code) override {
+ if (hci_register_.one_shot_inquiry_active || hci_register_.periodic_inquiry_active) {
+ LOG_ERROR("Event handlers may not be unregistered until inquiry is stopped");
+ return;
+ }
+
+ switch (event_code) {
+ case hci::EventCode::INQUIRY_RESULT:
+ inquiry_result_handler_ = nullptr;
+ inquiry_result_callback_ = {};
+ break;
+ case hci::EventCode::INQUIRY_RESULT_WITH_RSSI:
+ inquiry_result_with_rssi_handler_ = nullptr;
+ inquiry_result_with_rssi_callback_ = {};
+ break;
+ case hci::EventCode::EXTENDED_INQUIRY_RESULT:
+ extended_inquiry_result_handler_ = nullptr;
+ extended_inquiry_result_callback_ = {};
+ break;
+ case hci::EventCode::INQUIRY_COMPLETE:
+ inquiry_complete_handler_ = nullptr;
+ inquiry_complete_callback_ = {};
+ break;
+ default:
+ ASSERT_TRUE(false) << "Unexpected event handler being unregistered";
+ break;
+ }
+ }
+
+ void Synchronize(std::function<void()> func) {
+ ASSERT(promise_sync_complete_ == nullptr);
+ promise_sync_complete_ = new std::promise<bool>();
+ auto future = promise_sync_complete_->get_future();
+ func();
+ future.wait();
+ delete promise_sync_complete_;
+ promise_sync_complete_ = nullptr;
+ }
+
+ void InjectInquiryResult(std::unique_ptr<hci::InquiryResultBuilder> result) {
+ if (inquiry_result_handler_ != nullptr) {
+ hci::EventPacketView view = hci::EventPacketView::Create(GetPacketView(std::move(result)));
+ ASSERT(view.IsValid());
+ inquiry_result_handler_->Post(common::BindOnce(inquiry_result_callback_, std::move(view)));
+ }
+ }
+
+ void ListDependencies(ModuleList* list) override {}
+ void Start() override {}
+ void Stop() override {}
+
+ private:
+ std::promise<bool>* promise_sync_complete_{nullptr};
+
+ os::Handler* inquiry_result_handler_{nullptr};
+ common::Callback<void(hci::EventPacketView)> inquiry_result_callback_;
+ os::Handler* inquiry_result_with_rssi_handler_{nullptr};
+ common::Callback<void(hci::EventPacketView)> inquiry_result_with_rssi_callback_;
+ os::Handler* extended_inquiry_result_handler_{nullptr};
+ common::Callback<void(hci::EventPacketView)> extended_inquiry_result_callback_;
+ os::Handler* inquiry_complete_handler_{nullptr};
+ common::Callback<void(hci::EventPacketView)> inquiry_complete_callback_;
+};
+
+class InquiryTest : public ::testing::Test {
+ public:
+ void Result(hci::InquiryResultView view) {
+ ASSERT(view.size() >= sizeof(uint16_t));
+ promise_result_complete_->set_value(true);
+ }
+
+ void WaitForInquiryResult(std::function<void()> func) {
+ ASSERT(promise_result_complete_ == nullptr);
+ promise_result_complete_ = new std::promise<bool>();
+ auto future = promise_result_complete_->get_future();
+ func();
+ future.wait();
+ delete promise_result_complete_;
+ promise_result_complete_ = nullptr;
+ }
+
+ void ResultWithRssi(hci::InquiryResultWithRssiView view) {
+ ASSERT(view.size() >= sizeof(uint16_t));
+ }
+
+ void ExtendedResult(hci::ExtendedInquiryResultView view) {
+ ASSERT(view.size() >= sizeof(uint16_t));
+ }
+
+ void Complete(hci::ErrorCode status) {}
+
+ protected:
+ void SetUp() override {
+ test_hci_layer_ = new TestHciLayer;
+ fake_registry_.InjectTestModule(&hci::HciLayer::Factory, test_hci_layer_);
+ client_handler_ = fake_registry_.GetTestModuleHandler(&hci::HciLayer::Factory);
+ fake_registry_.Start<InquiryModule>(&thread_);
+
+ inquiry_module_ = static_cast<InquiryModule*>(fake_registry_.GetModuleUnderTest(&InquiryModule::Factory));
+
+ InquiryCallbacks inquiry_callbacks;
+ inquiry_callbacks.result = std::bind(&InquiryTest::Result, this, std::placeholders::_1);
+ inquiry_callbacks.result_with_rssi = std::bind(&InquiryTest::ResultWithRssi, this, std::placeholders::_1);
+ inquiry_callbacks.extended_result = std::bind(&InquiryTest::ExtendedResult, this, std::placeholders::_1);
+ inquiry_callbacks.complete = std::bind(&InquiryTest::Complete, this, std::placeholders::_1);
+ inquiry_module_->RegisterCallbacks(inquiry_callbacks);
+ }
+
+ void TearDown() override {
+ inquiry_module_->UnregisterCallbacks();
+ fake_registry_.StopAll();
+ }
+
+ TestModuleRegistry fake_registry_;
+ TestHciLayer* test_hci_layer_ = nullptr;
+ os::Thread& thread_ = fake_registry_.GetTestThread();
+ InquiryModule* inquiry_module_ = nullptr;
+ os::Handler* client_handler_ = nullptr;
+
+ std::promise<bool>* promise_result_complete_{nullptr};
+};
+
+TEST_F(InquiryTest, Module) {
+ ScanParameters params{
+ .interval = 0,
+ .window = 0,
+ };
+ params = inquiry_module_->GetScanActivity();
+
+ ASSERT_EQ(kInitialInquiryScanInterval, params.interval);
+ ASSERT_EQ(kInitialInquiryScanWindow, params.window);
+}
+
+TEST_F(InquiryTest, SetInquiryModes) {
+ test_hci_layer_->Synchronize([this] { inquiry_module_->SetInquiryWithRssiResultMode(); });
+ ASSERT_EQ(hci_register_.inquiry_mode, hci::InquiryMode::RSSI);
+
+ test_hci_layer_->Synchronize([this] { inquiry_module_->SetExtendedInquiryResultMode(); });
+ ASSERT_EQ(hci_register_.inquiry_mode, hci::InquiryMode::RSSI_OR_EXTENDED);
+
+ test_hci_layer_->Synchronize([this] { inquiry_module_->SetStandardInquiryResultMode(); });
+ ASSERT_EQ(hci_register_.inquiry_mode, hci::InquiryMode::STANDARD);
+}
+
+TEST_F(InquiryTest, SetScanType) {
+ test_hci_layer_->Synchronize([this] { inquiry_module_->SetInterlacedScan(); });
+ ASSERT_EQ(hci_register_.inquiry_scan_type, hci::InquiryScanType::INTERLACED);
+
+ test_hci_layer_->Synchronize([this] { inquiry_module_->SetStandardScan(); });
+ ASSERT_EQ(hci_register_.inquiry_scan_type, hci::InquiryScanType::STANDARD);
+}
+
+TEST_F(InquiryTest, ScanActivity) {
+ ScanParameters params{
+ .interval = 0x1234,
+ .window = 0x5678,
+ };
+
+ test_hci_layer_->Synchronize([this, params] { inquiry_module_->SetScanActivity(params); });
+
+ ASSERT_EQ(0x1234, hci_register_.inquiry_scan_interval);
+ ASSERT_EQ(0x5678, hci_register_.inquiry_scan_window);
+
+ params = inquiry_module_->GetScanActivity();
+
+ EXPECT_EQ(0x1234, params.interval);
+ EXPECT_EQ(0x5678, params.window);
+}
+
+TEST_F(InquiryTest, OneShotGeneralInquiry) {
+ ASSERT(!inquiry_module_->IsGeneralInquiryActive());
+ ASSERT(!inquiry_module_->IsLimitedInquiryActive());
+
+ test_hci_layer_->Synchronize([this] { inquiry_module_->StartGeneralInquiry(128, 100); });
+
+ ASSERT(inquiry_module_->IsGeneralInquiryActive());
+ ASSERT(!inquiry_module_->IsLimitedInquiryActive());
+
+ test_hci_layer_->Synchronize([this] { inquiry_module_->StopInquiry(); });
+
+ ASSERT(!inquiry_module_->IsGeneralInquiryActive());
+ ASSERT(!inquiry_module_->IsLimitedInquiryActive());
+}
+
+TEST_F(InquiryTest, OneShotLimitedInquiry) {
+ ASSERT(!inquiry_module_->IsGeneralInquiryActive());
+ ASSERT(!inquiry_module_->IsLimitedInquiryActive());
+
+ test_hci_layer_->Synchronize([this] { inquiry_module_->StartLimitedInquiry(128, 100); });
+
+ ASSERT(!inquiry_module_->IsGeneralInquiryActive());
+ ASSERT(inquiry_module_->IsLimitedInquiryActive());
+
+ test_hci_layer_->Synchronize([this] { inquiry_module_->StopInquiry(); });
+
+ ASSERT(!inquiry_module_->IsGeneralInquiryActive());
+ ASSERT(!inquiry_module_->IsLimitedInquiryActive());
+}
+
+TEST_F(InquiryTest, GeneralPeriodicInquiry) {
+ ASSERT(!inquiry_module_->IsGeneralPeriodicInquiryActive());
+ ASSERT(!inquiry_module_->IsLimitedPeriodicInquiryActive());
+
+ test_hci_layer_->Synchronize([this] { inquiry_module_->StartGeneralPeriodicInquiry(128, 100, 1100, 200); });
+
+ ASSERT(inquiry_module_->IsGeneralPeriodicInquiryActive());
+ ASSERT(!inquiry_module_->IsLimitedPeriodicInquiryActive());
+
+ test_hci_layer_->Synchronize([this] { inquiry_module_->StopPeriodicInquiry(); });
+
+ ASSERT(!inquiry_module_->IsGeneralPeriodicInquiryActive());
+ ASSERT(!inquiry_module_->IsLimitedPeriodicInquiryActive());
+}
+
+TEST_F(InquiryTest, LimitedPeriodicInquiry) {
+ ASSERT(!inquiry_module_->IsGeneralPeriodicInquiryActive());
+ ASSERT(!inquiry_module_->IsLimitedPeriodicInquiryActive());
+
+ test_hci_layer_->Synchronize([this] { inquiry_module_->StartLimitedPeriodicInquiry(128, 100, 1100, 200); });
+
+ ASSERT(!inquiry_module_->IsGeneralPeriodicInquiryActive());
+ ASSERT(inquiry_module_->IsLimitedPeriodicInquiryActive());
+
+ test_hci_layer_->Synchronize([this] { inquiry_module_->StopPeriodicInquiry(); });
+
+ ASSERT(!inquiry_module_->IsGeneralPeriodicInquiryActive());
+ ASSERT(!inquiry_module_->IsLimitedPeriodicInquiryActive());
+}
+
+TEST_F(InquiryTest, InjectInquiryResult) {
+ ASSERT(!inquiry_module_->IsGeneralInquiryActive());
+ ASSERT(!inquiry_module_->IsLimitedInquiryActive());
+
+ test_hci_layer_->Synchronize([this] { inquiry_module_->StartGeneralInquiry(128, 100); });
+
+ ASSERT(inquiry_module_->IsGeneralInquiryActive());
+ ASSERT(!inquiry_module_->IsLimitedInquiryActive());
+
+ WaitForInquiryResult([this] {
+ uint8_t num_responses = 1;
+ hci::Address bd_addr;
+ hci::Address::FromString("11:22:33:44:55:66", bd_addr);
+ hci::PageScanRepetitionMode page_scan_repetition_mode = hci::PageScanRepetitionMode::R1;
+ hci::ClassOfDevice class_of_device;
+ hci::ClassOfDevice::FromString("00:00:00", class_of_device);
+ uint16_t clock_offset = 0x1234;
+ auto packet = hci::InquiryResultBuilder::Create(num_responses, bd_addr, page_scan_repetition_mode, class_of_device,
+ clock_offset);
+ test_hci_layer_->InjectInquiryResult(std::move(packet));
+ });
+ test_hci_layer_->Synchronize([this] { inquiry_module_->StopInquiry(); });
+}
+
+} // namespace
+} // namespace neighbor
+} // namespace bluetooth
diff --git a/gd/neighbor/name.cc b/gd/neighbor/name.cc
new file mode 100644
index 0000000..34fa86b
--- /dev/null
+++ b/gd/neighbor/name.cc
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2019 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.
+ */
+#define LOG_TAG "bt_gd_neigh"
+
+#include "neighbor/name.h"
+
+#include <memory>
+#include <unordered_map>
+#include <utility>
+
+#include "common/bind.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace neighbor {
+
+struct ReadCallbackHandler {
+ ReadRemoteNameCallback callback;
+ os::Handler* handler;
+};
+
+struct CancelCallbackHandler {
+ CancelRemoteNameCallback callback;
+ os::Handler* handler;
+};
+
+constexpr std::array<uint8_t, 248> kEmptyName{};
+
+struct NameModule::impl {
+ void ReadRemoteNameRequest(hci::Address address, hci::PageScanRepetitionMode page_scan_repetition_mode,
+ uint16_t clock_offset, hci::ClockOffsetValid clock_offset_valid,
+ ReadRemoteNameCallback callback, os::Handler* handler);
+ void CancelRemoteNameRequest(hci::Address address, CancelRemoteNameCallback, os::Handler* handler);
+
+ void Start();
+ void Stop();
+
+ impl(const NameModule& name_module);
+
+ private:
+ const NameModule& module_;
+
+ void EnqueueCommandComplete(std::unique_ptr<hci::CommandPacketBuilder> command);
+ void EnqueueCommandStatus(std::unique_ptr<hci::CommandPacketBuilder> command);
+
+ void OnCommandComplete(hci::CommandCompleteView view);
+ void OnCommandStatus(hci::CommandStatusView status);
+ void OnEvent(hci::EventPacketView view);
+
+ std::unordered_map<hci::Address, std::unique_ptr<ReadCallbackHandler>> read_callback_handler_map_;
+ std::unordered_map<hci::Address, std::unique_ptr<CancelCallbackHandler>> cancel_callback_handler_map_;
+
+ hci::HciLayer* hci_layer_;
+ os::Handler* handler_;
+};
+
+const ModuleFactory neighbor::NameModule::Factory = ModuleFactory([]() { return new neighbor::NameModule(); });
+
+neighbor::NameModule::impl::impl(const neighbor::NameModule& module) : module_(module) {}
+
+void neighbor::NameModule::impl::EnqueueCommandComplete(std::unique_ptr<hci::CommandPacketBuilder> command) {
+ hci_layer_->EnqueueCommand(std::move(command), common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)),
+ handler_);
+}
+
+void neighbor::NameModule::impl::EnqueueCommandStatus(std::unique_ptr<hci::CommandPacketBuilder> command) {
+ hci_layer_->EnqueueCommand(std::move(command), common::BindOnce(&impl::OnCommandStatus, common::Unretained(this)),
+ handler_);
+}
+
+void neighbor::NameModule::impl::OnCommandComplete(hci::CommandCompleteView view) {
+ switch (view.GetCommandOpCode()) {
+ case hci::OpCode::REMOTE_NAME_REQUEST_CANCEL: {
+ auto packet = hci::RemoteNameRequestCancelCompleteView::Create(view);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ hci::Address address = packet.GetBdAddr();
+ ASSERT(cancel_callback_handler_map_.find(address) != cancel_callback_handler_map_.end());
+ cancel_callback_handler_map_.erase(address);
+ } break;
+ default:
+ LOG_WARN("Unhandled command:%s", hci::OpCodeText(view.GetCommandOpCode()).c_str());
+ break;
+ }
+}
+
+void neighbor::NameModule::impl::OnCommandStatus(hci::CommandStatusView status) {
+ ASSERT(status.GetStatus() == hci::ErrorCode::SUCCESS);
+
+ switch (status.GetCommandOpCode()) {
+ case hci::OpCode::REMOTE_NAME_REQUEST: {
+ auto packet = hci::RemoteNameRequestStatusView::Create(status);
+ ASSERT(packet.IsValid());
+ } break;
+
+ default:
+ LOG_WARN("Unhandled command:%s", hci::OpCodeText(status.GetCommandOpCode()).c_str());
+ break;
+ }
+}
+
+void neighbor::NameModule::impl::OnEvent(hci::EventPacketView view) {
+ switch (view.GetEventCode()) {
+ case hci::EventCode::REMOTE_NAME_REQUEST_COMPLETE: {
+ auto packet = hci::RemoteNameRequestCompleteView::Create(view);
+ ASSERT(packet.IsValid());
+ hci::Address address = packet.GetBdAddr();
+ ASSERT(read_callback_handler_map_.find(address) != read_callback_handler_map_.end());
+ auto read_callback_handler = std::move(read_callback_handler_map_[address]);
+ read_callback_handler->handler->Post(common::BindOnce(std::move(read_callback_handler->callback),
+ packet.GetStatus(), address, packet.GetRemoteName()));
+ read_callback_handler_map_.erase(address);
+ } break;
+ default:
+ LOG_ERROR("Unhandled event:%s", hci::EventCodeText(view.GetEventCode()).c_str());
+ break;
+ }
+}
+
+void neighbor::NameModule::impl::Start() {
+ hci_layer_ = module_.GetDependency<hci::HciLayer>();
+ handler_ = module_.GetHandler();
+
+ hci_layer_->RegisterEventHandler(hci::EventCode::REMOTE_NAME_REQUEST_COMPLETE,
+ common::Bind(&NameModule::impl::OnEvent, common::Unretained(this)), handler_);
+}
+
+void neighbor::NameModule::impl::Stop() {
+ hci_layer_->UnregisterEventHandler(hci::EventCode::REMOTE_NAME_REQUEST_COMPLETE);
+}
+
+void neighbor::NameModule::impl::ReadRemoteNameRequest(hci::Address address,
+ hci::PageScanRepetitionMode page_scan_repetition_mode,
+ uint16_t clock_offset, hci::ClockOffsetValid clock_offset_valid,
+ ReadRemoteNameCallback callback, os::Handler* handler) {
+ LOG_DEBUG("%s Start read remote name request for %s", __func__, address.ToString().c_str());
+
+ if (read_callback_handler_map_.find(address) != read_callback_handler_map_.end()) {
+ LOG_WARN("Ignoring duplicate read remote name request to:%s", address.ToString().c_str());
+ handler->Post(common::BindOnce(std::move(callback), hci::ErrorCode::UNSPECIFIED_ERROR, address, kEmptyName));
+ return;
+ }
+ read_callback_handler_map_[address] = std::unique_ptr<ReadCallbackHandler>(new ReadCallbackHandler{
+ .callback = std::move(callback),
+ .handler = handler,
+ });
+
+ EnqueueCommandStatus(
+ hci::RemoteNameRequestBuilder::Create(address, page_scan_repetition_mode, clock_offset, clock_offset_valid));
+}
+
+void neighbor::NameModule::impl::CancelRemoteNameRequest(hci::Address address, CancelRemoteNameCallback callback,
+ os::Handler* handler) {
+ LOG_DEBUG("%s Cancel remote name request for %s", __func__, address.ToString().c_str());
+
+ if (cancel_callback_handler_map_.find(address) != cancel_callback_handler_map_.end()) {
+ LOG_WARN("Ignoring duplicate cancel remote name request to:%s", address.ToString().c_str());
+ handler->Post(common::BindOnce(std::move(callback), hci::ErrorCode::UNSPECIFIED_ERROR, address));
+ return;
+ }
+ cancel_callback_handler_map_[address] = std::unique_ptr<CancelCallbackHandler>(new CancelCallbackHandler{
+ .callback = std::move(callback),
+ .handler = handler,
+ });
+ EnqueueCommandComplete(hci::RemoteNameRequestCancelBuilder::Create(address));
+}
+
+/**
+ * General API here
+ */
+neighbor::NameModule::NameModule() : pimpl_(std::make_unique<impl>(*this)) {}
+
+neighbor::NameModule::~NameModule() {
+ pimpl_.reset();
+}
+
+void neighbor::NameModule::ReadRemoteNameRequest(hci::Address address,
+ hci::PageScanRepetitionMode page_scan_repetition_mode,
+ uint16_t clock_offset, hci::ClockOffsetValid clock_offset_valid,
+ ReadRemoteNameCallback callback, os::Handler* handler) {
+ GetHandler()->Post(common::BindOnce(&NameModule::impl::ReadRemoteNameRequest, common::Unretained(pimpl_.get()),
+ address, page_scan_repetition_mode, clock_offset, clock_offset_valid,
+ std::move(callback), handler));
+}
+
+void neighbor::NameModule::CancelRemoteNameRequest(hci::Address address, CancelRemoteNameCallback callback,
+ os::Handler* handler) {
+ GetHandler()->Post(common::BindOnce(&NameModule::impl::CancelRemoteNameRequest, common::Unretained(pimpl_.get()),
+ address, std::move(callback), handler));
+}
+
+/**
+ * Module methods here
+ */
+void neighbor::NameModule::ListDependencies(ModuleList* list) {
+ list->add<hci::HciLayer>();
+}
+
+void neighbor::NameModule::Start() {
+ pimpl_->Start();
+}
+
+void neighbor::NameModule::Stop() {
+ pimpl_->Stop();
+}
+
+} // namespace neighbor
+} // namespace bluetooth
diff --git a/gd/neighbor/name.h b/gd/neighbor/name.h
new file mode 100644
index 0000000..291e1de
--- /dev/null
+++ b/gd/neighbor/name.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <array>
+#include <cstdint>
+#include <memory>
+
+#include "common/bind.h"
+#include "hci/address.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+
+namespace bluetooth {
+namespace neighbor {
+
+using ReadRemoteNameCallback =
+ common::OnceCallback<void(hci::ErrorCode status, hci::Address address, std::array<uint8_t, 248> name)>;
+using CancelRemoteNameCallback = common::OnceCallback<void(hci::ErrorCode status, hci::Address address)>;
+
+class NameModule : public bluetooth::Module {
+ public:
+ void ReadRemoteNameRequest(hci::Address address, hci::PageScanRepetitionMode page_scan_repetition_mode,
+ uint16_t clock_offset, hci::ClockOffsetValid clock_offset_valid,
+ ReadRemoteNameCallback on_read_name, os::Handler* handler);
+ void CancelRemoteNameRequest(hci::Address address, CancelRemoteNameCallback on_cancel, os::Handler* handler);
+
+ static const ModuleFactory Factory;
+
+ NameModule();
+ ~NameModule();
+
+ protected:
+ void ListDependencies(ModuleList* list) override;
+ void Start() override;
+ void Stop() override;
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+
+ DISALLOW_COPY_AND_ASSIGN(NameModule);
+};
+
+} // namespace neighbor
+} // namespace bluetooth
diff --git a/gd/neighbor/page.cc b/gd/neighbor/page.cc
new file mode 100644
index 0000000..4631875
--- /dev/null
+++ b/gd/neighbor/page.cc
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2019 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.
+ */
+#define LOG_TAG "bt_gd_neigh"
+
+#include <memory>
+
+#include "common/bind.h"
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "neighbor/page.h"
+#include "neighbor/scan_parameters.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace neighbor {
+
+struct PageModule::impl {
+ void SetScanActivity(ScanParameters params);
+ ScanParameters GetScanActivity() const;
+
+ void SetScanType(hci::PageScanType type);
+
+ void SetTimeout(PageTimeout timeout);
+
+ void Start();
+ void Stop();
+
+ impl(PageModule& page_module);
+
+ private:
+ PageModule& module_;
+
+ ScanParameters scan_parameters_;
+ hci::PageScanType scan_type_;
+ PageTimeout timeout_;
+
+ void OnCommandComplete(hci::CommandCompleteView status);
+
+ hci::HciLayer* hci_layer_;
+ os::Handler* handler_;
+};
+
+const ModuleFactory neighbor::PageModule::Factory = ModuleFactory([]() { return new neighbor::PageModule(); });
+
+neighbor::PageModule::impl::impl(neighbor::PageModule& module) : module_(module) {}
+
+void neighbor::PageModule::impl::OnCommandComplete(hci::CommandCompleteView view) {
+ switch (view.GetCommandOpCode()) {
+ case hci::OpCode::WRITE_PAGE_SCAN_ACTIVITY: {
+ auto packet = hci::WritePageScanActivityCompleteView::Create(view);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ } break;
+
+ case hci::OpCode::READ_PAGE_SCAN_ACTIVITY: {
+ auto packet = hci::ReadPageScanActivityCompleteView::Create(view);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ scan_parameters_.interval = packet.GetPageScanInterval();
+ scan_parameters_.window = packet.GetPageScanWindow();
+ } break;
+
+ case hci::OpCode::WRITE_PAGE_SCAN_TYPE: {
+ auto packet = hci::WritePageScanTypeCompleteView::Create(view);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ } break;
+
+ case hci::OpCode::READ_PAGE_SCAN_TYPE: {
+ auto packet = hci::ReadPageScanTypeCompleteView::Create(view);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ scan_type_ = packet.GetPageScanType();
+ } break;
+
+ case hci::OpCode::WRITE_PAGE_TIMEOUT: {
+ auto packet = hci::WritePageTimeoutCompleteView::Create(view);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ } break;
+
+ case hci::OpCode::READ_PAGE_TIMEOUT: {
+ auto packet = hci::ReadPageTimeoutCompleteView::Create(view);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ timeout_ = packet.GetPageTimeout();
+ } break;
+
+ default:
+ LOG_ERROR("Unhandled command %s", hci::OpCodeText(view.GetCommandOpCode()).c_str());
+ break;
+ }
+}
+
+void neighbor::PageModule::impl::Start() {
+ hci_layer_ = module_.GetDependency<hci::HciLayer>();
+ handler_ = module_.GetHandler();
+
+ hci_layer_->EnqueueCommand(hci::ReadPageScanActivityBuilder::Create(),
+ common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+
+ hci_layer_->EnqueueCommand(hci::ReadPageScanTypeBuilder::Create(),
+ common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+
+ hci_layer_->EnqueueCommand(hci::ReadPageTimeoutBuilder::Create(),
+ common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+}
+
+void neighbor::PageModule::impl::Stop() {
+ LOG_DEBUG("Page scan interval:%hd window:%hd", scan_parameters_.interval, scan_parameters_.window);
+ LOG_DEBUG("Page scan_type:%s", hci::PageScanTypeText(scan_type_).c_str());
+}
+
+void neighbor::PageModule::impl::SetScanActivity(ScanParameters params) {
+ hci_layer_->EnqueueCommand(hci::WritePageScanActivityBuilder::Create(params.interval, params.window),
+ common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+
+ hci_layer_->EnqueueCommand(hci::ReadPageScanActivityBuilder::Create(),
+ common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+ LOG_DEBUG("Set page scan activity interval:0x%x/%.02fms window:0x%x/%.02fms", params.interval,
+ ScanIntervalTimeMs(params.interval), params.window, ScanWindowTimeMs(params.window));
+}
+
+ScanParameters neighbor::PageModule::impl::GetScanActivity() const {
+ return scan_parameters_;
+}
+
+void neighbor::PageModule::impl::SetScanType(hci::PageScanType scan_type) {
+ hci_layer_->EnqueueCommand(hci::WritePageScanTypeBuilder::Create(scan_type),
+ common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+
+ hci_layer_->EnqueueCommand(hci::ReadPageScanTypeBuilder::Create(),
+ common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+ LOG_DEBUG("Set page scan type:%s", hci::PageScanTypeText(scan_type).c_str());
+}
+
+void neighbor::PageModule::impl::SetTimeout(PageTimeout timeout) {
+ hci_layer_->EnqueueCommand(hci::WritePageTimeoutBuilder::Create(timeout),
+ common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+
+ hci_layer_->EnqueueCommand(hci::ReadPageTimeoutBuilder::Create(),
+ common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)), handler_);
+ LOG_DEBUG("Set page scan timeout:0x%x/%.02fms", timeout, PageTimeoutMs(timeout));
+}
+
+/**
+ * General API here
+ */
+neighbor::PageModule::PageModule() : pimpl_(std::make_unique<impl>(*this)) {}
+
+neighbor::PageModule::~PageModule() {
+ pimpl_.reset();
+}
+
+void neighbor::PageModule::SetScanActivity(ScanParameters params) {
+ pimpl_->SetScanActivity(params);
+}
+
+ScanParameters neighbor::PageModule::GetScanActivity() const {
+ return pimpl_->GetScanActivity();
+}
+
+void neighbor::PageModule::SetInterlacedScan() {
+ pimpl_->SetScanType(hci::PageScanType::INTERLACED);
+}
+
+void neighbor::PageModule::SetStandardScan() {
+ pimpl_->SetScanType(hci::PageScanType::STANDARD);
+}
+
+void neighbor::PageModule::SetTimeout(PageTimeout timeout) {
+ pimpl_->SetTimeout(timeout);
+}
+
+/**
+ * Module methods here
+ */
+void neighbor::PageModule::ListDependencies(ModuleList* list) {
+ list->add<hci::HciLayer>();
+}
+
+void neighbor::PageModule::Start() {
+ pimpl_->Start();
+}
+
+void neighbor::PageModule::Stop() {
+ pimpl_->Stop();
+}
+
+} // namespace neighbor
+} // namespace bluetooth
diff --git a/gd/neighbor/page.h b/gd/neighbor/page.h
new file mode 100644
index 0000000..075217b
--- /dev/null
+++ b/gd/neighbor/page.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <memory>
+
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "neighbor/scan_parameters.h"
+
+namespace bluetooth {
+namespace neighbor {
+
+using PageTimeout = uint16_t; // Range = 0x0001 to 0xffff, Time N * 0.625ms
+
+inline double PageTimeoutMs(PageTimeout timeout) {
+ return kTimeTickMs * timeout;
+}
+
+class PageModule : public bluetooth::Module {
+ public:
+ void SetScanActivity(ScanParameters params);
+ ScanParameters GetScanActivity() const;
+
+ void SetInterlacedScan();
+ void SetStandardScan();
+
+ void SetTimeout(PageTimeout timeout);
+
+ static const ModuleFactory Factory;
+
+ PageModule();
+ ~PageModule();
+
+ protected:
+ void ListDependencies(ModuleList* list) override;
+ void Start() override;
+ void Stop() override;
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+
+ DISALLOW_COPY_AND_ASSIGN(PageModule);
+};
+
+} // namespace neighbor
+} // namespace bluetooth
diff --git a/gd/neighbor/scan.cc b/gd/neighbor/scan.cc
new file mode 100644
index 0000000..5232b08
--- /dev/null
+++ b/gd/neighbor/scan.cc
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2019 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.
+ */
+#define LOG_TAG "bt_gd_neigh"
+
+#include "neighbor/scan.h"
+#include <memory>
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace neighbor {
+
+struct ScanModule::impl {
+ impl(ScanModule& module);
+
+ void SetInquiryScan(bool enabled);
+ bool IsInquiryEnabled() const;
+
+ void SetPageScan(bool enabled);
+ bool IsPageEnabled() const;
+
+ void Start();
+ void Stop();
+
+ private:
+ ScanModule& module_;
+
+ bool inquiry_scan_enabled_;
+ bool page_scan_enabled_;
+
+ void WriteScanEnable();
+ void ReadScanEnable(hci::ScanEnable);
+
+ void OnCommandComplete(hci::CommandCompleteView status);
+
+ hci::HciLayer* hci_layer_;
+ os::Handler* handler_;
+};
+
+const ModuleFactory neighbor::ScanModule::Factory = ModuleFactory([]() { return new neighbor::ScanModule(); });
+
+neighbor::ScanModule::impl::impl(neighbor::ScanModule& module)
+ : module_(module), inquiry_scan_enabled_(false), page_scan_enabled_(false) {}
+
+void neighbor::ScanModule::impl::OnCommandComplete(hci::CommandCompleteView view) {
+ switch (view.GetCommandOpCode()) {
+ case hci::OpCode::READ_SCAN_ENABLE: {
+ auto packet = hci::ReadScanEnableCompleteView::Create(view);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ ReadScanEnable(packet.GetScanEnable());
+ } break;
+
+ case hci::OpCode::WRITE_SCAN_ENABLE: {
+ auto packet = hci::WriteScanEnableCompleteView::Create(view);
+ ASSERT(packet.IsValid());
+ ASSERT(packet.GetStatus() == hci::ErrorCode::SUCCESS);
+ } break;
+
+ default:
+ LOG_ERROR("Unhandled command %s", hci::OpCodeText(view.GetCommandOpCode()).c_str());
+ break;
+ }
+}
+
+void neighbor::ScanModule::impl::WriteScanEnable() {
+ hci::ScanEnable scan_enable;
+
+ if (inquiry_scan_enabled_ && !page_scan_enabled_) {
+ scan_enable = hci::ScanEnable::INQUIRY_SCAN_ONLY;
+ } else if (!inquiry_scan_enabled_ && page_scan_enabled_) {
+ scan_enable = hci::ScanEnable::PAGE_SCAN_ONLY;
+ } else if (inquiry_scan_enabled_ && page_scan_enabled_) {
+ scan_enable = hci::ScanEnable::INQUIRY_AND_PAGE_SCAN;
+ } else {
+ scan_enable = hci::ScanEnable::NO_SCANS;
+ }
+
+ {
+ std::unique_ptr<hci::WriteScanEnableBuilder> packet = hci::WriteScanEnableBuilder::Create(scan_enable);
+ hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)),
+ handler_);
+ }
+
+ {
+ std::unique_ptr<hci::ReadScanEnableBuilder> packet = hci::ReadScanEnableBuilder::Create();
+ hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)),
+ handler_);
+ }
+}
+
+void neighbor::ScanModule::impl::ReadScanEnable(hci::ScanEnable scan_enable) {
+ switch (scan_enable) {
+ case hci::ScanEnable::INQUIRY_SCAN_ONLY:
+ inquiry_scan_enabled_ = true;
+ page_scan_enabled_ = false;
+ break;
+
+ case hci::ScanEnable::PAGE_SCAN_ONLY:
+ inquiry_scan_enabled_ = false;
+ page_scan_enabled_ = true;
+ break;
+
+ case hci::ScanEnable::INQUIRY_AND_PAGE_SCAN:
+ inquiry_scan_enabled_ = true;
+ page_scan_enabled_ = true;
+ break;
+
+ default:
+ inquiry_scan_enabled_ = false;
+ page_scan_enabled_ = false;
+ break;
+ }
+}
+
+void neighbor::ScanModule::impl::SetInquiryScan(bool enabled) {
+ inquiry_scan_enabled_ = enabled;
+ WriteScanEnable();
+}
+
+void neighbor::ScanModule::impl::SetPageScan(bool enabled) {
+ page_scan_enabled_ = enabled;
+ WriteScanEnable();
+}
+
+bool neighbor::ScanModule::impl::IsInquiryEnabled() const {
+ return inquiry_scan_enabled_;
+}
+
+bool neighbor::ScanModule::impl::IsPageEnabled() const {
+ return page_scan_enabled_;
+}
+
+void neighbor::ScanModule::impl::Start() {
+ hci_layer_ = module_.GetDependency<hci::HciLayer>();
+ handler_ = module_.GetHandler();
+
+ std::unique_ptr<hci::ReadScanEnableBuilder> packet = hci::ReadScanEnableBuilder::Create();
+ hci_layer_->EnqueueCommand(std::move(packet), common::BindOnce(&impl::OnCommandComplete, common::Unretained(this)),
+ handler_);
+}
+
+void neighbor::ScanModule::impl::Stop() {
+ LOG_DEBUG("inquiry scan enabled:%d page scan enabled:%d", inquiry_scan_enabled_, page_scan_enabled_);
+}
+
+neighbor::ScanModule::ScanModule() : pimpl_(std::make_unique<impl>(*this)) {}
+
+neighbor::ScanModule::~ScanModule() {
+ pimpl_.reset();
+}
+
+void neighbor::ScanModule::SetInquiryScan() {
+ pimpl_->SetInquiryScan(true);
+}
+
+void neighbor::ScanModule::ClearInquiryScan() {
+ pimpl_->SetInquiryScan(false);
+}
+
+void neighbor::ScanModule::SetPageScan() {
+ pimpl_->SetPageScan(true);
+}
+
+void neighbor::ScanModule::ClearPageScan() {
+ pimpl_->SetPageScan(false);
+}
+
+bool neighbor::ScanModule::IsInquiryEnabled() const {
+ return pimpl_->IsInquiryEnabled();
+}
+
+bool neighbor::ScanModule::IsPageEnabled() const {
+ return pimpl_->IsPageEnabled();
+}
+
+void neighbor::ScanModule::ListDependencies(ModuleList* list) {
+ list->add<hci::HciLayer>();
+}
+
+void neighbor::ScanModule::Start() {
+ pimpl_->Start();
+}
+
+void neighbor::ScanModule::Stop() {
+ pimpl_->Stop();
+}
+
+} // namespace neighbor
+} // namespace bluetooth
diff --git a/gd/neighbor/scan.h b/gd/neighbor/scan.h
new file mode 100644
index 0000000..b6499d3
--- /dev/null
+++ b/gd/neighbor/scan.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <memory>
+
+#include "module.h"
+
+namespace bluetooth {
+namespace neighbor {
+
+class ScanModule : public bluetooth::Module {
+ public:
+ ScanModule();
+ ~ScanModule();
+
+ void SetInquiryScan();
+ void ClearInquiryScan();
+ bool IsInquiryEnabled() const;
+
+ void SetPageScan();
+ void ClearPageScan();
+ bool IsPageEnabled() const;
+
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override;
+ void Start() override;
+ void Stop() override;
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScanModule);
+};
+
+} // namespace neighbor
+} // namespace bluetooth
diff --git a/gd/neighbor/scan_parameters.h b/gd/neighbor/scan_parameters.h
new file mode 100644
index 0000000..8927ee1
--- /dev/null
+++ b/gd/neighbor/scan_parameters.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <cstdint>
+
+namespace bluetooth {
+namespace neighbor {
+
+static constexpr double kTimeTickMs = 0.625;
+
+using ScanInterval = uint16_t; // Range 0x0012 to 0x1000; only even values valid 11.25 to 2560ms
+using ScanWindow = uint16_t; // Range 0x0011 to 0x1000; 10.625ms to 2560ms
+
+inline double ScanIntervalTimeMs(ScanInterval interval) {
+ return kTimeTickMs * interval;
+}
+
+inline double ScanWindowTimeMs(ScanWindow window) {
+ return kTimeTickMs * window;
+}
+
+using ScanParameters = struct {
+ ScanInterval interval;
+ ScanWindow window;
+};
+
+} // namespace neighbor
+} // namespace bluetooth
diff --git a/gd/os/Android.bp b/gd/os/Android.bp
index 535f144..b8ad91a 100644
--- a/gd/os/Android.bp
+++ b/gd/os/Android.bp
@@ -5,8 +5,9 @@
"linux_generic/handler.cc",
"linux_generic/reactor.cc",
"linux_generic/repeating_alarm.cc",
+ "linux_generic/reactive_semaphore.cc",
"linux_generic/thread.cc",
- ]
+ ],
}
filegroup {
@@ -14,10 +15,11 @@
srcs: [
"linux_generic/alarm_unittest.cc",
"linux_generic/handler_unittest.cc",
+ "linux_generic/queue_unittest.cc",
"linux_generic/reactor_unittest.cc",
"linux_generic/repeating_alarm_unittest.cc",
"linux_generic/thread_unittest.cc",
- ]
+ ],
}
filegroup {
@@ -25,5 +27,6 @@
srcs: [
"alarm_benchmark.cc",
"thread_benchmark.cc",
- ]
+ "queue_benchmark.cc",
+ ],
}
diff --git a/gd/os/alarm.h b/gd/os/alarm.h
index 6c07474..e529fb9 100644
--- a/gd/os/alarm.h
+++ b/gd/os/alarm.h
@@ -20,6 +20,8 @@
#include <memory>
#include <mutex>
+#include "common/callback.h"
+#include "os/handler.h"
#include "os/thread.h"
#include "os/utils.h"
@@ -31,8 +33,8 @@
// itself from the thread.
class Alarm {
public:
- // Create and register a single-shot alarm on given thread
- explicit Alarm(Thread* thread);
+ // Create and register a single-shot alarm on a given handler
+ explicit Alarm(Handler* handler);
// Unregister this alarm from the thread and release resource
~Alarm();
@@ -40,14 +42,14 @@
DISALLOW_COPY_AND_ASSIGN(Alarm);
// Schedule the alarm with given delay
- void Schedule(Closure task, std::chrono::milliseconds delay);
+ void Schedule(OnceClosure task, std::chrono::milliseconds delay);
// Cancel the alarm. No-op if it's not armed.
void Cancel();
private:
- Closure task_;
- Thread* thread_;
+ OnceClosure task_;
+ Handler* handler_;
int fd_ = 0;
Reactor::Reactable* token_;
mutable std::mutex mutex_;
diff --git a/gd/os/alarm_benchmark.cc b/gd/os/alarm_benchmark.cc
index 54b8a38..2150625 100644
--- a/gd/os/alarm_benchmark.cc
+++ b/gd/os/alarm_benchmark.cc
@@ -20,12 +20,15 @@
#include "benchmark/benchmark.h"
+#include "common/bind.h"
#include "os/alarm.h"
#include "os/repeating_alarm.h"
#include "os/thread.h"
using ::benchmark::State;
+using ::bluetooth::common::Bind;
using ::bluetooth::os::Alarm;
+using ::bluetooth::os::Handler;
using ::bluetooth::os::RepeatingAlarm;
using ::bluetooth::os::Thread;
@@ -34,8 +37,9 @@
void SetUp(State& st) override {
::benchmark::Fixture::SetUp(st);
thread_ = std::make_unique<Thread>("timer_benchmark", Thread::Priority::REAL_TIME);
- alarm_ = std::make_unique<Alarm>(thread_.get());
- repeating_alarm_ = std::make_unique<RepeatingAlarm>(thread_.get());
+ handler_ = std::make_unique<Handler>(thread_.get());
+ alarm_ = std::make_unique<Alarm>(handler_.get());
+ repeating_alarm_ = std::make_unique<RepeatingAlarm>(handler_.get());
map_.clear();
scheduled_tasks_ = 0;
task_length_ = 0;
@@ -47,6 +51,7 @@
void TearDown(State& st) override {
alarm_ = nullptr;
repeating_alarm_ = nullptr;
+ handler_ = nullptr;
thread_->Stop();
thread_ = nullptr;
::benchmark::Fixture::TearDown(st);
@@ -75,6 +80,7 @@
std::promise<void> promise_;
std::chrono::time_point<std::chrono::steady_clock> start_time_;
std::unique_ptr<Thread> thread_;
+ std::unique_ptr<Handler> handler_;
std::unique_ptr<Alarm> alarm_;
std::unique_ptr<RepeatingAlarm> repeating_alarm_;
};
@@ -83,7 +89,9 @@
auto milliseconds = static_cast<int>(state.range(0));
for (auto _ : state) {
auto start_time_point = std::chrono::steady_clock::now();
- alarm_->Schedule([this] { return TimerFire(); }, std::chrono::milliseconds(milliseconds));
+ alarm_->Schedule(
+ Bind(&BM_ReactableAlarm_timer_performance_ms_Benchmark::TimerFire, bluetooth::common::Unretained(this)),
+ std::chrono::milliseconds(milliseconds));
promise_.get_future().get();
auto end_time_point = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time_point - start_time_point);
@@ -109,7 +117,9 @@
task_length_ = state.range(1);
task_interval_ = state.range(2);
start_time_ = std::chrono::steady_clock::now();
- repeating_alarm_->Schedule([this] { AlarmSleepAndCountDelayedTime(); }, std::chrono::milliseconds(task_interval_));
+ repeating_alarm_->Schedule(Bind(&BM_ReactableAlarm_periodic_accuracy_Benchmark::AlarmSleepAndCountDelayedTime,
+ bluetooth::common::Unretained(this)),
+ std::chrono::milliseconds(task_interval_));
promise_.get_future().get();
repeating_alarm_->Cancel();
}
diff --git a/gd/os/handler.h b/gd/os/handler.h
index dc6d510..d9dea0b 100644
--- a/gd/os/handler.h
+++ b/gd/os/handler.h
@@ -21,6 +21,7 @@
#include <mutex>
#include <queue>
+#include "common/callback.h"
#include "os/thread.h"
#include "os/utils.h"
@@ -41,13 +42,26 @@
DISALLOW_COPY_AND_ASSIGN(Handler);
// Enqueue a closure to the queue of this handler
- void Post(Closure closure);
+ void Post(OnceClosure closure);
// Remove all pending events from the queue of this handler
void Clear();
+ // Die if the current reactable doesn't stop before the timeout. Must be called after Clear()
+ void WaitUntilStopped(std::chrono::milliseconds timeout);
+
+ template <typename T>
+ friend class Queue;
+
+ friend class Alarm;
+
+ friend class RepeatingAlarm;
+
private:
- std::queue<Closure> tasks_;
+ inline bool was_cleared() const {
+ return tasks_ == nullptr;
+ };
+ std::queue<OnceClosure>* tasks_;
Thread* thread_;
int fd_;
Reactor::Reactable* reactable_;
diff --git a/gd/os/linux_generic/alarm.cc b/gd/os/linux_generic/alarm.cc
index b1ee5b0..a2d895e 100644
--- a/gd/os/linux_generic/alarm.cc
+++ b/gd/os/linux_generic/alarm.cc
@@ -20,6 +20,7 @@
#include <cstring>
#include <unistd.h>
+#include "common/bind.h"
#include "os/log.h"
#include "os/utils.h"
@@ -32,23 +33,22 @@
namespace bluetooth {
namespace os {
-Alarm::Alarm(Thread* thread)
- : thread_(thread),
- fd_(timerfd_create(ALARM_CLOCK, 0)) {
+Alarm::Alarm(Handler* handler) : handler_(handler), fd_(timerfd_create(ALARM_CLOCK, 0)) {
ASSERT_LOG(fd_ != -1, "cannot create timerfd: %s", strerror(errno));
- token_ = thread_->GetReactor()->Register(fd_, [this] { on_fire(); }, nullptr);
+ token_ = handler_->thread_->GetReactor()->Register(fd_, common::Bind(&Alarm::on_fire, common::Unretained(this)),
+ Closure());
}
Alarm::~Alarm() {
- thread_->GetReactor()->Unregister(token_);
+ handler_->thread_->GetReactor()->Unregister(token_);
int close_status;
RUN_NO_INTR(close_status = close(fd_));
ASSERT(close_status != -1);
}
-void Alarm::Schedule(Closure task, std::chrono::milliseconds delay) {
+void Alarm::Schedule(OnceClosure task, std::chrono::milliseconds delay) {
std::lock_guard<std::mutex> lock(mutex_);
long delay_ms = delay.count();
itimerspec timer_itimerspec{
@@ -74,7 +74,7 @@
uint64_t times_invoked;
auto bytes_read = read(fd_, ×_invoked, sizeof(uint64_t));
lock.unlock();
- task();
+ std::move(task).Run();
ASSERT(bytes_read == static_cast<ssize_t>(sizeof(uint64_t)));
ASSERT(times_invoked == static_cast<uint64_t>(1));
}
diff --git a/gd/os/linux_generic/alarm_unittest.cc b/gd/os/linux_generic/alarm_unittest.cc
index 3ffd0d9..b389a82 100644
--- a/gd/os/linux_generic/alarm_unittest.cc
+++ b/gd/os/linux_generic/alarm_unittest.cc
@@ -18,26 +18,33 @@
#include <future>
+#include "common/bind.h"
#include "gtest/gtest.h"
namespace bluetooth {
namespace os {
namespace {
+using common::BindOnce;
+
class AlarmTest : public ::testing::Test {
protected:
void SetUp() override {
thread_ = new Thread("test_thread", Thread::Priority::NORMAL);
- alarm_ = new Alarm(thread_);
+ handler_ = new Handler(thread_);
+ alarm_ = new Alarm(handler_);
}
void TearDown() override {
delete alarm_;
+ handler_->Clear();
+ delete handler_;
delete thread_;
}
Alarm* alarm_;
private:
+ Handler* handler_;
Thread* thread_;
};
@@ -51,7 +58,8 @@
auto before = std::chrono::steady_clock::now();
int delay_ms = 10;
int delay_error_ms = 3;
- alarm_->Schedule([&promise]() { promise.set_value(); }, std::chrono::milliseconds(delay_ms));
+ alarm_->Schedule(BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)),
+ std::chrono::milliseconds(delay_ms));
future.get();
auto after = std::chrono::steady_clock::now();
auto duration_ms = std::chrono::duration_cast<std::chrono::milliseconds>(after - before);
@@ -59,26 +67,27 @@
}
TEST_F(AlarmTest, cancel_alarm) {
- alarm_->Schedule([]() { ASSERT_TRUE(false) << "Should not happen"; }, std::chrono::milliseconds(3));
+ alarm_->Schedule(BindOnce([]() { ASSERT_TRUE(false) << "Should not happen"; }), std::chrono::milliseconds(3));
alarm_->Cancel();
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
TEST_F(AlarmTest, cancel_alarm_from_callback) {
- alarm_->Schedule([this]() { this->alarm_->Cancel(); }, std::chrono::milliseconds(1));
+ alarm_->Schedule(BindOnce(&Alarm::Cancel, common::Unretained(alarm_)), std::chrono::milliseconds(1));
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
TEST_F(AlarmTest, schedule_while_alarm_armed) {
- alarm_->Schedule([]() { ASSERT_TRUE(false) << "Should not happen"; }, std::chrono::milliseconds(1));
+ alarm_->Schedule(BindOnce([]() { ASSERT_TRUE(false) << "Should not happen"; }), std::chrono::milliseconds(1));
std::promise<void> promise;
auto future = promise.get_future();
- alarm_->Schedule([&promise]() { promise.set_value(); }, std::chrono::milliseconds(10));
+ alarm_->Schedule(BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)),
+ std::chrono::milliseconds(10));
future.get();
}
TEST_F(AlarmTest, delete_while_alarm_armed) {
- alarm_->Schedule([]() { ASSERT_TRUE(false) << "Should not happen"; }, std::chrono::milliseconds(1));
+ alarm_->Schedule(BindOnce([]() { ASSERT_TRUE(false) << "Should not happen"; }), std::chrono::milliseconds(1));
delete alarm_;
alarm_ = nullptr;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
diff --git a/gd/os/linux_generic/handler.cc b/gd/os/linux_generic/handler.cc
index cdb3240..85cbcc3 100644
--- a/gd/os/linux_generic/handler.cc
+++ b/gd/os/linux_generic/handler.cc
@@ -17,9 +17,11 @@
#include "os/handler.h"
#include <sys/eventfd.h>
-#include <cstring>
#include <unistd.h>
+#include <cstring>
+#include "common/bind.h"
+#include "common/callback.h"
#include "os/log.h"
#include "os/reactor.h"
#include "os/utils.h"
@@ -32,26 +34,30 @@
namespace os {
Handler::Handler(Thread* thread)
- : thread_(thread),
- fd_(eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK)) {
+ : tasks_(new std::queue<OnceClosure>()), thread_(thread), fd_(eventfd(0, EFD_SEMAPHORE | EFD_NONBLOCK)) {
ASSERT(fd_ != -1);
-
- reactable_ = thread_->GetReactor()->Register(fd_, [this] { this->handle_next_event(); }, nullptr);
+ reactable_ = thread_->GetReactor()->Register(fd_, common::Bind(&Handler::handle_next_event, common::Unretained(this)),
+ common::Closure());
}
Handler::~Handler() {
- thread_->GetReactor()->Unregister(reactable_);
- reactable_ = nullptr;
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT_LOG(was_cleared(), "Handlers must be cleared before they are destroyed");
+ }
int close_status;
RUN_NO_INTR(close_status = close(fd_));
ASSERT(close_status != -1);
}
-void Handler::Post(Closure closure) {
+void Handler::Post(OnceClosure closure) {
{
std::lock_guard<std::mutex> lock(mutex_);
- tasks_.emplace(std::move(closure));
+ if (was_cleared()) {
+ return;
+ }
+ tasks_->emplace(std::move(closure));
}
uint64_t val = 1;
auto write_result = eventfd_write(fd_, val);
@@ -59,34 +65,43 @@
}
void Handler::Clear() {
- std::lock_guard<std::mutex> lock(mutex_);
-
- std::queue<Closure> empty;
- std::swap(tasks_, empty);
+ std::queue<OnceClosure>* tmp = nullptr;
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT_LOG(!was_cleared(), "Handlers must only be cleared once");
+ std::swap(tasks_, tmp);
+ }
+ delete tmp;
uint64_t val;
while (eventfd_read(fd_, &val) == 0) {
}
+
+ thread_->GetReactor()->Unregister(reactable_);
+ reactable_ = nullptr;
+}
+
+void Handler::WaitUntilStopped(std::chrono::milliseconds timeout) {
+ ASSERT(reactable_ == nullptr);
+ ASSERT(thread_->GetReactor()->WaitForUnregisteredReactable(timeout));
}
void Handler::handle_next_event() {
- Closure closure;
- uint64_t val = 0;
- auto read_result = eventfd_read(fd_, &val);
- if (read_result == -1 && errno == EAGAIN) {
- // We were told there was an item, but it was removed before we got there
- // (aka the queue was cleared). Not a fatal error, so just bail.
- return;
- }
-
- ASSERT(read_result != -1);
-
+ common::OnceClosure closure;
{
std::lock_guard<std::mutex> lock(mutex_);
- closure = std::move(tasks_.front());
- tasks_.pop();
+ uint64_t val = 0;
+ auto read_result = eventfd_read(fd_, &val);
+
+ if (was_cleared()) {
+ return;
+ }
+ ASSERT_LOG(read_result != -1, "eventfd read error %d %s", errno, strerror(errno));
+
+ closure = std::move(tasks_->front());
+ tasks_->pop();
}
- closure();
+ std::move(closure).Run();
}
} // namespace os
diff --git a/gd/os/linux_generic/handler_unittest.cc b/gd/os/linux_generic/handler_unittest.cc
index 7e0488f..80456db 100644
--- a/gd/os/linux_generic/handler_unittest.cc
+++ b/gd/os/linux_generic/handler_unittest.cc
@@ -17,9 +17,13 @@
#include "os/handler.h"
#include <sys/eventfd.h>
+#include <future>
#include <thread>
+#include "common/bind.h"
+#include "common/callback.h"
#include "gtest/gtest.h"
+#include "os/log.h"
namespace bluetooth {
namespace os {
@@ -40,31 +44,103 @@
Thread* thread_;
};
-TEST_F(HandlerTest, empty) {}
+TEST_F(HandlerTest, empty) {
+ handler_->Clear();
+}
TEST_F(HandlerTest, post_task_invoked) {
int val = 0;
- Closure closure = [&val]() { val++; };
- handler_->Post(closure);
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- EXPECT_EQ(val, 1);
+ std::promise<void> closure_ran;
+ auto future = closure_ran.get_future();
+ OnceClosure closure = common::BindOnce(
+ [](int* val, std::promise<void> closure_ran) {
+ *val = *val + 1;
+ closure_ran.set_value();
+ },
+ common::Unretained(&val), std::move(closure_ran));
+ handler_->Post(std::move(closure));
+ future.wait();
+ ASSERT_EQ(val, 1);
+ handler_->Clear();
}
TEST_F(HandlerTest, post_task_cleared) {
int val = 0;
- Closure closure = [&val]() {
- val++;
- std::this_thread::sleep_for(std::chrono::milliseconds(5));
- };
- handler_->Post(std::move(closure));
- closure = []() {
- ASSERT_TRUE(false);
- };
- std::this_thread::sleep_for(std::chrono::milliseconds(5));
- handler_->Post(std::move(closure));
+ std::promise<void> closure_started;
+ auto closure_started_future = closure_started.get_future();
+ std::promise<void> closure_can_continue;
+ auto can_continue_future = closure_can_continue.get_future();
+ handler_->Post(common::BindOnce(
+ [](int* val, std::promise<void> closure_started, std::future<void> can_continue_future) {
+ closure_started.set_value();
+ *val = *val + 1;
+ can_continue_future.wait();
+ },
+ common::Unretained(&val), std::move(closure_started), std::move(can_continue_future)));
+ handler_->Post(common::BindOnce([]() { ASSERT_TRUE(false); }));
+ closure_started_future.wait();
handler_->Clear();
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
- EXPECT_EQ(val, 1);
+ closure_can_continue.set_value();
+ ASSERT_EQ(val, 1);
+}
+
+void check_int(std::unique_ptr<int> number, std::shared_ptr<int> to_change) {
+ *to_change = *number;
+}
+
+TEST_F(HandlerTest, once_callback) {
+ auto number = std::make_unique<int>(1);
+ auto to_change = std::make_shared<int>(0);
+ auto once_callback = common::BindOnce(&check_int, std::move(number), to_change);
+ std::move(once_callback).Run();
+ EXPECT_EQ(*to_change, 1);
+ handler_->Clear();
+}
+
+TEST_F(HandlerTest, callback_with_promise) {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ auto once_callback = common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise));
+ std::move(once_callback).Run();
+ future.wait();
+ handler_->Clear();
+}
+
+// For Death tests, all the threading needs to be done in the ASSERT_DEATH call
+class HandlerDeathTest : public ::testing::Test {
+ protected:
+ void ThreadSetUp() {
+ thread_ = new Thread("test_thread", Thread::Priority::NORMAL);
+ handler_ = new Handler(thread_);
+ }
+
+ void ThreadTearDown() {
+ delete handler_;
+ delete thread_;
+ }
+
+ void ClearTwice() {
+ ThreadSetUp();
+ handler_->Clear();
+ handler_->Clear();
+ ThreadTearDown();
+ }
+
+ void NotCleared() {
+ ThreadSetUp();
+ ThreadTearDown();
+ }
+
+ Handler* handler_;
+ Thread* thread_;
+};
+
+TEST_F(HandlerDeathTest, clear_after_handler_cleared) {
+ ASSERT_DEATH(ClearTwice(), "Handlers must only be cleared once");
+}
+
+TEST_F(HandlerDeathTest, not_cleared_before_destruction) {
+ ASSERT_DEATH(NotCleared(), "Handlers must be cleared");
}
} // namespace
diff --git a/gd/os/linux_generic/linux.h b/gd/os/linux_generic/linux.h
new file mode 100644
index 0000000..524aa7d
--- /dev/null
+++ b/gd/os/linux_generic/linux.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#ifndef EFD_SEMAPHORE
+#define EFD_SEMAPHORE 1
+#endif
diff --git a/gd/os/linux_generic/queue.tpp b/gd/os/linux_generic/queue.tpp
new file mode 100644
index 0000000..bd9a292
--- /dev/null
+++ b/gd/os/linux_generic/queue.tpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2019 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.
+ */
+
+template <typename T>
+Queue<T>::Queue(size_t capacity) : enqueue_(capacity), dequeue_(0){};
+
+template <typename T>
+Queue<T>::~Queue() {
+ ASSERT(enqueue_.handler_ == nullptr);
+ ASSERT(dequeue_.handler_ == nullptr);
+};
+
+template <typename T>
+void Queue<T>::RegisterEnqueue(Handler* handler, EnqueueCallback callback) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT(enqueue_.handler_ == nullptr);
+ ASSERT(enqueue_.reactable_ == nullptr);
+ enqueue_.handler_ = handler;
+ enqueue_.reactable_ = enqueue_.handler_->thread_->GetReactor()->Register(
+ enqueue_.reactive_semaphore_.GetFd(),
+ base::Bind(&Queue<T>::EnqueueCallbackInternal, base::Unretained(this), std::move(callback)),
+ base::Closure());
+}
+
+template <typename T>
+void Queue<T>::UnregisterEnqueue() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT(enqueue_.reactable_ != nullptr);
+ enqueue_.handler_->thread_->GetReactor()->Unregister(enqueue_.reactable_);
+ enqueue_.reactable_ = nullptr;
+ enqueue_.handler_ = nullptr;
+}
+
+template <typename T>
+void Queue<T>::RegisterDequeue(Handler* handler, DequeueCallback callback) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT(dequeue_.handler_ == nullptr);
+ ASSERT(dequeue_.reactable_ == nullptr);
+ dequeue_.handler_ = handler;
+ dequeue_.reactable_ = dequeue_.handler_->thread_->GetReactor()->Register(dequeue_.reactive_semaphore_.GetFd(),
+ callback, base::Closure());
+}
+
+template <typename T>
+void Queue<T>::UnregisterDequeue() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ ASSERT(dequeue_.reactable_ != nullptr);
+ dequeue_.handler_->thread_->GetReactor()->Unregister(dequeue_.reactable_);
+ dequeue_.reactable_ = nullptr;
+ dequeue_.handler_ = nullptr;
+}
+
+template <typename T>
+std::unique_ptr<T> Queue<T>::TryDequeue() {
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ if (queue_.empty()) {
+ return nullptr;
+ }
+
+ dequeue_.reactive_semaphore_.Decrease();
+
+ std::unique_ptr<T> data = std::move(queue_.front());
+ queue_.pop();
+
+ enqueue_.reactive_semaphore_.Increase();
+
+ return data;
+}
+
+template <typename T>
+void Queue<T>::EnqueueCallbackInternal(EnqueueCallback callback) {
+ std::unique_ptr<T> data = callback.Run();
+ ASSERT(data != nullptr);
+ std::lock_guard<std::mutex> lock(mutex_);
+ enqueue_.reactive_semaphore_.Decrease();
+ queue_.push(std::move(data));
+ dequeue_.reactive_semaphore_.Increase();
+}
diff --git a/gd/os/linux_generic/queue_unittest.cc b/gd/os/linux_generic/queue_unittest.cc
new file mode 100644
index 0000000..f0ca2bd
--- /dev/null
+++ b/gd/os/linux_generic/queue_unittest.cc
@@ -0,0 +1,834 @@
+/*
+ * Copyright 2019 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 "os/queue.h"
+
+#include <sys/eventfd.h>
+#include <future>
+#include <unordered_map>
+
+#include "common/bind.h"
+#include "gtest/gtest.h"
+#include "os/reactor.h"
+
+namespace bluetooth {
+namespace os {
+namespace {
+
+constexpr int kQueueSize = 10;
+constexpr int kHalfOfQueueSize = kQueueSize / 2;
+constexpr int kDoubleOfQueueSize = kQueueSize * 2;
+constexpr int kQueueSizeOne = 1;
+
+class QueueTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ enqueue_thread_ = new Thread("enqueue_thread", Thread::Priority::NORMAL);
+ enqueue_handler_ = new Handler(enqueue_thread_);
+ dequeue_thread_ = new Thread("dequeue_thread", Thread::Priority::NORMAL);
+ dequeue_handler_ = new Handler(dequeue_thread_);
+ }
+ void TearDown() override {
+ enqueue_handler_->Clear();
+ delete enqueue_handler_;
+ delete enqueue_thread_;
+ dequeue_handler_->Clear();
+ delete dequeue_handler_;
+ delete dequeue_thread_;
+ enqueue_handler_ = nullptr;
+ enqueue_thread_ = nullptr;
+ dequeue_handler_ = nullptr;
+ dequeue_thread_ = nullptr;
+ }
+
+ Thread* enqueue_thread_;
+ Handler* enqueue_handler_;
+ Thread* dequeue_thread_;
+ Handler* dequeue_handler_;
+};
+
+class TestEnqueueEnd {
+ public:
+ explicit TestEnqueueEnd(Queue<std::string>* queue, Handler* handler)
+ : count(0), handler_(handler), queue_(queue), delay_(0) {}
+
+ ~TestEnqueueEnd() {}
+
+ void RegisterEnqueue(std::unordered_map<int, std::promise<int>>* promise_map) {
+ promise_map_ = promise_map;
+ handler_->Post(common::BindOnce(&TestEnqueueEnd::handle_register_enqueue, common::Unretained(this)));
+ }
+
+ void UnregisterEnqueue() {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+
+ handler_->Post(
+ common::BindOnce(&TestEnqueueEnd::handle_unregister_enqueue, common::Unretained(this), std::move(promise)));
+ future.wait();
+ }
+
+ std::unique_ptr<std::string> EnqueueCallbackForTest() {
+ if (delay_ != 0) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(delay_));
+ }
+
+ count++;
+ std::unique_ptr<std::string> data = std::move(buffer_.front());
+ buffer_.pop();
+ std::string copy = *data;
+ if (buffer_.empty()) {
+ queue_->UnregisterEnqueue();
+ }
+
+ auto pair = promise_map_->find(buffer_.size());
+ if (pair != promise_map_->end()) {
+ pair->second.set_value(pair->first);
+ promise_map_->erase(pair->first);
+ }
+ return data;
+ }
+
+ void setDelay(int value) {
+ delay_ = value;
+ }
+
+ std::queue<std::unique_ptr<std::string>> buffer_;
+ int count;
+
+ private:
+ Handler* handler_;
+ Queue<std::string>* queue_;
+ std::unordered_map<int, std::promise<int>>* promise_map_;
+ int delay_;
+
+ void handle_register_enqueue() {
+ queue_->RegisterEnqueue(handler_, common::Bind(&TestEnqueueEnd::EnqueueCallbackForTest, common::Unretained(this)));
+ }
+
+ void handle_unregister_enqueue(std::promise<void> promise) {
+ queue_->UnregisterEnqueue();
+ promise.set_value();
+ }
+};
+
+class TestDequeueEnd {
+ public:
+ explicit TestDequeueEnd(Queue<std::string>* queue, Handler* handler, int capacity)
+ : count(0), handler_(handler), queue_(queue), capacity_(capacity), delay_(0) {}
+
+ ~TestDequeueEnd() {}
+
+ void RegisterDequeue(std::unordered_map<int, std::promise<int>>* promise_map) {
+ promise_map_ = promise_map;
+ handler_->Post(common::BindOnce(&TestDequeueEnd::handle_register_dequeue, common::Unretained(this)));
+ }
+
+ void UnregisterDequeue() {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+
+ handler_->Post(
+ common::BindOnce(&TestDequeueEnd::handle_unregister_dequeue, common::Unretained(this), std::move(promise)));
+ future.wait();
+ }
+
+ void DequeueCallbackForTest() {
+ if (delay_ != 0) {
+ std::this_thread::sleep_for(std::chrono::milliseconds(delay_));
+ }
+
+ count++;
+ std::unique_ptr<std::string> data = queue_->TryDequeue();
+ buffer_.push(std::move(data));
+
+ if (buffer_.size() == capacity_) {
+ queue_->UnregisterDequeue();
+ }
+
+ auto pair = promise_map_->find(buffer_.size());
+ if (pair != promise_map_->end()) {
+ pair->second.set_value(pair->first);
+ promise_map_->erase(pair->first);
+ }
+ }
+
+ void setDelay(int value) {
+ delay_ = value;
+ }
+
+ std::queue<std::unique_ptr<std::string>> buffer_;
+ int count;
+
+ private:
+ Handler* handler_;
+ Queue<std::string>* queue_;
+ std::unordered_map<int, std::promise<int>>* promise_map_;
+ int capacity_;
+ int delay_;
+
+ void handle_register_dequeue() {
+ queue_->RegisterDequeue(handler_, common::Bind(&TestDequeueEnd::DequeueCallbackForTest, common::Unretained(this)));
+ }
+
+ void handle_unregister_dequeue(std::promise<void> promise) {
+ queue_->UnregisterDequeue();
+ promise.set_value();
+ }
+};
+
+// Enqueue end level : 0 -> queue is full, 1 - > queue isn't full
+// Dequeue end level : 0 -> queue is empty, 1 - > queue isn't empty
+
+// Test 1 : Queue is empty
+
+// Enqueue end level : 1
+// Dequeue end level : 0
+// Test 1-1 EnqueueCallback should continually be invoked when queue isn't full
+TEST_F(QueueTest, register_enqueue_with_empty_queue) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+
+ // Push kQueueSize data to enqueue_end buffer
+ for (int i = 0; i < kQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ EXPECT_EQ(test_enqueue_end.buffer_.size(), (size_t)kQueueSize);
+
+ // Register enqueue and expect data move to Queue
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple());
+ auto enqueue_future = enqueue_promise_map[0].get_future();
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), 0);
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+}
+
+// Enqueue end level : 1
+// Dequeue end level : 0
+// Test 1-2 DequeueCallback shouldn't be invoked when queue is empty
+TEST_F(QueueTest, register_dequeue_with_empty_queue) {
+ Queue<std::string> queue(kQueueSize);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kQueueSize);
+
+ // Register dequeue, DequeueCallback shouldn't be invoked
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ EXPECT_EQ(test_dequeue_end.count, 0);
+
+ test_dequeue_end.UnregisterDequeue();
+}
+
+// Test 2 : Queue is full
+
+// Enqueue end level : 0
+// Dequeue end level : 1
+// Test 2-1 EnqueueCallback shouldn't be invoked when queue is full
+TEST_F(QueueTest, register_enqueue_with_full_queue) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+
+ // make Queue full
+ for (int i = 0; i < kQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple());
+ auto enqueue_future = enqueue_promise_map[0].get_future();
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), 0);
+
+ // push some data to enqueue_end buffer and register enqueue;
+ for (int i = 0; i < kHalfOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+
+ // EnqueueCallback shouldn't be invoked
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ EXPECT_EQ(test_enqueue_end.buffer_.size(), (size_t)kHalfOfQueueSize);
+ EXPECT_EQ(test_enqueue_end.count, kQueueSize);
+
+ test_enqueue_end.UnregisterEnqueue();
+}
+
+// Enqueue end level : 0
+// Dequeue end level : 1
+// Test 2-2 DequeueCallback should continually be invoked when queue isn't empty
+TEST_F(QueueTest, register_dequeue_with_full_queue) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kDoubleOfQueueSize);
+
+ // make Queue full
+ for (int i = 0; i < kQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple());
+ auto enqueue_future = enqueue_promise_map[0].get_future();
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), 0);
+
+ // Register dequeue and expect data move to dequeue end buffer
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ dequeue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kQueueSize), std::forward_as_tuple());
+ auto dequeue_future = dequeue_promise_map[kQueueSize].get_future();
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+ dequeue_future.wait();
+ EXPECT_EQ(dequeue_future.get(), kQueueSize);
+
+ test_dequeue_end.UnregisterDequeue();
+}
+
+// Test 3 : Queue is non-empty and non-full
+
+// Enqueue end level : 1
+// Dequeue end level : 1
+// Test 3-1 Register enqueue with half empty queue, EnqueueCallback should continually be invoked
+TEST_F(QueueTest, register_enqueue_with_half_empty_queue) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+
+ // make Queue half empty
+ for (int i = 0; i < kHalfOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple());
+ auto enqueue_future = enqueue_promise_map[0].get_future();
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), 0);
+
+ // push some data to enqueue_end buffer and register enqueue;
+ for (int i = 0; i < kHalfOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+
+ // Register enqueue and expect data move to Queue
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple());
+ enqueue_future = enqueue_promise_map[0].get_future();
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), 0);
+}
+
+// Enqueue end level : 1
+// Dequeue end level : 1
+// Test 3-2 Register dequeue with half empty queue, DequeueCallback should continually be invoked
+TEST_F(QueueTest, register_dequeue_with_half_empty_queue) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kQueueSize);
+
+ // make Queue half empty
+ for (int i = 0; i < kHalfOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple());
+ auto enqueue_future = enqueue_promise_map[0].get_future();
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), 0);
+
+ // Register dequeue and expect data move to dequeue end buffer
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ dequeue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kHalfOfQueueSize),
+ std::forward_as_tuple());
+ auto dequeue_future = dequeue_promise_map[kHalfOfQueueSize].get_future();
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+ dequeue_future.wait();
+ EXPECT_EQ(dequeue_future.get(), kHalfOfQueueSize);
+
+ test_dequeue_end.UnregisterDequeue();
+}
+
+// Dynamic level test
+
+// Test 4 : Queue becomes full during test, EnqueueCallback should stop to be invoked
+
+// Enqueue end level : 1 -> 0
+// Dequeue end level : 1
+// Test 4-1 Queue becomes full due to only register EnqueueCallback
+TEST_F(QueueTest, queue_becomes_full_enqueue_callback_only) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+
+ // push double of kQueueSize to enqueue end buffer
+ for (int i = 0; i < kDoubleOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+
+ // Register enqueue and expect kQueueSize data move to Queue
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kQueueSize), std::forward_as_tuple());
+ auto enqueue_future = enqueue_promise_map[kQueueSize].get_future();
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), kQueueSize);
+
+ // EnqueueCallback shouldn't be invoked and buffer size stay in kQueueSize
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ EXPECT_EQ(test_enqueue_end.buffer_.size(), (size_t)kQueueSize);
+ EXPECT_EQ(test_enqueue_end.count, kQueueSize);
+
+ test_enqueue_end.UnregisterEnqueue();
+}
+
+// Enqueue end level : 1 -> 0
+// Dequeue end level : 1
+// Test 4-2 Queue becomes full due to DequeueCallback unregister during test
+TEST_F(QueueTest, queue_becomes_full_dequeue_callback_unregister) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kHalfOfQueueSize);
+
+ // push double of kQueueSize to enqueue end buffer
+ for (int i = 0; i < kDoubleOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+
+ // Register dequeue
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ dequeue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kHalfOfQueueSize),
+ std::forward_as_tuple());
+ auto dequeue_future = dequeue_promise_map[kHalfOfQueueSize].get_future();
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+
+ // Register enqueue
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kHalfOfQueueSize),
+ std::forward_as_tuple());
+ auto enqueue_future = enqueue_promise_map[kHalfOfQueueSize].get_future();
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+
+ // Dequeue end will unregister when buffer size is kHalfOfQueueSize
+ dequeue_future.wait();
+ EXPECT_EQ(dequeue_future.get(), kHalfOfQueueSize);
+
+ // EnqueueCallback shouldn't be invoked and buffer size stay in kHalfOfQueueSize
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), kHalfOfQueueSize);
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ EXPECT_EQ(test_enqueue_end.buffer_.size(), (size_t)kHalfOfQueueSize);
+ EXPECT_EQ(test_enqueue_end.count, kQueueSize + kHalfOfQueueSize);
+
+ test_enqueue_end.UnregisterEnqueue();
+}
+
+// Enqueue end level : 1 -> 0
+// Dequeue end level : 1
+// Test 4-3 Queue becomes full due to DequeueCallback is slower
+TEST_F(QueueTest, queue_becomes_full_dequeue_callback_slower) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kDoubleOfQueueSize);
+
+ // push double of kDoubleOfQueueSize to enqueue end buffer
+ for (int i = 0; i < kDoubleOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+
+ // Set 20 ms delay for callback and register dequeue
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ test_dequeue_end.setDelay(20);
+ auto dequeue_future = dequeue_promise_map[kHalfOfQueueSize].get_future();
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+
+ // Register enqueue
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple());
+ auto enqueue_future = enqueue_promise_map[0].get_future();
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+
+ // Wait for enqueue buffer empty and expect queue is full
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), 0);
+ EXPECT_GE(test_dequeue_end.buffer_.size(), kQueueSize - 1);
+
+ test_dequeue_end.UnregisterDequeue();
+}
+
+// Enqueue end level : 0 -> 1
+// Dequeue end level : 1 -> 0
+// Test 5 Queue becomes full and non empty at same time.
+TEST_F(QueueTest, queue_becomes_full_and_non_empty_at_same_time) {
+ Queue<std::string> queue(kQueueSizeOne);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kDoubleOfQueueSize);
+
+ // push double of kQueueSize to enqueue end buffer
+ for (int i = 0; i < kQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+
+ // Register dequeue
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ dequeue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kQueueSize), std::forward_as_tuple());
+ auto dequeue_future = dequeue_promise_map[kQueueSize].get_future();
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+
+ // Register enqueue
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ auto enqueue_future = enqueue_promise_map[0].get_future();
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+
+ // Wait for all data move from enqueue end buffer to dequeue end buffer
+ dequeue_future.wait();
+ EXPECT_EQ(dequeue_future.get(), kQueueSize);
+
+ test_dequeue_end.UnregisterDequeue();
+}
+
+// Enqueue end level : 1 -> 0
+// Dequeue end level : 1
+// Test 6 Queue becomes not full during test, EnqueueCallback should start to be invoked
+TEST_F(QueueTest, queue_becomes_non_full_during_test) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kQueueSize * 3);
+
+ // make Queue full
+ for (int i = 0; i < kDoubleOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kQueueSize), std::forward_as_tuple());
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple());
+ auto enqueue_future = enqueue_promise_map[kQueueSize].get_future();
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), kQueueSize);
+
+ // Expect kQueueSize data block in enqueue end buffer
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ EXPECT_EQ(test_enqueue_end.buffer_.size(), kQueueSize);
+
+ // Register dequeue
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+
+ // Expect enqueue end will empty
+ enqueue_future = enqueue_promise_map[0].get_future();
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), 0);
+
+ test_dequeue_end.UnregisterDequeue();
+}
+
+// Enqueue end level : 0 -> 1
+// Dequeue end level : 1 -> 0
+// Test 7 Queue becomes non full and empty at same time. (Exactly same as Test 5)
+TEST_F(QueueTest, queue_becomes_non_full_and_empty_at_same_time) {
+ Queue<std::string> queue(kQueueSizeOne);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kDoubleOfQueueSize);
+
+ // push double of kQueueSize to enqueue end buffer
+ for (int i = 0; i < kQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+
+ // Register dequeue
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ dequeue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kQueueSize), std::forward_as_tuple());
+ auto dequeue_future = dequeue_promise_map[kQueueSize].get_future();
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+
+ // Register enqueue
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ auto enqueue_future = enqueue_promise_map[0].get_future();
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+
+ // Wait for all data move from enqueue end buffer to dequeue end buffer
+ dequeue_future.wait();
+ EXPECT_EQ(dequeue_future.get(), kQueueSize);
+
+ test_dequeue_end.UnregisterDequeue();
+}
+
+// Test 8 : Queue becomes empty during test, DequeueCallback should stop to be invoked
+
+// Enqueue end level : 1
+// Dequeue end level : 1 -> 0
+// Test 8-1 Queue becomes empty due to only register DequeueCallback
+TEST_F(QueueTest, queue_becomes_empty_dequeue_callback_only) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kHalfOfQueueSize);
+
+ // make Queue half empty
+ for (int i = 0; i < kHalfOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple());
+ auto enqueue_future = enqueue_promise_map[0].get_future();
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), 0);
+
+ // Register dequeue, expect kHalfOfQueueSize data move to dequeue end buffer
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ dequeue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kHalfOfQueueSize),
+ std::forward_as_tuple());
+ auto dequeue_future = dequeue_promise_map[kHalfOfQueueSize].get_future();
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+ dequeue_future.wait();
+ EXPECT_EQ(dequeue_future.get(), kHalfOfQueueSize);
+
+ // Expect DequeueCallback should stop to be invoked
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ EXPECT_EQ(test_dequeue_end.count, kHalfOfQueueSize);
+}
+
+// Enqueue end level : 1
+// Dequeue end level : 1 -> 0
+// Test 8-2 Queue becomes empty due to EnqueueCallback unregister during test
+TEST_F(QueueTest, queue_becomes_empty_enqueue_callback_unregister) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kQueueSize);
+
+ // make Queue half empty
+ for (int i = 0; i < kHalfOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ enqueue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(0), std::forward_as_tuple());
+ auto enqueue_future = enqueue_promise_map[0].get_future();
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+ enqueue_future.wait();
+ EXPECT_EQ(enqueue_future.get(), 0);
+
+ // push kHalfOfQueueSize to enqueue end buffer and register enqueue.
+ for (int i = 0; i < kHalfOfQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+
+ // Register dequeue, expect kQueueSize move to dequeue end buffer
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ dequeue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kQueueSize), std::forward_as_tuple());
+ auto dequeue_future = dequeue_promise_map[kQueueSize].get_future();
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+ dequeue_future.wait();
+ EXPECT_EQ(dequeue_future.get(), kQueueSize);
+
+ // Expect DequeueCallback should stop to be invoked
+ std::this_thread::sleep_for(std::chrono::milliseconds(20));
+ EXPECT_EQ(test_dequeue_end.count, kQueueSize);
+}
+
+// Enqueue end level : 1
+// Dequeue end level : 0 -> 1
+// Test 9 Queue becomes not empty during test, DequeueCallback should start to be invoked
+TEST_F(QueueTest, queue_becomes_non_empty_during_test) {
+ Queue<std::string> queue(kQueueSize);
+ TestEnqueueEnd test_enqueue_end(&queue, enqueue_handler_);
+ TestDequeueEnd test_dequeue_end(&queue, dequeue_handler_, kQueueSize);
+
+ // Register dequeue
+ std::unordered_map<int, std::promise<int>> dequeue_promise_map;
+ dequeue_promise_map.emplace(std::piecewise_construct, std::forward_as_tuple(kQueueSize), std::forward_as_tuple());
+ test_dequeue_end.RegisterDequeue(&dequeue_promise_map);
+
+ // push kQueueSize data to enqueue end buffer and register enqueue
+ for (int i = 0; i < kQueueSize; i++) {
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::to_string(i));
+ test_enqueue_end.buffer_.push(std::move(data));
+ }
+ std::unordered_map<int, std::promise<int>> enqueue_promise_map;
+ test_enqueue_end.RegisterEnqueue(&enqueue_promise_map);
+
+ // Expect kQueueSize data move to dequeue end buffer
+ auto dequeue_future = dequeue_promise_map[kQueueSize].get_future();
+ dequeue_future.wait();
+ EXPECT_EQ(dequeue_future.get(), kQueueSize);
+}
+
+TEST_F(QueueTest, pass_smart_pointer_and_unregister) {
+ Queue<std::string>* queue = new Queue<std::string>(kQueueSize);
+
+ // Enqueue a string
+ std::string valid = "Valid String";
+ std::shared_ptr<std::string> shared = std::make_shared<std::string>(valid);
+ queue->RegisterEnqueue(enqueue_handler_, common::Bind(
+ [](Queue<std::string>* queue, std::shared_ptr<std::string> shared) {
+ queue->UnregisterEnqueue();
+ return std::make_unique<std::string>(*shared);
+ },
+ common::Unretained(queue), shared));
+
+ // Dequeue the string
+ queue->RegisterDequeue(dequeue_handler_, common::Bind(
+ [](Queue<std::string>* queue, std::string valid) {
+ queue->UnregisterDequeue();
+ auto answer = *queue->TryDequeue();
+ ASSERT_EQ(answer, valid);
+ },
+ common::Unretained(queue), valid));
+
+ // Wait for both handlers to finish and delete the Queue
+ std::promise<void> promise;
+ auto future = promise.get_future();
+
+ enqueue_handler_->Post(common::BindOnce(
+ [](os::Handler* dequeue_handler, Queue<std::string>* queue, std::promise<void>* promise) {
+ dequeue_handler->Post(common::BindOnce(
+ [](Queue<std::string>* queue, std::promise<void>* promise) {
+ delete queue;
+ promise->set_value();
+ },
+ common::Unretained(queue), common::Unretained(promise)));
+ },
+ common::Unretained(dequeue_handler_), common::Unretained(queue), common::Unretained(&promise)));
+ future.wait();
+}
+
+// Create all threads for death tests in the function that dies
+class QueueDeathTest : public ::testing::Test {
+ public:
+ void RegisterEnqueueAndDelete() {
+ Thread* enqueue_thread = new Thread("enqueue_thread", Thread::Priority::NORMAL);
+ Handler* enqueue_handler = new Handler(enqueue_thread);
+ Queue<std::string>* queue = new Queue<std::string>(kQueueSizeOne);
+ queue->RegisterEnqueue(enqueue_handler,
+ common::Bind([]() { return std::make_unique<std::string>("A string to fill the queue"); }));
+ delete queue;
+ }
+
+ void RegisterDequeueAndDelete() {
+ Thread* dequeue_thread = new Thread("dequeue_thread", Thread::Priority::NORMAL);
+ Handler* dequeue_handler = new Handler(dequeue_thread);
+ Queue<std::string>* queue = new Queue<std::string>(kQueueSizeOne);
+ queue->RegisterDequeue(dequeue_handler, common::Bind([](Queue<std::string>* queue) { queue->TryDequeue(); },
+ common::Unretained(queue)));
+ delete queue;
+ }
+};
+
+TEST_F(QueueDeathTest, die_if_enqueue_not_unregistered) {
+ EXPECT_DEATH(RegisterEnqueueAndDelete(), "nqueue");
+}
+
+TEST_F(QueueDeathTest, die_if_dequeue_not_unregistered) {
+ EXPECT_DEATH(RegisterDequeueAndDelete(), "equeue");
+}
+
+class MockIQueueEnqueue : public IQueueEnqueue<int> {
+ public:
+ void RegisterEnqueue(Handler* handler, EnqueueCallback callback) override {
+ EXPECT_FALSE(registered_);
+ registered_ = true;
+ handler->Post(common::BindOnce(&MockIQueueEnqueue::handle_register_enqueue, common::Unretained(this), callback));
+ }
+
+ void handle_register_enqueue(EnqueueCallback callback) {
+ if (dont_handle_register_enqueue_) {
+ return;
+ }
+ while (registered_) {
+ std::unique_ptr<int> front = callback.Run();
+ queue_.push(*front);
+ }
+ }
+
+ void UnregisterEnqueue() override {
+ EXPECT_TRUE(registered_);
+ registered_ = false;
+ }
+
+ bool dont_handle_register_enqueue_ = false;
+ bool registered_ = false;
+ std::queue<int> queue_;
+};
+
+class EnqueueBufferTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ thread_ = new Thread("test_thread", Thread::Priority::NORMAL);
+ handler_ = new Handler(thread_);
+ }
+
+ void TearDown() override {
+ handler_->Clear();
+ delete handler_;
+ delete thread_;
+ }
+
+ void SynchronizeHandler() {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ handler_->Post(common::BindOnce([](std::promise<void> promise) { promise.set_value(); }, std::move(promise)));
+ future.wait();
+ }
+
+ MockIQueueEnqueue enqueue_;
+ EnqueueBuffer<int> enqueue_buffer_{&enqueue_};
+ Thread* thread_;
+ Handler* handler_;
+};
+
+TEST_F(EnqueueBufferTest, enqueue) {
+ int num_items = 10;
+ for (int i = 0; i < num_items; i++) {
+ enqueue_buffer_.Enqueue(std::make_unique<int>(i), handler_);
+ }
+ SynchronizeHandler();
+ for (int i = 0; i < num_items; i++) {
+ ASSERT_EQ(enqueue_.queue_.front(), i);
+ enqueue_.queue_.pop();
+ }
+ ASSERT_FALSE(enqueue_.registered_);
+}
+
+TEST_F(EnqueueBufferTest, clear) {
+ enqueue_.dont_handle_register_enqueue_ = true;
+ int num_items = 10;
+ for (int i = 0; i < num_items; i++) {
+ enqueue_buffer_.Enqueue(std::make_unique<int>(i), handler_);
+ }
+ ASSERT_TRUE(enqueue_.registered_);
+ enqueue_buffer_.Clear();
+ ASSERT_FALSE(enqueue_.registered_);
+}
+
+} // namespace
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/linux_generic/reactive_semaphore.cc b/gd/os/linux_generic/reactive_semaphore.cc
new file mode 100644
index 0000000..df0050a
--- /dev/null
+++ b/gd/os/linux_generic/reactive_semaphore.cc
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019 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 "reactive_semaphore.h"
+
+#include <error.h>
+#include <sys/eventfd.h>
+#include <unistd.h>
+#include <functional>
+
+#include "os/linux_generic/linux.h"
+#include "os/log.h"
+
+namespace bluetooth {
+namespace os {
+
+ReactiveSemaphore::ReactiveSemaphore(unsigned int value) : fd_(eventfd(value, EFD_SEMAPHORE | EFD_NONBLOCK)) {
+ ASSERT(fd_ != -1);
+}
+
+ReactiveSemaphore::~ReactiveSemaphore() {
+ int close_status;
+ RUN_NO_INTR(close_status = close(fd_));
+ ASSERT_LOG(close_status != -1, "close failed: %s", strerror(errno));
+}
+
+void ReactiveSemaphore::Decrease() {
+ uint64_t val = 0;
+ auto read_result = eventfd_read(fd_, &val);
+ ASSERT_LOG(read_result != -1, "decrease failed: %s", strerror(errno));
+}
+
+void ReactiveSemaphore::Increase() {
+ uint64_t val = 1;
+ auto write_result = eventfd_write(fd_, val);
+ ASSERT_LOG(write_result != -1, "increase failed: %s", strerror(errno));
+}
+
+int ReactiveSemaphore::GetFd() {
+ return fd_;
+}
+
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/linux_generic/reactive_semaphore.h b/gd/os/linux_generic/reactive_semaphore.h
new file mode 100644
index 0000000..718666c
--- /dev/null
+++ b/gd/os/linux_generic/reactive_semaphore.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "os/utils.h"
+
+namespace bluetooth {
+namespace os {
+
+// A event_fd work in non-blocking and Semaphore mode
+class ReactiveSemaphore {
+ public:
+ // Creates a new ReactiveSemaphore with an initial value of |value|.
+ explicit ReactiveSemaphore(unsigned int value);
+ ~ReactiveSemaphore();
+ // Decrements the value of |fd_|, this will cause a crash if |fd_| unreadable.
+ void Decrease();
+ // Increase the value of |fd_|, this will cause a crash if |fd_| unwritable.
+ void Increase();
+ int GetFd();
+
+ DISALLOW_COPY_AND_ASSIGN(ReactiveSemaphore);
+
+ private:
+ int fd_;
+};
+
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/linux_generic/reactor.cc b/gd/os/linux_generic/reactor.cc
index dfc6757..220d3a9 100644
--- a/gd/os/linux_generic/reactor.cc
+++ b/gd/os/linux_generic/reactor.cc
@@ -39,22 +39,21 @@
class Reactor::Reactable {
public:
Reactable(int fd, Closure on_read_ready, Closure on_write_ready)
- : fd_(fd),
- on_read_ready_(std::move(on_read_ready)),
- on_write_ready_(std::move(on_write_ready)),
- is_executing_(false) {}
+ : fd_(fd), on_read_ready_(std::move(on_read_ready)), on_write_ready_(std::move(on_write_ready)),
+ is_executing_(false), removed_(false) {}
const int fd_;
Closure on_read_ready_;
Closure on_write_ready_;
bool is_executing_;
- std::recursive_mutex lock_;
+ bool removed_;
+ std::mutex mutex_;
+ std::unique_ptr<std::promise<void>> finished_promise_;
};
Reactor::Reactor()
: epoll_fd_(0),
control_fd_(0),
- is_running_(false),
- reactable_removed_(false) {
+ is_running_(false) {
RUN_NO_INTR(epoll_fd_ = epoll_create1(EPOLL_CLOEXEC));
ASSERT_LOG(epoll_fd_ != -1, "could not create epoll fd: %s", strerror(errno));
@@ -80,11 +79,14 @@
}
void Reactor::Run() {
- bool previously_running = is_running_.exchange(true);
- ASSERT(!previously_running);
+ bool already_running = is_running_.exchange(true);
+ ASSERT(!already_running);
for (;;) {
- invalidation_list_.clear();
+ {
+ std::unique_lock<std::mutex> lock(mutex_);
+ invalidation_list_.clear();
+ }
epoll_event events[kEpollMaxEvents];
int count;
RUN_NO_INTR(count = epoll_wait(epoll_fd_, events, kEpollMaxEvents, -1));
@@ -102,26 +104,29 @@
return;
}
auto* reactable = static_cast<Reactor::Reactable*>(event.data.ptr);
- {
- std::unique_lock<std::mutex> lock(mutex_);
- // See if this reactable has been removed in the meantime.
- if (std::find(invalidation_list_.begin(), invalidation_list_.end(), reactable) != invalidation_list_.end()) {
- continue;
- }
+ std::unique_lock<std::mutex> lock(mutex_);
+ // See if this reactable has been removed in the meantime.
+ if (std::find(invalidation_list_.begin(), invalidation_list_.end(), reactable) != invalidation_list_.end()) {
+ continue;
+ }
- std::lock_guard<std::recursive_mutex> reactable_lock(reactable->lock_);
+ {
+ std::lock_guard<std::mutex> reactable_lock(reactable->mutex_);
lock.unlock();
- reactable_removed_ = false;
reactable->is_executing_ = true;
- if (event.events & (EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR) && reactable->on_read_ready_ != nullptr) {
- reactable->on_read_ready_();
- }
- if (!reactable_removed_ && event.events & EPOLLOUT && reactable->on_write_ready_ != nullptr) {
- reactable->on_write_ready_();
- }
+ }
+ if (event.events & (EPOLLIN | EPOLLHUP | EPOLLRDHUP | EPOLLERR) && !reactable->on_read_ready_.is_null()) {
+ reactable->on_read_ready_.Run();
+ }
+ if (event.events & EPOLLOUT && !reactable->on_write_ready_.is_null()) {
+ reactable->on_write_ready_.Run();
+ }
+ {
+ std::lock_guard<std::mutex> reactable_lock(reactable->mutex_);
reactable->is_executing_ = false;
}
- if (reactable_removed_) {
+ if (reactable->removed_) {
+ reactable->finished_promise_->set_value();
delete reactable;
}
}
@@ -133,25 +138,25 @@
LOG_WARN("not running, will stop once it's started");
}
auto control = eventfd_write(control_fd_, 1);
- ASSERT(control != -1)
+ ASSERT(control != -1);
}
Reactor::Reactable* Reactor::Register(int fd, Closure on_read_ready, Closure on_write_ready) {
uint32_t poll_event_type = 0;
- if (on_read_ready != nullptr) {
+ if (!on_read_ready.is_null()) {
poll_event_type |= (EPOLLIN | EPOLLRDHUP);
}
- if (on_write_ready != nullptr) {
+ if (!on_write_ready.is_null()) {
poll_event_type |= EPOLLOUT;
}
auto* reactable = new Reactable(fd, on_read_ready, on_write_ready);
epoll_event event = {
.events = poll_event_type,
- {.ptr = reactable}
+ .data = {.ptr = reactable},
};
int register_fd;
RUN_NO_INTR(register_fd = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &event));
- ASSERT(register_fd != -1)
+ ASSERT(register_fd != -1);
return reactable;
}
@@ -161,45 +166,58 @@
std::lock_guard<std::mutex> lock(mutex_);
invalidation_list_.push_back(reactable);
}
+ bool delaying_delete_until_callback_finished = false;
{
int result;
- std::lock_guard<std::recursive_mutex> reactable_lock(reactable->lock_);
+ std::lock_guard<std::mutex> reactable_lock(reactable->mutex_);
RUN_NO_INTR(result = epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, reactable->fd_, nullptr));
if (result == -1 && errno == ENOENT) {
LOG_INFO("reactable is invalid or unregistered");
} else {
ASSERT(result != -1);
}
- // If we are unregistering during the callback event from this reactable, we delete it after the callback is executed.
- // reactable->is_executing_ is protected by reactable->lock_, so it's thread safe.
+
+ // If we are unregistering during the callback event from this reactable, we delete it after the callback is
+ // executed. reactable->is_executing_ is protected by reactable->mutex_, so it's thread safe.
if (reactable->is_executing_) {
- reactable_removed_ = true;
+ reactable->removed_ = true;
+ reactable->finished_promise_ = std::make_unique<std::promise<void>>();
+ executing_reactable_finished_ = std::make_unique<std::future<void>>(reactable->finished_promise_->get_future());
+ delaying_delete_until_callback_finished = true;
}
}
// If we are unregistering outside of the callback event from this reactable, we delete it now
- if (!reactable_removed_) {
+ if (!delaying_delete_until_callback_finished) {
delete reactable;
}
}
+bool Reactor::WaitForUnregisteredReactable(std::chrono::milliseconds timeout) {
+ if (executing_reactable_finished_ == nullptr) {
+ return true;
+ }
+ auto stop_status = executing_reactable_finished_->wait_for(timeout);
+ return stop_status == std::future_status::ready;
+}
+
void Reactor::ModifyRegistration(Reactor::Reactable* reactable, Closure on_read_ready, Closure on_write_ready) {
ASSERT(reactable != nullptr);
uint32_t poll_event_type = 0;
- if (on_read_ready != nullptr) {
+ if (!on_read_ready.is_null()) {
poll_event_type |= (EPOLLIN | EPOLLRDHUP);
}
- if (on_write_ready != nullptr) {
+ if (!on_write_ready.is_null()) {
poll_event_type |= EPOLLOUT;
}
{
- std::lock_guard<std::recursive_mutex> reactable_lock(reactable->lock_);
+ std::lock_guard<std::mutex> reactable_lock(reactable->mutex_);
reactable->on_read_ready_ = std::move(on_read_ready);
reactable->on_write_ready_ = std::move(on_write_ready);
}
epoll_event event = {
.events = poll_event_type,
- {.ptr = reactable}
+ .data = {.ptr = reactable},
};
int modify_fd;
RUN_NO_INTR(modify_fd = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, reactable->fd_, &event));
diff --git a/gd/os/linux_generic/reactor_unittest.cc b/gd/os/linux_generic/reactor_unittest.cc
index 7fda234..b9cd07d 100644
--- a/gd/os/linux_generic/reactor_unittest.cc
+++ b/gd/os/linux_generic/reactor_unittest.cc
@@ -21,7 +21,10 @@
#include <future>
#include <thread>
+#include "common/bind.h"
+#include "common/callback.h"
#include "gtest/gtest.h"
+#include "os/log.h"
namespace bluetooth {
namespace os {
@@ -29,6 +32,8 @@
constexpr int kReadReadyValue = 100;
+using common::Bind;
+
std::promise<int>* g_promise;
class ReactorTest : public ::testing::Test {
@@ -51,7 +56,7 @@
class SampleReactable {
public:
SampleReactable() : fd_(eventfd(0, EFD_NONBLOCK)) {
- EXPECT_NE(fd_, 0);
+ EXPECT_NE(fd_, -1);
}
~SampleReactable() {
@@ -74,11 +79,11 @@
kSampleOutputValue,
};
FakeReactable() : fd_(eventfd(0, 0)), reactor_(nullptr) {
- EXPECT_NE(fd_, 0);
+ EXPECT_NE(fd_, -1);
}
FakeReactable(Reactor* reactor) : fd_(eventfd(0, 0)), reactor_(reactor) {
- EXPECT_NE(fd_, 0);
+ EXPECT_NE(fd_, -1);
}
~FakeReactable() {
@@ -86,15 +91,18 @@
}
void OnReadReady() {
+ LOG_INFO();
uint64_t value = 0;
auto read_result = eventfd_read(fd_, &value);
+ LOG_INFO("value = %d", (int)value);
EXPECT_EQ(read_result, 0);
if (value == kSetPromise && g_promise != nullptr) {
g_promise->set_value(kReadReadyValue);
}
if (value == kRegisterSampleReactable) {
- reactable_ = reactor_->Register(sample_reactable_.fd_, [this] { this->sample_reactable_.OnReadReady(); },
- [this] { this->sample_reactable_.OnWriteReady(); });
+ reactable_ =
+ reactor_->Register(sample_reactable_.fd_, Bind(&FakeReactable::OnReadReady, common::Unretained(this)),
+ Bind(&FakeReactable::OnWriteReadyNoOp, common::Unretained(this)));
g_promise->set_value(kReadReadyValue);
}
if (value == kUnregisterSampleReactable) {
@@ -109,6 +117,16 @@
EXPECT_EQ(write_result, 0);
}
+ void OnWriteReadyNoOp() {}
+
+ void UnregisterInCallback() {
+ uint64_t value = 0;
+ auto read_result = eventfd_read(fd_, &value);
+ EXPECT_EQ(read_result, 0);
+ g_promise->set_value(kReadReadyValue);
+ reactor_->Unregister(reactable_);
+ }
+
SampleReactable sample_reactable_;
Reactor::Reactable* reactable_ = nullptr;
int fd_;
@@ -118,6 +136,33 @@
uint64_t output_data_ = kSampleOutputValue;
};
+class FakeRunningReactable {
+ public:
+ FakeRunningReactable() : fd_(eventfd(0, 0)) {
+ EXPECT_NE(fd_, -1);
+ }
+
+ ~FakeRunningReactable() {
+ close(fd_);
+ }
+
+ void OnReadReady() {
+ uint64_t value = 0;
+ auto read_result = eventfd_read(fd_, &value);
+ ASSERT_EQ(read_result, 0);
+ started.set_value();
+ can_finish.get_future().wait();
+ finished.set_value();
+ }
+
+ Reactor::Reactable* reactable_ = nullptr;
+ int fd_;
+
+ std::promise<void> started;
+ std::promise<void> can_finish;
+ std::promise<void> finished;
+};
+
TEST_F(ReactorTest, start_and_stop) {
auto reactor_thread = std::thread(&Reactor::Run, reactor_);
reactor_->Stop();
@@ -141,16 +186,16 @@
TEST_F(ReactorTest, cold_register_only) {
FakeReactable fake_reactable;
- auto* reactable =
- reactor_->Register(fake_reactable.fd_, std::bind(&FakeReactable::OnReadReady, &fake_reactable), nullptr);
+ auto* reactable = reactor_->Register(
+ fake_reactable.fd_, Bind(&FakeReactable::OnReadReady, common::Unretained(&fake_reactable)), Closure());
reactor_->Unregister(reactable);
}
TEST_F(ReactorTest, cold_register) {
FakeReactable fake_reactable;
- auto* reactable =
- reactor_->Register(fake_reactable.fd_, std::bind(&FakeReactable::OnReadReady, &fake_reactable), nullptr);
+ auto* reactable = reactor_->Register(
+ fake_reactable.fd_, Bind(&FakeReactable::OnReadReady, common::Unretained(&fake_reactable)), Closure());
auto reactor_thread = std::thread(&Reactor::Run, reactor_);
auto future = g_promise->get_future();
@@ -167,8 +212,8 @@
auto future = g_promise->get_future();
FakeReactable fake_reactable;
- auto* reactable =
- reactor_->Register(fake_reactable.fd_, std::bind(&FakeReactable::OnReadReady, &fake_reactable), nullptr);
+ auto* reactable = reactor_->Register(
+ fake_reactable.fd_, Bind(&FakeReactable::OnReadReady, common::Unretained(&fake_reactable)), Closure());
auto write_result = eventfd_write(fake_reactable.fd_, FakeReactable::kSetPromise);
EXPECT_EQ(write_result, 0);
EXPECT_EQ(future.get(), kReadReadyValue);
@@ -178,10 +223,62 @@
reactor_->Unregister(reactable);
}
+TEST_F(ReactorTest, unregister_from_different_thread_while_task_is_executing_) {
+ FakeRunningReactable fake_reactable;
+ auto* reactable = reactor_->Register(
+ fake_reactable.fd_, Bind(&FakeRunningReactable::OnReadReady, common::Unretained(&fake_reactable)), Closure());
+ auto reactor_thread = std::thread(&Reactor::Run, reactor_);
+ auto write_result = eventfd_write(fake_reactable.fd_, 1);
+ ASSERT_EQ(write_result, 0);
+ fake_reactable.started.get_future().wait();
+ reactor_->Unregister(reactable);
+ fake_reactable.can_finish.set_value();
+ fake_reactable.finished.get_future().wait();
+
+ reactor_->Stop();
+ reactor_thread.join();
+}
+
+TEST_F(ReactorTest, unregister_from_different_thread_while_task_is_executing_wait_fails) {
+ FakeRunningReactable fake_reactable;
+ auto* reactable = reactor_->Register(
+ fake_reactable.fd_, common::Bind(&FakeRunningReactable::OnReadReady, common::Unretained(&fake_reactable)),
+ common::Closure());
+ auto reactor_thread = std::thread(&Reactor::Run, reactor_);
+ auto write_result = eventfd_write(fake_reactable.fd_, 1);
+ ASSERT_EQ(write_result, 0);
+ fake_reactable.started.get_future().wait();
+ reactor_->Unregister(reactable);
+ ASSERT_FALSE(reactor_->WaitForUnregisteredReactable(std::chrono::milliseconds(1)));
+ fake_reactable.can_finish.set_value();
+ fake_reactable.finished.get_future().wait();
+
+ reactor_->Stop();
+ reactor_thread.join();
+}
+
+TEST_F(ReactorTest, unregister_from_different_thread_while_task_is_executing_wait_succeeds) {
+ FakeRunningReactable fake_reactable;
+ auto* reactable = reactor_->Register(
+ fake_reactable.fd_, common::Bind(&FakeRunningReactable::OnReadReady, common::Unretained(&fake_reactable)),
+ common::Closure());
+ auto reactor_thread = std::thread(&Reactor::Run, reactor_);
+ auto write_result = eventfd_write(fake_reactable.fd_, 1);
+ ASSERT_EQ(write_result, 0);
+ fake_reactable.started.get_future().wait();
+ reactor_->Unregister(reactable);
+ fake_reactable.can_finish.set_value();
+ fake_reactable.finished.get_future().wait();
+ ASSERT_TRUE(reactor_->WaitForUnregisteredReactable(std::chrono::milliseconds(1)));
+
+ reactor_->Stop();
+ reactor_thread.join();
+}
+
TEST_F(ReactorTest, hot_unregister_from_different_thread) {
FakeReactable fake_reactable;
- auto* reactable =
- reactor_->Register(fake_reactable.fd_, std::bind(&FakeReactable::OnReadReady, &fake_reactable), nullptr);
+ auto* reactable = reactor_->Register(
+ fake_reactable.fd_, Bind(&FakeReactable::OnReadReady, common::Unretained(&fake_reactable)), Closure());
auto reactor_thread = std::thread(&Reactor::Run, reactor_);
reactor_->Unregister(reactable);
auto future = g_promise->get_future();
@@ -200,11 +297,16 @@
auto future = g_promise->get_future();
FakeReactable fake_reactable(reactor_);
- auto* reactable =
- reactor_->Register(fake_reactable.fd_, std::bind(&FakeReactable::OnReadReady, &fake_reactable), nullptr);
+ auto* reactable = reactor_->Register(
+ fake_reactable.fd_, Bind(&FakeReactable::OnReadReady, common::Unretained(&fake_reactable)), Closure());
auto write_result = eventfd_write(fake_reactable.fd_, FakeReactable::kRegisterSampleReactable);
EXPECT_EQ(write_result, 0);
EXPECT_EQ(future.get(), kReadReadyValue);
+ delete g_promise;
+ g_promise = new std::promise<int>;
+ future = g_promise->get_future();
+ write_result = eventfd_write(fake_reactable.fd_, FakeReactable::kUnregisterSampleReactable);
+ EXPECT_EQ(write_result, 0);
reactor_->Stop();
reactor_thread.join();
@@ -216,23 +318,65 @@
auto future = g_promise->get_future();
FakeReactable fake_reactable(reactor_);
- auto* reactable =
- reactor_->Register(fake_reactable.fd_, std::bind(&FakeReactable::OnReadReady, &fake_reactable), nullptr);
+ auto* reactable = reactor_->Register(
+ fake_reactable.fd_, Bind(&FakeReactable::OnReadReady, common::Unretained(&fake_reactable)), Closure());
auto write_result = eventfd_write(fake_reactable.fd_, FakeReactable::kRegisterSampleReactable);
EXPECT_EQ(write_result, 0);
EXPECT_EQ(future.get(), kReadReadyValue);
+ LOG_INFO();
delete g_promise;
g_promise = new std::promise<int>;
future = g_promise->get_future();
write_result = eventfd_write(fake_reactable.fd_, FakeReactable::kUnregisterSampleReactable);
EXPECT_EQ(write_result, 0);
EXPECT_EQ(future.get(), kReadReadyValue);
+ LOG_INFO();
reactor_->Stop();
reactor_thread.join();
reactor_->Unregister(reactable);
}
+TEST_F(ReactorTest, hot_unregister_from_callback) {
+ auto reactor_thread = std::thread(&Reactor::Run, reactor_);
+
+ FakeReactable fake_reactable1(reactor_);
+ auto* reactable1 = reactor_->Register(
+ fake_reactable1.fd_, Bind(&FakeReactable::OnReadReady, common::Unretained(&fake_reactable1)), Closure());
+
+ FakeReactable fake_reactable2(reactor_);
+ auto* reactable2 = reactor_->Register(
+ fake_reactable2.fd_, Bind(&FakeReactable::UnregisterInCallback, common::Unretained(&fake_reactable2)), Closure());
+ fake_reactable2.reactable_ = reactable2;
+ auto write_result = eventfd_write(fake_reactable2.fd_, 1);
+ EXPECT_EQ(write_result, 0);
+ reactor_->Stop();
+ reactor_thread.join();
+
+ reactor_->Unregister(reactable1);
+}
+
+TEST_F(ReactorTest, hot_unregister_during_unregister_from_callback) {
+ auto reactor_thread = std::thread(&Reactor::Run, reactor_);
+ auto future = g_promise->get_future();
+
+ FakeReactable fake_reactable1(reactor_);
+ auto* reactable1 = reactor_->Register(
+ fake_reactable1.fd_, Bind(&FakeReactable::OnReadReady, common::Unretained(&fake_reactable1)), Closure());
+
+ FakeReactable fake_reactable2(reactor_);
+ auto* reactable2 = reactor_->Register(
+ fake_reactable2.fd_, Bind(&FakeReactable::UnregisterInCallback, common::Unretained(&fake_reactable2)), Closure());
+ fake_reactable2.reactable_ = reactable2;
+ auto write_result = eventfd_write(fake_reactable2.fd_, 1);
+ EXPECT_EQ(write_result, 0);
+ EXPECT_EQ(future.get(), kReadReadyValue);
+ reactor_->Unregister(reactable1);
+
+ reactor_->Stop();
+ reactor_thread.join();
+}
+
TEST_F(ReactorTest, start_and_stop_multi_times) {
auto reactor_thread = std::thread(&Reactor::Run, reactor_);
reactor_->Stop();
@@ -246,8 +390,8 @@
TEST_F(ReactorTest, on_write_ready) {
FakeReactable fake_reactable;
- auto* reactable =
- reactor_->Register(fake_reactable.fd_, nullptr, std::bind(&FakeReactable::OnWriteReady, &fake_reactable));
+ auto* reactable = reactor_->Register(fake_reactable.fd_, Closure(),
+ Bind(&FakeReactable::OnWriteReady, common::Unretained(&fake_reactable)));
auto reactor_thread = std::thread(&Reactor::Run, reactor_);
uint64_t value = 0;
auto read_result = eventfd_read(fake_reactable.fd_, &value);
@@ -262,9 +406,10 @@
TEST_F(ReactorTest, modify_registration) {
FakeReactable fake_reactable;
- auto* reactable =
- reactor_->Register(fake_reactable.fd_, std::bind(&FakeReactable::OnReadReady, &fake_reactable), nullptr);
- reactor_->ModifyRegistration(reactable, nullptr, std::bind(&FakeReactable::OnWriteReady, &fake_reactable));
+ auto* reactable = reactor_->Register(
+ fake_reactable.fd_, Bind(&FakeReactable::OnReadReady, common::Unretained(&fake_reactable)), Closure());
+ reactor_->ModifyRegistration(reactable, Closure(),
+ Bind(&FakeReactable::OnWriteReady, common::Unretained(&fake_reactable)));
auto reactor_thread = std::thread(&Reactor::Run, reactor_);
uint64_t value = 0;
auto read_result = eventfd_read(fake_reactable.fd_, &value);
@@ -273,6 +418,8 @@
reactor_->Stop();
reactor_thread.join();
+
+ reactor_->Unregister(reactable);
}
} // namespace
diff --git a/gd/os/linux_generic/repeating_alarm.cc b/gd/os/linux_generic/repeating_alarm.cc
index 3258400..79cda6d 100644
--- a/gd/os/linux_generic/repeating_alarm.cc
+++ b/gd/os/linux_generic/repeating_alarm.cc
@@ -20,6 +20,7 @@
#include <cstring>
#include <unistd.h>
+#include "common/bind.h"
#include "os/log.h"
#include "os/utils.h"
@@ -32,16 +33,15 @@
namespace bluetooth {
namespace os {
-RepeatingAlarm::RepeatingAlarm(Thread* thread)
- : thread_(thread),
- fd_(timerfd_create(ALARM_CLOCK, 0)) {
+RepeatingAlarm::RepeatingAlarm(Handler* handler) : handler_(handler), fd_(timerfd_create(ALARM_CLOCK, 0)) {
ASSERT(fd_ != -1);
- token_ = thread_->GetReactor()->Register(fd_, [this] { on_fire(); }, nullptr);
+ token_ = handler_->thread_->GetReactor()->Register(
+ fd_, common::Bind(&RepeatingAlarm::on_fire, common::Unretained(this)), common::Closure());
}
RepeatingAlarm::~RepeatingAlarm() {
- thread_->GetReactor()->Unregister(token_);
+ handler_->thread_->GetReactor()->Unregister(token_);
int close_status;
RUN_NO_INTR(close_status = close(fd_));
@@ -74,7 +74,7 @@
uint64_t times_invoked;
auto bytes_read = read(fd_, ×_invoked, sizeof(uint64_t));
lock.unlock();
- task();
+ task.Run();
ASSERT(bytes_read == static_cast<ssize_t>(sizeof(uint64_t)));
}
diff --git a/gd/os/linux_generic/repeating_alarm_unittest.cc b/gd/os/linux_generic/repeating_alarm_unittest.cc
index a017f66..d30bbd9 100644
--- a/gd/os/linux_generic/repeating_alarm_unittest.cc
+++ b/gd/os/linux_generic/repeating_alarm_unittest.cc
@@ -18,6 +18,7 @@
#include <future>
+#include "common/bind.h"
#include "gtest/gtest.h"
namespace bluetooth {
@@ -30,11 +31,14 @@
protected:
void SetUp() override {
thread_ = new Thread("test_thread", Thread::Priority::NORMAL);
- alarm_ = new RepeatingAlarm(thread_);
+ handler_ = new Handler(thread_);
+ alarm_ = new RepeatingAlarm(handler_);
}
void TearDown() override {
delete alarm_;
+ handler_->Clear();
+ delete handler_;
delete thread_;
}
@@ -43,26 +47,33 @@
auto future = promise.get_future();
auto start_time = std::chrono::steady_clock::now();
int counter = 0;
- alarm_->Schedule(
- [&counter, &promise, start_time, scheduled_tasks, task_length_ms, interval_between_tasks_ms]() {
- counter++;
- auto time_now = std::chrono::steady_clock::now();
- auto time_delta = time_now - start_time;
- if (counter == scheduled_tasks) {
- promise.set_value();
- }
- ASSERT_NEAR(time_delta.count(), interval_between_tasks_ms * 1000000 * counter, error_ms * 1000000);
- std::this_thread::sleep_for(std::chrono::milliseconds(task_length_ms));
- },
- std::chrono::milliseconds(interval_between_tasks_ms));
+ alarm_->Schedule(common::Bind(&RepeatingAlarmTest::verify_delayed_tasks, common::Unretained(this),
+ common::Unretained(&counter), start_time, scheduled_tasks,
+ common::Unretained(&promise), task_length_ms, interval_between_tasks_ms),
+ std::chrono::milliseconds(interval_between_tasks_ms));
future.get();
alarm_->Cancel();
}
+ void verify_delayed_tasks(int* counter, std::chrono::steady_clock::time_point start_time, int scheduled_tasks,
+ std::promise<void>* promise, int task_length_ms, int interval_between_tasks_ms) {
+ *counter = *counter + 1;
+ auto time_now = std::chrono::steady_clock::now();
+ auto time_delta = time_now - start_time;
+ if (*counter == scheduled_tasks) {
+ promise->set_value();
+ }
+ ASSERT_NEAR(time_delta.count(), interval_between_tasks_ms * 1000000 * *counter, error_ms * 1000000);
+ std::this_thread::sleep_for(std::chrono::milliseconds(task_length_ms));
+ }
+
RepeatingAlarm* alarm_;
+ Closure should_not_happen_ = common::Bind([] { ASSERT_TRUE(false); });
+
private:
Thread* thread_;
+ Handler* handler_;
};
TEST_F(RepeatingAlarmTest, cancel_while_not_armed) {
@@ -74,7 +85,8 @@
auto future = promise.get_future();
auto before = std::chrono::steady_clock::now();
int period_ms = 10;
- alarm_->Schedule([&promise]() { promise.set_value(); }, std::chrono::milliseconds(period_ms));
+ alarm_->Schedule(common::Bind(&std::promise<void>::set_value, common::Unretained(&promise)),
+ std::chrono::milliseconds(period_ms));
future.get();
alarm_->Cancel();
auto after = std::chrono::steady_clock::now();
@@ -83,27 +95,29 @@
}
TEST_F(RepeatingAlarmTest, cancel_alarm) {
- alarm_->Schedule([]() { ASSERT_TRUE(false); }, std::chrono::milliseconds(1));
+ alarm_->Schedule(should_not_happen_, std::chrono::milliseconds(1));
alarm_->Cancel();
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
TEST_F(RepeatingAlarmTest, cancel_alarm_from_callback) {
- alarm_->Schedule([this]() { this->alarm_->Cancel(); }, std::chrono::milliseconds(1));
+ alarm_->Schedule(common::Bind(&RepeatingAlarm::Cancel, common::Unretained(this->alarm_)),
+ std::chrono::milliseconds(1));
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
TEST_F(RepeatingAlarmTest, schedule_while_alarm_armed) {
- alarm_->Schedule([]() { ASSERT_TRUE(false); }, std::chrono::milliseconds(1));
+ alarm_->Schedule(should_not_happen_, std::chrono::milliseconds(1));
std::promise<void> promise;
auto future = promise.get_future();
- alarm_->Schedule([&promise]() { promise.set_value(); }, std::chrono::milliseconds(10));
+ alarm_->Schedule(common::Bind(&std::promise<void>::set_value, common::Unretained(&promise)),
+ std::chrono::milliseconds(10));
future.get();
alarm_->Cancel();
}
TEST_F(RepeatingAlarmTest, delete_while_alarm_armed) {
- alarm_->Schedule([]() { ASSERT_TRUE(false); }, std::chrono::milliseconds(1));
+ alarm_->Schedule(should_not_happen_, std::chrono::milliseconds(1));
delete alarm_;
alarm_ = nullptr;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
diff --git a/gd/os/linux_generic/thread_unittest.cc b/gd/os/linux_generic/thread_unittest.cc
index 1e16edc..f0b8f24 100644
--- a/gd/os/linux_generic/thread_unittest.cc
+++ b/gd/os/linux_generic/thread_unittest.cc
@@ -18,6 +18,7 @@
#include <sys/eventfd.h>
+#include "common/bind.h"
#include "gtest/gtest.h"
#include "os/reactor.h"
@@ -85,7 +86,8 @@
Reactor* reactor = thread->GetReactor();
SampleReactable sample_reactable(thread);
auto* reactable =
- reactor->Register(sample_reactable.fd_, std::bind(&SampleReactable::OnReadReady, &sample_reactable), nullptr);
+ reactor->Register(sample_reactable.fd_,
+ common::Bind(&SampleReactable::OnReadReady, common::Unretained(&sample_reactable)), Closure());
int fd = sample_reactable.fd_;
int write_result = eventfd_write(fd, kCheckIsSameThread);
EXPECT_EQ(write_result, 0);
diff --git a/gd/os/log.h b/gd/os/log.h
index 291b17b..3d8a89f 100644
--- a/gd/os/log.h
+++ b/gd/os/log.h
@@ -18,6 +18,8 @@
#pragma once
+#include <stdlib.h>
+
#ifndef LOG_TAG
#define LOG_TAG "bt"
#endif
@@ -26,11 +28,11 @@
#include <log/log.h>
-#define LOG_VERBOSE(fmt, args...) ALOGV("%s: " fmt, __PRETTY_FUNCTION__, ##args)
-#define LOG_DEBUG(fmt, args...) ALOGD("%s: " fmt, __PRETTY_FUNCTION__, ##args)
-#define LOG_INFO(fmt, args...) ALOGI("%s: " fmt, __PRETTY_FUNCTION__, ##args)
-#define LOG_WARN(fmt, args...) ALOGW("%s: " fmt, __PRETTY_FUNCTION__, ##args)
-#define LOG_ERROR(fmt, args...) ALOGE("%s: " fmt, __PRETTY_FUNCTION__, ##args)
+#define LOG_VERBOSE(fmt, args...) ALOGV("%s:%d %s: " fmt, __FILE__, __LINE__, __func__, ##args)
+#define LOG_DEBUG(fmt, args...) ALOGD("%s:%d %s: " fmt, __FILE__, __LINE__, __func__, ##args)
+#define LOG_INFO(fmt, args...) ALOGI("%s:%d %s: " fmt, __FILE__, __LINE__, __func__, ##args)
+#define LOG_WARN(fmt, args...) ALOGW("%s:%d %s: " fmt, __FILE__, __LINE__, __func__, ##args)
+#define LOG_ERROR(fmt, args...) ALOGE("%s:%d %s: " fmt, __FILE__, __LINE__, __func__, ##args)
#else
@@ -38,25 +40,31 @@
#include <stdio.h>
#define LOGWRAPPER(fmt, args...) \
- fprintf(stderr, "%s - %s: " fmt "\n", LOG_TAG, __PRETTY_FUNCTION__, ##args)
+ fprintf(stderr, "%s - %s:%d - %s: " fmt "\n", LOG_TAG, __FILE__, __LINE__, __func__, ##args)
#define LOG_VERBOSE(...) LOGWRAPPER(__VA_ARGS__)
#define LOG_DEBUG(...) LOGWRAPPER(__VA_ARGS__)
#define LOG_INFO(...) LOGWRAPPER(__VA_ARGS__)
#define LOG_WARN(...) LOGWRAPPER(__VA_ARGS__)
#define LOG_ERROR(...) LOGWRAPPER(__VA_ARGS__)
+#define LOG_ALWAYS_FATAL(...) \
+ do { \
+ LOGWRAPPER(__VA_ARGS__); \
+ abort(); \
+ } while (false)
#endif /* defined(OS_ANDROID) */
-#define ASSERT(condition) \
- if (!(condition)) { \
- LOG_ERROR("%s:%d assertion '" #condition "' failed", __FILE__, __LINE__); \
- abort(); \
- }
+#define ASSERT(condition) \
+ do { \
+ if (!(condition)) { \
+ LOG_ALWAYS_FATAL("assertion '" #condition "' failed"); \
+ } \
+ } while (false)
-#define ASSERT_LOG(condition, fmt, args...) \
- if (!(condition)) { \
- LOG_ERROR("%s:%d assertion '" #condition "' failed - " fmt, __FILE__, __LINE__, ##args); \
- abort(); \
- }
-
+#define ASSERT_LOG(condition, fmt, args...) \
+ do { \
+ if (!(condition)) { \
+ LOG_ALWAYS_FATAL("assertion '" #condition "' failed - " fmt, ##args); \
+ } \
+ } while (false)
diff --git a/gd/os/queue.h b/gd/os/queue.h
new file mode 100644
index 0000000..1d2af02
--- /dev/null
+++ b/gd/os/queue.h
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <unistd.h>
+#include <functional>
+#include <mutex>
+#include <queue>
+
+#include "common/bind.h"
+#include "common/callback.h"
+#include "os/handler.h"
+#ifdef OS_LINUX_GENERIC
+#include "os/linux_generic/reactive_semaphore.h"
+#endif
+#include "os/log.h"
+
+namespace bluetooth {
+namespace os {
+
+// See documentation for |Queue|
+template <typename T>
+class IQueueEnqueue {
+ public:
+ using EnqueueCallback = Callback<std::unique_ptr<T>()>;
+ virtual ~IQueueEnqueue() = default;
+ virtual void RegisterEnqueue(Handler* handler, EnqueueCallback callback) = 0;
+ virtual void UnregisterEnqueue() = 0;
+};
+
+// See documentation for |Queue|
+template <typename T>
+class IQueueDequeue {
+ public:
+ using DequeueCallback = Callback<void()>;
+ virtual ~IQueueDequeue() = default;
+ virtual void RegisterDequeue(Handler* handler, DequeueCallback callback) = 0;
+ virtual void UnregisterDequeue() = 0;
+ virtual std::unique_ptr<T> TryDequeue() = 0;
+};
+
+template <typename T>
+class Queue : public IQueueEnqueue<T>, public IQueueDequeue<T> {
+ public:
+ // A function moving data from enqueue end buffer to queue, it will be continually be invoked until queue
+ // is full. Enqueue end should make sure buffer isn't empty and UnregisterEnqueue when buffer become empty.
+ using EnqueueCallback = Callback<std::unique_ptr<T>()>;
+ // A function moving data form queue to dequeue end buffer, it will be continually be invoked until queue
+ // is empty. TryDequeue should be use in this function to get data from queue.
+ using DequeueCallback = Callback<void()>;
+ // Create a queue with |capacity| is the maximum number of messages a queue can contain
+ explicit Queue(size_t capacity);
+ ~Queue();
+ // Register |callback| that will be called on |handler| when the queue is able to enqueue one piece of data.
+ // This will cause a crash if handler or callback has already been registered before.
+ void RegisterEnqueue(Handler* handler, EnqueueCallback callback) override;
+ // Unregister current EnqueueCallback from this queue, this will cause a crash if not registered yet.
+ void UnregisterEnqueue() override;
+ // Register |callback| that will be called on |handler| when the queue has at least one piece of data ready
+ // for dequeue. This will cause a crash if handler or callback has already been registered before.
+ void RegisterDequeue(Handler* handler, DequeueCallback callback) override;
+ // Unregister current DequeueCallback from this queue, this will cause a crash if not registered yet.
+ void UnregisterDequeue() override;
+
+ // Try to dequeue an item from this queue. Return nullptr when there is nothing in the queue.
+ std::unique_ptr<T> TryDequeue() override;
+
+ private:
+ void EnqueueCallbackInternal(EnqueueCallback callback);
+ // An internal queue that holds at most |capacity| pieces of data
+ std::queue<std::unique_ptr<T>> queue_;
+ // A mutex that guards data in this queue
+ std::mutex mutex_;
+
+ class QueueEndpoint {
+ public:
+#ifdef OS_LINUX_GENERIC
+ explicit QueueEndpoint(unsigned int initial_value)
+ : reactive_semaphore_(initial_value), handler_(nullptr), reactable_(nullptr) {}
+ ReactiveSemaphore reactive_semaphore_;
+#endif
+ Handler* handler_;
+ Reactor::Reactable* reactable_;
+ };
+
+ QueueEndpoint enqueue_;
+ QueueEndpoint dequeue_;
+};
+
+template <typename T>
+class EnqueueBuffer {
+ public:
+ EnqueueBuffer(IQueueEnqueue<T>* queue) : queue_(queue) {}
+
+ void Enqueue(std::unique_ptr<T> t, os::Handler* handler) {
+ std::lock_guard<std::mutex> lock(mutex_);
+ buffer_.push(std::move(t));
+ if (buffer_.size() == 1) {
+ queue_->RegisterEnqueue(handler, common::Bind(&EnqueueBuffer<T>::enqueue_callback, common::Unretained(this)));
+ }
+ }
+
+ void Clear() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ if (!buffer_.empty()) {
+ queue_->UnregisterEnqueue();
+ std::queue<std::unique_ptr<T>> empty;
+ std::swap(buffer_, empty);
+ }
+ }
+
+ private:
+ std::unique_ptr<T> enqueue_callback() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ std::unique_ptr<T> enqueued_t = std::move(buffer_.front());
+ buffer_.pop();
+ if (buffer_.empty()) {
+ queue_->UnregisterEnqueue();
+ }
+ return enqueued_t;
+ }
+
+ mutable std::mutex mutex_;
+ IQueueEnqueue<T>* queue_;
+ std::queue<std::unique_ptr<T>> buffer_;
+};
+
+#ifdef OS_LINUX_GENERIC
+#include "os/linux_generic/queue.tpp"
+#endif
+
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/queue_benchmark.cc b/gd/os/queue_benchmark.cc
new file mode 100644
index 0000000..0c90fe9
--- /dev/null
+++ b/gd/os/queue_benchmark.cc
@@ -0,0 +1,207 @@
+/*
+ * Copyright 2019 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 "benchmark/benchmark.h"
+
+#include <future>
+
+#include "os/handler.h"
+#include "os/queue.h"
+#include "os/thread.h"
+
+using ::benchmark::State;
+
+namespace bluetooth {
+namespace os {
+
+class BM_QueuePerformance : public ::benchmark::Fixture {
+ protected:
+ void SetUp(State& st) override {
+ ::benchmark::Fixture::SetUp(st);
+ enqueue_thread_ = new Thread("enqueue_thread", Thread::Priority::NORMAL);
+ enqueue_handler_ = new Handler(enqueue_thread_);
+ dequeue_thread_ = new Thread("dequeue_thread", Thread::Priority::NORMAL);
+ dequeue_handler_ = new Handler(dequeue_thread_);
+ }
+
+ void TearDown(State& st) override {
+ delete enqueue_handler_;
+ delete enqueue_thread_;
+ delete dequeue_handler_;
+ delete dequeue_thread_;
+ enqueue_handler_ = nullptr;
+ enqueue_thread_ = nullptr;
+ dequeue_handler_ = nullptr;
+ dequeue_thread_ = nullptr;
+ benchmark::Fixture::TearDown(st);
+ }
+
+ Thread* enqueue_thread_;
+ Handler* enqueue_handler_;
+ Thread* dequeue_thread_;
+ Handler* dequeue_handler_;
+};
+
+class TestEnqueueEnd {
+ public:
+ explicit TestEnqueueEnd(int64_t count, Queue<std::string>* queue, Handler* handler, std::promise<void>* promise)
+ : count_(count), handler_(handler), queue_(queue), promise_(promise) {}
+
+ void RegisterEnqueue() {
+ handler_->Post(common::BindOnce(&TestEnqueueEnd::handle_register_enqueue, common::Unretained(this)));
+ }
+
+ void push(std::string data) {
+ {
+ std::lock_guard<std::mutex> lock(mutex_);
+ buffer_.push(std::move(data));
+ }
+ if (buffer_.size() == 1) {
+ RegisterEnqueue();
+ }
+ }
+
+ std::unique_ptr<std::string> EnqueueCallbackForTest() {
+ std::lock_guard<std::mutex> lock(mutex_);
+ std::unique_ptr<std::string> data = std::make_unique<std::string>(std::move(buffer_.front()));
+ buffer_.pop();
+
+ if (buffer_.empty()) {
+ queue_->UnregisterEnqueue();
+ }
+
+ count_--;
+ if (count_ == 0) {
+ promise_->set_value();
+ }
+
+ return data;
+ }
+
+ std::queue<std::string> buffer_;
+ int64_t count_;
+
+ private:
+ Handler* handler_;
+ Queue<std::string>* queue_;
+ std::promise<void>* promise_;
+ std::mutex mutex_;
+
+ void handle_register_enqueue() {
+ queue_->RegisterEnqueue(handler_, common::Bind(&TestEnqueueEnd::EnqueueCallbackForTest, common::Unretained(this)));
+ }
+};
+
+class TestDequeueEnd {
+ public:
+ explicit TestDequeueEnd(int64_t count, Queue<std::string>* queue, Handler* handler, std::promise<void>* promise)
+ : count_(count), handler_(handler), queue_(queue), promise_(promise) {}
+
+ void RegisterDequeue() {
+ handler_->Post(common::BindOnce(&TestDequeueEnd::handle_register_dequeue, common::Unretained(this)));
+ }
+
+ void DequeueCallbackForTest() {
+ std::string data = *(queue_->TryDequeue());
+ buffer_.push(data);
+
+ count_--;
+ if (count_ == 0) {
+ queue_->UnregisterDequeue();
+ promise_->set_value();
+ }
+ }
+
+ std::queue<std::string> buffer_;
+ int64_t count_;
+
+ private:
+ Handler* handler_;
+ Queue<std::string>* queue_;
+ std::promise<void>* promise_;
+
+ void handle_register_dequeue() {
+ queue_->RegisterDequeue(handler_, common::Bind(&TestDequeueEnd::DequeueCallbackForTest, common::Unretained(this)));
+ }
+};
+
+BENCHMARK_DEFINE_F(BM_QueuePerformance, send_packet_vary_by_packet_num)(State& state) {
+ for (auto _ : state) {
+ int64_t num_data_to_send_ = state.range(0);
+ Queue<std::string> queue(num_data_to_send_);
+
+ // register dequeue
+ std::promise<void> dequeue_promise;
+ auto dequeue_future = dequeue_promise.get_future();
+ TestDequeueEnd test_dequeue_end(num_data_to_send_, &queue, enqueue_handler_, &dequeue_promise);
+ test_dequeue_end.RegisterDequeue();
+
+ // Push data to enqueue end buffer and register enqueue
+ std::promise<void> enqueue_promise;
+ TestEnqueueEnd test_enqueue_end(num_data_to_send_, &queue, enqueue_handler_, &enqueue_promise);
+ for (int i = 0; i < num_data_to_send_; i++) {
+ std::string data = std::to_string(1);
+ test_enqueue_end.push(std::move(data));
+ }
+ dequeue_future.wait();
+ }
+
+ state.SetBytesProcessed(static_cast<int_fast64_t>(state.iterations()) * state.range(0));
+};
+
+BENCHMARK_REGISTER_F(BM_QueuePerformance, send_packet_vary_by_packet_num)
+ ->Arg(10)
+ ->Arg(100)
+ ->Arg(1000)
+ ->Arg(10000)
+ ->Arg(100000)
+ ->Iterations(100)
+ ->UseRealTime();
+
+BENCHMARK_DEFINE_F(BM_QueuePerformance, send_10000_packet_vary_by_packet_size)(State& state) {
+ for (auto _ : state) {
+ int64_t num_data_to_send_ = 10000;
+ int64_t packet_size = state.range(0);
+ Queue<std::string> queue(num_data_to_send_);
+
+ // register dequeue
+ std::promise<void> dequeue_promise;
+ auto dequeue_future = dequeue_promise.get_future();
+ TestDequeueEnd test_dequeue_end(num_data_to_send_, &queue, enqueue_handler_, &dequeue_promise);
+ test_dequeue_end.RegisterDequeue();
+
+ // Push data to enqueue end buffer and register enqueue
+ std::promise<void> enqueue_promise;
+ TestEnqueueEnd test_enqueue_end(num_data_to_send_, &queue, enqueue_handler_, &enqueue_promise);
+ for (int i = 0; i < num_data_to_send_; i++) {
+ std::string data = std::string(packet_size, 'x');
+ test_enqueue_end.push(std::move(data));
+ }
+ dequeue_future.wait();
+ }
+
+ state.SetBytesProcessed(static_cast<int_fast64_t>(state.iterations()) * state.range(0) * 10000);
+};
+
+BENCHMARK_REGISTER_F(BM_QueuePerformance, send_10000_packet_vary_by_packet_size)
+ ->Arg(10)
+ ->Arg(100)
+ ->Arg(1000)
+ ->Iterations(100)
+ ->UseRealTime();
+
+} // namespace os
+} // namespace bluetooth
diff --git a/gd/os/reactor.h b/gd/os/reactor.h
index a0de131..7e8476b 100644
--- a/gd/os/reactor.h
+++ b/gd/os/reactor.h
@@ -19,17 +19,21 @@
#include <sys/epoll.h>
#include <atomic>
#include <functional>
+#include <future>
#include <list>
#include <mutex>
#include <thread>
+#include "common/callback.h"
#include "os/utils.h"
namespace bluetooth {
namespace os {
-// Format of closure to be used in the entire stack
-using Closure = std::function<void()>;
+using common::Callback;
+using common::Closure;
+using common::OnceCallback;
+using common::OnceClosure;
// A simple implementation of reactor-style looper.
// When a reactor is running, the main loop is polling and blocked until at least one registered reactable is ready to
@@ -62,6 +66,9 @@
// Unregister a reactable from this reactor
void Unregister(Reactable* reactable);
+ // Wait for up to timeout milliseconds, and return true if the reactable finished executing.
+ bool WaitForUnregisteredReactable(std::chrono::milliseconds timeout);
+
// Modify the registration for a reactable with given reactable
void ModifyRegistration(Reactable* reactable, Closure on_read_ready, Closure on_write_ready);
@@ -71,7 +78,7 @@
int control_fd_;
std::atomic<bool> is_running_;
std::list<Reactable*> invalidation_list_;
- bool reactable_removed_;
+ std::unique_ptr<std::future<void>> executing_reactable_finished_;
};
} // namespace os
diff --git a/gd/os/repeating_alarm.h b/gd/os/repeating_alarm.h
index 776781a..cd91344 100644
--- a/gd/os/repeating_alarm.h
+++ b/gd/os/repeating_alarm.h
@@ -20,6 +20,8 @@
#include <memory>
#include <mutex>
+#include "common/callback.h"
+#include "os/handler.h"
#include "os/thread.h"
#include "os/utils.h"
@@ -31,8 +33,8 @@
// itself from the thread.
class RepeatingAlarm {
public:
- // Create and register a repeating alarm on given thread
- explicit RepeatingAlarm(Thread* thread);
+ // Create and register a repeating alarm on a given handler
+ explicit RepeatingAlarm(Handler* handler);
// Unregister this alarm from the thread and release resource
~RepeatingAlarm();
@@ -47,7 +49,7 @@
private:
Closure task_;
- Thread* thread_;
+ Handler* handler_;
int fd_ = 0;
Reactor::Reactable* token_;
mutable std::mutex mutex_;
diff --git a/gd/os/thread_benchmark.cc b/gd/os/thread_benchmark.cc
index dc22b9d..8d62889c 100644
--- a/gd/os/thread_benchmark.cc
+++ b/gd/os/thread_benchmark.cc
@@ -20,10 +20,12 @@
#include "benchmark/benchmark.h"
+#include "common/bind.h"
#include "os/handler.h"
#include "os/thread.h"
using ::benchmark::State;
+using ::bluetooth::common::BindOnce;
using ::bluetooth::os::Handler;
using ::bluetooth::os::Thread;
@@ -79,7 +81,8 @@
counter_promise_ = std::promise<void>();
std::future<void> counter_future = counter_promise_.get_future();
for (int i = 0; i < num_messages_to_send_; i++) {
- handler_->Post([this]() { callback_batch(); });
+ handler_->Post(BindOnce(&BM_ReactorThread_batch_enque_dequeue_Benchmark::callback_batch,
+ bluetooth::common::Unretained(this)));
}
counter_future.wait();
}
@@ -99,7 +102,8 @@
for (int i = 0; i < num_messages_to_send_; i++) {
counter_promise_ = std::promise<void>();
std::future<void> counter_future = counter_promise_.get_future();
- handler_->Post([this]() { callback(); });
+ handler_->Post(
+ BindOnce(&BM_ReactorThread_sequential_execution_Benchmark::callback, bluetooth::common::Unretained(this)));
counter_future.wait();
}
}
diff --git a/gd/os/utils.h b/gd/os/utils.h
index 26e8f23..89fca66 100644
--- a/gd/os/utils.h
+++ b/gd/os/utils.h
@@ -15,6 +15,7 @@
*/
#pragma once
+#include <errno.h>
// A macro to re-try a syscall when it receives EINTR
#ifndef RUN_NO_INTR
diff --git a/gd/packet/Android.bp b/gd/packet/Android.bp
index be5a3c9..c9ddb7a 100644
--- a/gd/packet/Android.bp
+++ b/gd/packet/Android.bp
@@ -2,7 +2,10 @@
name: "BluetoothPacketSources",
srcs: [
"bit_inserter.cc",
+ "byte_inserter.cc",
+ "byte_observer.cc",
"iterator.cc",
+ "fragmenting_inserter.cc",
"packet_view.cc",
"raw_builder.cc",
"view.cc",
@@ -13,6 +16,7 @@
name: "BluetoothPacketTestSources",
srcs: [
"bit_inserter_unittest.cc",
+ "fragmenting_inserter_unittest.cc",
"packet_builder_unittest.cc",
"packet_view_unittest.cc",
"raw_builder_unittest.cc",
diff --git a/gd/packet/base_struct.h b/gd/packet/base_struct.h
new file mode 100644
index 0000000..9983229
--- /dev/null
+++ b/gd/packet/base_struct.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <forward_list>
+#include <iterator>
+#include <memory>
+#include <vector>
+
+#include "packet/bit_inserter.h"
+
+namespace bluetooth {
+namespace packet {
+
+// A base struct to provide Serialize() and size() to be overridden.
+class BaseStruct {
+ public:
+ virtual ~BaseStruct() = default;
+
+ virtual size_t size() const = 0;
+
+ // Write to the vector with the given iterator.
+ virtual void Serialize(BitInserter& it) const = 0;
+
+ protected:
+ BaseStruct() = default;
+};
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/bit_inserter.cc b/gd/packet/bit_inserter.cc
index 5167806..0a8f2bc 100644
--- a/gd/packet/bit_inserter.cc
+++ b/gd/packet/bit_inserter.cc
@@ -14,147 +14,35 @@
* limitations under the License.
*/
-#include "packet/iterator.h"
+#include "packet/bit_inserter.h"
#include "os/log.h"
namespace bluetooth {
namespace packet {
-template <bool little_endian>
-Iterator<little_endian>::Iterator(std::forward_list<View> data, size_t offset) {
- data_ = data;
- index_ = offset;
- length_ = 0;
- for (auto& view : data) {
- length_ += view.size();
+BitInserter::BitInserter(std::vector<uint8_t>& vector) : ByteInserter(vector) {}
+
+BitInserter::~BitInserter() {
+ ASSERT(num_saved_bits_ == 0);
+}
+
+void BitInserter::insert_bits(uint8_t byte, size_t num_bits) {
+ size_t total_bits = num_bits + num_saved_bits_;
+ uint16_t new_value = static_cast<uint8_t>(saved_bits_) | (static_cast<uint16_t>(byte) << num_saved_bits_);
+ if (total_bits >= 8) {
+ ByteInserter::insert_byte(static_cast<uint8_t>(new_value));
+ total_bits -= 8;
+ new_value = new_value >> 8;
}
+ num_saved_bits_ = total_bits;
+ uint8_t mask = static_cast<uint8_t>(0xff) >> (8 - num_saved_bits_);
+ saved_bits_ = static_cast<uint8_t>(new_value) & mask;
}
-template <bool little_endian>
-Iterator<little_endian> Iterator<little_endian>::operator+(int offset) {
- auto itr(*this);
-
- return itr += offset;
+void BitInserter::insert_byte(uint8_t byte) {
+ insert_bits(byte, 8);
}
-template <bool little_endian>
-Iterator<little_endian>& Iterator<little_endian>::operator+=(int offset) {
- index_ += offset;
- return *this;
-}
-
-template <bool little_endian>
-Iterator<little_endian> Iterator<little_endian>::operator++(int) {
- auto itr(*this);
- index_++;
- return itr;
-}
-
-template <bool little_endian>
-Iterator<little_endian>& Iterator<little_endian>::operator++() {
- index_++;
- return *this;
-}
-
-template <bool little_endian>
-Iterator<little_endian> Iterator<little_endian>::operator-(int offset) {
- auto itr(*this);
-
- return itr -= offset;
-}
-
-template <bool little_endian>
-int Iterator<little_endian>::operator-(Iterator<little_endian>& itr) {
- return index_ - itr.index_;
-}
-
-template <bool little_endian>
-Iterator<little_endian>& Iterator<little_endian>::operator-=(int offset) {
- index_ -= offset;
-
- return *this;
-}
-
-template <bool little_endian>
-Iterator<little_endian> Iterator<little_endian>::operator--(int) {
- auto itr(*this);
- if (index_ != 0) index_--;
-
- return itr;
-}
-
-template <bool little_endian>
-Iterator<little_endian>& Iterator<little_endian>::operator--() {
- if (index_ != 0) index_--;
-
- return *this;
-}
-
-template <bool little_endian>
-Iterator<little_endian>& Iterator<little_endian>::operator=(const Iterator<little_endian>& itr) {
- data_ = itr.data_;
- index_ = itr.index_;
-
- return *this;
-}
-
-template <bool little_endian>
-bool Iterator<little_endian>::operator==(const Iterator<little_endian>& itr) const {
- return index_ == itr.index_;
-}
-
-template <bool little_endian>
-bool Iterator<little_endian>::operator!=(const Iterator<little_endian>& itr) const {
- return !(*this == itr);
-}
-
-template <bool little_endian>
-bool Iterator<little_endian>::operator<(const Iterator<little_endian>& itr) const {
- return index_ < itr.index_;
-}
-
-template <bool little_endian>
-bool Iterator<little_endian>::operator>(const Iterator<little_endian>& itr) const {
- return index_ > itr.index_;
-}
-
-template <bool little_endian>
-bool Iterator<little_endian>::operator<=(const Iterator<little_endian>& itr) const {
- return index_ <= itr.index_;
-}
-
-template <bool little_endian>
-bool Iterator<little_endian>::operator>=(const Iterator<little_endian>& itr) const {
- return index_ >= itr.index_;
-}
-
-template <bool little_endian>
-uint8_t Iterator<little_endian>::operator*() const {
- ASSERT_LOG(index_ < length_, "Index %zu out of bounds: %zu", index_, length_);
- size_t index = index_;
-
- for (auto view : data_) {
- if (index < view.size()) {
- return view[index];
- }
- index -= view.size();
- }
- ASSERT_LOG(false, "Out of fragments searching for index %zu", index_);
- return 0;
-}
-
-template <bool little_endian>
-size_t Iterator<little_endian>::NumBytesRemaining() const {
- if (length_ > index_) {
- return length_ - index_;
- } else {
- return 0;
- }
-}
-
-// Explicit instantiations for both types of Iterators.
-template class Iterator<true>;
-template class Iterator<false>;
} // namespace packet
} // namespace bluetooth
diff --git a/gd/packet/bit_inserter.h b/gd/packet/bit_inserter.h
index 9034e38..487eba5 100644
--- a/gd/packet/bit_inserter.h
+++ b/gd/packet/bit_inserter.h
@@ -21,41 +21,21 @@
#include <memory>
#include <vector>
-#include "os/log.h"
+#include "packet/byte_inserter.h"
namespace bluetooth {
namespace packet {
-class BitInserter : public std::back_insert_iterator<std::vector<uint8_t>> {
+class BitInserter : public ByteInserter {
public:
- BitInserter(std::vector<uint8_t>& vector) : std::back_insert_iterator<std::vector<uint8_t>>(vector) {}
- virtual ~BitInserter() {
- ASSERT(num_saved_bits_ == 0);
- }
+ BitInserter(std::vector<uint8_t>& vector);
+ ~BitInserter() override;
- void insert_bits(uint8_t byte, size_t num_bits) {
- size_t total_bits = num_bits + num_saved_bits_;
- uint16_t new_value = saved_bits_ | (static_cast<uint16_t>(byte) << num_saved_bits_);
- if (total_bits >= 8) {
- uint8_t new_byte = static_cast<uint8_t>(new_value);
- std::back_insert_iterator<std::vector<uint8_t>>::operator=(new_byte);
- total_bits -= 8;
- new_value = new_value >> 8;
- }
- num_saved_bits_ = total_bits;
- uint8_t mask = 0xff >> (8 - num_saved_bits_);
- saved_bits_ = static_cast<uint8_t>(new_value) & mask;
- }
+ virtual void insert_bits(uint8_t byte, size_t num_bits);
- void insert_byte(uint8_t byte) {
- insert_bits(byte, 8);
- }
+ void insert_byte(uint8_t byte) override;
- bool IsByteAligned() {
- return num_saved_bits_ == 0;
- }
-
- private:
+ protected:
size_t num_saved_bits_{0};
uint8_t saved_bits_{0};
};
diff --git a/gd/packet/bit_inserter_unittest.cc b/gd/packet/bit_inserter_unittest.cc
index 6a3b668..fae19f8 100644
--- a/gd/packet/bit_inserter_unittest.cc
+++ b/gd/packet/bit_inserter_unittest.cc
@@ -27,12 +27,6 @@
namespace bluetooth {
namespace packet {
-class BitInserterTest : public ::testing::Test {
- public:
- BitInserterTest() {}
- ~BitInserterTest() = default;
-};
-
TEST(BitInserterTest, addMoreBits) {
std::vector<uint8_t> bytes;
BitInserter it(bytes);
@@ -41,12 +35,8 @@
it.insert_bits(static_cast<uint8_t>(i), i);
}
it.insert_bits(static_cast<uint8_t>(0b1010), 4);
- std::vector<uint8_t> result = {
- 0b00011101 /* 3 2 1 */,
- 0b00010101 /* 5 4 */,
- 0b11100011 /* 7 6 */,
- 0b10000000 /* 8 */,
- 0b10100000 /* filled with 1010 */};
+ std::vector<uint8_t> result = {0b00011101 /* 3 2 1 */, 0b00010101 /* 5 4 */, 0b11100011 /* 7 6 */, 0b10000000 /* 8 */,
+ 0b10100000 /* filled with 1010 */};
ASSERT_EQ(result.size(), bytes.size());
for (size_t i = 0; i < bytes.size(); i++) {
@@ -54,5 +44,39 @@
}
}
+TEST(BitInserterTest, observerTest) {
+ std::vector<uint8_t> bytes;
+ BitInserter it(bytes);
+ std::vector<uint8_t> copy;
+
+ uint64_t checksum = 0x0123456789abcdef;
+ it.RegisterObserver(ByteObserver([©](uint8_t byte) { copy.push_back(byte); }, [checksum]() { return checksum; }));
+
+ for (size_t i = 0; i < 9; i++) {
+ it.insert_bits(static_cast<uint8_t>(i), i);
+ }
+ it.insert_bits(static_cast<uint8_t>(0b1010), 4);
+ std::vector<uint8_t> result = {0b00011101 /* 3 2 1 */, 0b00010101 /* 5 4 */, 0b11100011 /* 7 6 */, 0b10000000 /* 8 */,
+ 0b10100000 /* filled with 1010 */};
+
+ ASSERT_EQ(result.size(), bytes.size());
+ for (size_t i = 0; i < bytes.size(); i++) {
+ ASSERT_EQ(result[i], bytes[i]);
+ }
+
+ ASSERT_EQ(result.size(), copy.size());
+ for (size_t i = 0; i < copy.size(); i++) {
+ ASSERT_EQ(result[i], copy[i]);
+ }
+
+ ByteObserver observer = it.UnregisterObserver();
+ ASSERT_EQ(checksum, observer.GetValue());
+ uint8_t another_byte = 0xef;
+ it.insert_bits(another_byte, 8);
+ ASSERT_EQ(bytes.back(), another_byte);
+ ASSERT_EQ(result.size() + 1, bytes.size());
+ ASSERT_EQ(result.size(), copy.size());
+}
+
} // namespace packet
} // namespace bluetooth
diff --git a/gd/packet/byte_inserter.cc b/gd/packet/byte_inserter.cc
new file mode 100644
index 0000000..b872427
--- /dev/null
+++ b/gd/packet/byte_inserter.cc
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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 "packet/byte_inserter.h"
+
+#include "os/log.h"
+
+namespace bluetooth {
+namespace packet {
+
+ByteInserter::ByteInserter(std::vector<uint8_t>& vector) : std::back_insert_iterator<std::vector<uint8_t>>(vector) {}
+
+ByteInserter::~ByteInserter() {
+ ASSERT(registered_observers_.empty());
+}
+
+void ByteInserter::RegisterObserver(const ByteObserver& observer) {
+ registered_observers_.push_back(observer);
+}
+
+ByteObserver ByteInserter::UnregisterObserver() {
+ ByteObserver observer = registered_observers_.back();
+ registered_observers_.pop_back();
+ return observer;
+}
+
+void ByteInserter::on_byte(uint8_t byte) {
+ for (auto& observer : registered_observers_) {
+ observer.OnByte(byte);
+ }
+}
+
+void ByteInserter::insert_byte(uint8_t byte) {
+ on_byte(byte);
+ std::back_insert_iterator<std::vector<uint8_t>>::operator=(byte);
+}
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/byte_inserter.h b/gd/packet/byte_inserter.h
new file mode 100644
index 0000000..6d33aee
--- /dev/null
+++ b/gd/packet/byte_inserter.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <iterator>
+#include <memory>
+#include <vector>
+
+#include "packet/byte_observer.h"
+
+namespace bluetooth {
+namespace packet {
+
+class ByteInserter : public std::back_insert_iterator<std::vector<uint8_t>> {
+ public:
+ ByteInserter(std::vector<uint8_t>& vector);
+ virtual ~ByteInserter();
+
+ virtual void insert_byte(uint8_t byte);
+
+ void RegisterObserver(const ByteObserver& observer);
+
+ ByteObserver UnregisterObserver();
+
+ protected:
+ void on_byte(uint8_t);
+
+ private:
+ std::vector<ByteObserver> registered_observers_;
+};
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/byte_observer.cc b/gd/packet/byte_observer.cc
new file mode 100644
index 0000000..358a230
--- /dev/null
+++ b/gd/packet/byte_observer.cc
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2019 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 "packet/byte_observer.h"
+
+namespace bluetooth {
+namespace packet {
+
+ByteObserver::ByteObserver(const std::function<void(uint8_t)>& on_byte, const std::function<uint64_t()>& get_value)
+ : on_byte_(on_byte), get_value_(get_value) {}
+
+void ByteObserver::OnByte(uint8_t byte) {
+ on_byte_(byte);
+}
+
+uint64_t ByteObserver::GetValue() {
+ return get_value_();
+}
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/byte_observer.h b/gd/packet/byte_observer.h
new file mode 100644
index 0000000..adfcfc1
--- /dev/null
+++ b/gd/packet/byte_observer.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <functional>
+
+namespace bluetooth {
+namespace packet {
+
+class ByteObserver {
+ public:
+ ByteObserver(const std::function<void(uint8_t)>& on_byte_, const std::function<uint64_t()>& get_value_);
+
+ void OnByte(uint8_t byte);
+
+ uint64_t GetValue();
+
+ private:
+ std::function<void(uint8_t)> on_byte_;
+ std::function<uint64_t()> get_value_;
+};
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/endian_inserter.h b/gd/packet/endian_inserter.h
new file mode 100644
index 0000000..317c12c
--- /dev/null
+++ b/gd/packet/endian_inserter.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <forward_list>
+#include <iterator>
+#include <memory>
+#include <vector>
+
+#include "os/log.h"
+#include "packet/bit_inserter.h"
+
+namespace bluetooth {
+namespace packet {
+
+// Abstract base class that is subclassed to provide insert() functions.
+// The template parameter little_endian controls the generation of insert().
+template <bool little_endian>
+class EndianInserter {
+ public:
+ EndianInserter() = default;
+ virtual ~EndianInserter() = default;
+
+ protected:
+ // Write sizeof(FixedWidthIntegerType) bytes using the iterator
+ template <typename FixedWidthPODType, typename std::enable_if<std::is_pod<FixedWidthPODType>::value, int>::type = 0>
+ void insert(FixedWidthPODType value, BitInserter& it) const {
+ uint8_t* raw_bytes = (uint8_t*)&value;
+ for (size_t i = 0; i < sizeof(FixedWidthPODType); i++) {
+ if (little_endian == true) {
+ it.insert_byte(raw_bytes[i]);
+ } else {
+ it.insert_byte(raw_bytes[sizeof(FixedWidthPODType) - i - 1]);
+ }
+ }
+ }
+
+ // Write num_bits bits using the iterator
+ template <typename FixedWidthIntegerType,
+ typename std::enable_if<std::is_pod<FixedWidthIntegerType>::value, int>::type = 0>
+ void insert(FixedWidthIntegerType value, BitInserter& it, size_t num_bits) const {
+ ASSERT(num_bits <= (sizeof(FixedWidthIntegerType) * 8));
+
+ for (size_t i = 0; i < num_bits / 8; i++) {
+ if (little_endian == true) {
+ it.insert_byte(static_cast<uint8_t>(value >> (i * 8)));
+ } else {
+ it.insert_byte(static_cast<uint8_t>(value >> (((num_bits / 8) - i - 1) * 8)));
+ }
+ }
+ if (num_bits % 8) {
+ it.insert_bits(static_cast<uint8_t>(value >> ((num_bits / 8) * 8)), num_bits % 8);
+ }
+ }
+
+ // Specialized insert that allows inserting enums without casting
+ template <typename Enum, typename std::enable_if<std::is_enum_v<Enum>, int>::type = 0>
+ inline void insert(Enum value, BitInserter& it) const {
+ using enum_type = typename std::underlying_type_t<Enum>;
+ static_assert(std::is_unsigned_v<enum_type>, "Enum type is signed. Did you forget to specify the enum size?");
+ insert<enum_type>(static_cast<enum_type>(value), it);
+ }
+
+ // Write a vector of FixedWidthIntegerType using the iterator
+ template <typename FixedWidthIntegerType>
+ void insert_vector(const std::vector<FixedWidthIntegerType>& vec, BitInserter& it) const {
+ static_assert(std::is_pod<FixedWidthIntegerType>::value,
+ "EndianInserter::insert requires a vector with elements of a fixed-size.");
+ for (const auto& element : vec) {
+ insert(element, it);
+ }
+ }
+};
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/fragmenting_inserter.cc b/gd/packet/fragmenting_inserter.cc
new file mode 100644
index 0000000..90f87c6
--- /dev/null
+++ b/gd/packet/fragmenting_inserter.cc
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019 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 "packet/fragmenting_inserter.h"
+
+#include "os/log.h"
+
+namespace bluetooth {
+namespace packet {
+
+FragmentingInserter::FragmentingInserter(size_t mtu,
+ std::back_insert_iterator<std::vector<std::unique_ptr<RawBuilder>>> iterator)
+ : BitInserter(to_construct_bit_inserter_), mtu_(mtu), curr_packet_(std::make_unique<RawBuilder>(mtu)),
+ iterator_(iterator) {}
+
+void FragmentingInserter::insert_bits(uint8_t byte, size_t num_bits) {
+ ASSERT(curr_packet_ != nullptr);
+ size_t total_bits = num_bits + num_saved_bits_;
+ uint16_t new_value = static_cast<uint8_t>(saved_bits_) | (static_cast<uint16_t>(byte) << num_saved_bits_);
+ if (total_bits >= 8) {
+ uint8_t new_byte = static_cast<uint8_t>(new_value);
+ on_byte(new_byte);
+ curr_packet_->AddOctets1(new_byte);
+ if (curr_packet_->size() >= mtu_) {
+ iterator_ = std::move(curr_packet_);
+ curr_packet_ = std::make_unique<RawBuilder>(mtu_);
+ }
+ total_bits -= 8;
+ new_value = new_value >> 8;
+ }
+ num_saved_bits_ = total_bits;
+ uint8_t mask = static_cast<uint8_t>(0xff) >> (8 - num_saved_bits_);
+ saved_bits_ = static_cast<uint8_t>(new_value) & mask;
+}
+
+void FragmentingInserter::finalize() {
+ if (curr_packet_->size() != 0) {
+ iterator_ = std::move(curr_packet_);
+ }
+ curr_packet_.reset();
+}
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/fragmenting_inserter.h b/gd/packet/fragmenting_inserter.h
new file mode 100644
index 0000000..ff23a09
--- /dev/null
+++ b/gd/packet/fragmenting_inserter.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <iterator>
+#include <memory>
+#include <vector>
+
+#include "packet/bit_inserter.h"
+#include "packet/raw_builder.h"
+
+namespace bluetooth {
+namespace packet {
+
+class FragmentingInserter : public BitInserter {
+ public:
+ FragmentingInserter(size_t mtu, std::back_insert_iterator<std::vector<std::unique_ptr<RawBuilder>>> iterator);
+
+ void insert_bits(uint8_t byte, size_t num_bits) override;
+
+ void finalize();
+
+ protected:
+ std::vector<uint8_t> to_construct_bit_inserter_;
+ size_t mtu_;
+ std::unique_ptr<RawBuilder> curr_packet_;
+ std::back_insert_iterator<std::vector<std::unique_ptr<RawBuilder>>> iterator_;
+};
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/fragmenting_inserter_unittest.cc b/gd/packet/fragmenting_inserter_unittest.cc
new file mode 100644
index 0000000..c2f1124
--- /dev/null
+++ b/gd/packet/fragmenting_inserter_unittest.cc
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2019 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 "packet/fragmenting_inserter.h"
+
+#include <gtest/gtest.h>
+#include <memory>
+
+#include "os/log.h"
+
+using bluetooth::packet::FragmentingInserter;
+using std::vector;
+
+namespace bluetooth {
+namespace packet {
+
+TEST(FragmentingInserterTest, addMoreBits) {
+ std::vector<uint8_t> result = {0b00011101 /* 3 2 1 */, 0b00010101 /* 5 4 */, 0b11100011 /* 7 6 */, 0b10000000 /* 8 */,
+ 0b10100000 /* filled with 1010 */};
+ std::vector<std::unique_ptr<RawBuilder>> fragments;
+
+ FragmentingInserter it(result.size(), std::back_insert_iterator(fragments));
+
+ for (size_t i = 0; i < 9; i++) {
+ it.insert_bits(static_cast<uint8_t>(i), i);
+ }
+ it.insert_bits(static_cast<uint8_t>(0b1010), 4);
+
+ it.finalize();
+
+ ASSERT_EQ(1, fragments.size());
+
+ std::vector<uint8_t> bytes;
+ BitInserter bit_inserter(bytes);
+ fragments[0]->Serialize(bit_inserter);
+
+ ASSERT_EQ(result.size(), bytes.size());
+ for (size_t i = 0; i < bytes.size(); i++) {
+ ASSERT_EQ(result[i], bytes[i]);
+ }
+}
+
+TEST(FragmentingInserterTest, observerTest) {
+ std::vector<uint8_t> result = {0b00011101 /* 3 2 1 */, 0b00010101 /* 5 4 */, 0b11100011 /* 7 6 */, 0b10000000 /* 8 */,
+ 0b10100000 /* filled with 1010 */};
+ std::vector<std::unique_ptr<RawBuilder>> fragments;
+
+ FragmentingInserter it(result.size() + 1, std::back_insert_iterator(fragments));
+
+ std::vector<uint8_t> copy;
+
+ uint64_t checksum = 0x0123456789abcdef;
+ it.RegisterObserver(ByteObserver([©](uint8_t byte) { copy.push_back(byte); }, [checksum]() { return checksum; }));
+
+ for (size_t i = 0; i < 9; i++) {
+ it.insert_bits(static_cast<uint8_t>(i), i);
+ }
+ it.insert_bits(static_cast<uint8_t>(0b1010), 4);
+ it.finalize();
+
+ ASSERT_EQ(1, fragments.size());
+
+ std::vector<uint8_t> bytes;
+ BitInserter bit_inserter(bytes);
+ fragments[0]->Serialize(bit_inserter);
+
+ ASSERT_EQ(result.size(), bytes.size());
+ for (size_t i = 0; i < bytes.size(); i++) {
+ ASSERT_EQ(result[i], bytes[i]);
+ }
+
+ ASSERT_EQ(result.size(), copy.size());
+ for (size_t i = 0; i < copy.size(); i++) {
+ ASSERT_EQ(result[i], copy[i]);
+ }
+
+ ByteObserver observer = it.UnregisterObserver();
+ ASSERT_EQ(checksum, observer.GetValue());
+}
+
+TEST(FragmentingInserterTest, testMtuBoundaries) {
+ constexpr size_t kPacketSize = 1024;
+ auto counts = RawBuilder();
+ for (size_t i = 0; i < kPacketSize; i++) {
+ counts.AddOctets1(static_cast<uint8_t>(i));
+ }
+
+ std::vector<std::unique_ptr<RawBuilder>> fragments_mtu_is_kPacketSize;
+ FragmentingInserter it(kPacketSize, std::back_insert_iterator(fragments_mtu_is_kPacketSize));
+ counts.Serialize(it);
+ it.finalize();
+ ASSERT_EQ(1, fragments_mtu_is_kPacketSize.size());
+ ASSERT_EQ(kPacketSize, fragments_mtu_is_kPacketSize[0]->size());
+
+ std::vector<std::unique_ptr<RawBuilder>> fragments_mtu_is_less;
+ FragmentingInserter it_less(kPacketSize - 1, std::back_insert_iterator(fragments_mtu_is_less));
+ counts.Serialize(it_less);
+ it_less.finalize();
+ ASSERT_EQ(2, fragments_mtu_is_less.size());
+ ASSERT_EQ(kPacketSize - 1, fragments_mtu_is_less[0]->size());
+ ASSERT_EQ(1, fragments_mtu_is_less[1]->size());
+
+ std::vector<std::unique_ptr<RawBuilder>> fragments_mtu_is_more;
+ FragmentingInserter it_more(kPacketSize + 1, std::back_insert_iterator(fragments_mtu_is_more));
+ counts.Serialize(it_more);
+ it_more.finalize();
+ ASSERT_EQ(1, fragments_mtu_is_more.size());
+ ASSERT_EQ(kPacketSize, fragments_mtu_is_more[0]->size());
+}
+
+constexpr size_t kPacketSize = 128;
+class FragmentingTest : public ::testing::TestWithParam<size_t> {
+ public:
+ void StartUp() {
+ counts_.reserve(kPacketSize);
+ for (size_t i = 0; i < kPacketSize; i++) {
+ counts_.push_back(static_cast<uint8_t>(i));
+ }
+ }
+ void ShutDown() {
+ counts_.clear();
+ }
+ std::vector<uint8_t> counts_;
+};
+
+TEST_P(FragmentingTest, mtuFragmentTest) {
+ size_t mtu = GetParam();
+ std::vector<std::unique_ptr<RawBuilder>> fragments;
+ FragmentingInserter it(mtu, std::back_insert_iterator(fragments));
+
+ RawBuilder original_packet(counts_);
+ ASSERT_EQ(counts_.size(), original_packet.size());
+
+ original_packet.Serialize(it);
+ it.finalize();
+
+ size_t expected_fragments = counts_.size() / mtu;
+ if (counts_.size() % mtu != 0) {
+ expected_fragments++;
+ }
+ ASSERT_EQ(expected_fragments, fragments.size());
+
+ std::vector<std::vector<uint8_t>> serialized_fragments;
+ for (size_t f = 0; f < fragments.size(); f++) {
+ serialized_fragments.emplace_back(mtu);
+ BitInserter bit_inserter(serialized_fragments[f]);
+ fragments[f]->Serialize(bit_inserter);
+ if (f + 1 == fragments.size() && (counts_.size() % mtu != 0)) {
+ ASSERT_EQ(serialized_fragments[f].size(), counts_.size() % mtu);
+ } else {
+ ASSERT_EQ(serialized_fragments[f].size(), mtu);
+ }
+ for (size_t b = 0; b < serialized_fragments[f].size(); b++) {
+ EXPECT_EQ(counts_[f * mtu + b], serialized_fragments[f][b]);
+ }
+ }
+}
+
+INSTANTIATE_TEST_CASE_P(chopomatic, FragmentingTest, ::testing::Range<size_t>(1, kPacketSize + 1));
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/iterator.cc b/gd/packet/iterator.cc
index 5167806..f924b05 100644
--- a/gd/packet/iterator.cc
+++ b/gd/packet/iterator.cc
@@ -25,9 +25,10 @@
Iterator<little_endian>::Iterator(std::forward_list<View> data, size_t offset) {
data_ = data;
index_ = offset;
- length_ = 0;
+ begin_ = 0;
+ end_ = 0;
for (auto& view : data) {
- length_ += view.size();
+ end_ += view.size();
}
}
@@ -93,9 +94,10 @@
template <bool little_endian>
Iterator<little_endian>& Iterator<little_endian>::operator=(const Iterator<little_endian>& itr) {
- data_ = itr.data_;
- index_ = itr.index_;
-
+ this->data_ = itr.data_;
+ this->begin_ = itr.begin_;
+ this->end_ = itr.end_;
+ this->index_ = itr.index_;
return *this;
}
@@ -131,7 +133,7 @@
template <bool little_endian>
uint8_t Iterator<little_endian>::operator*() const {
- ASSERT_LOG(index_ < length_, "Index %zu out of bounds: %zu", index_, length_);
+ ASSERT_LOG(index_ < end_ && !(begin_ > index_), "Index %zu out of bounds: [%zu,%zu)", index_, begin_, end_);
size_t index = index_;
for (auto view : data_) {
@@ -146,13 +148,29 @@
template <bool little_endian>
size_t Iterator<little_endian>::NumBytesRemaining() const {
- if (length_ > index_) {
- return length_ - index_;
+ if (end_ > index_ && !(begin_ > index_)) {
+ return end_ - index_;
} else {
return 0;
}
}
+template <bool little_endian>
+Iterator<little_endian> Iterator<little_endian>::Subrange(size_t index, size_t length) const {
+ Iterator<little_endian> to_return(*this);
+ if (to_return.NumBytesRemaining() > index) {
+ to_return.index_ = to_return.index_ + index;
+ to_return.begin_ = to_return.index_;
+ if (to_return.NumBytesRemaining() >= length) {
+ to_return.end_ = to_return.index_ + length;
+ }
+ } else {
+ to_return.end_ = 0;
+ }
+
+ return to_return;
+}
+
// Explicit instantiations for both types of Iterators.
template class Iterator<true>;
template class Iterator<false>;
diff --git a/gd/packet/iterator.h b/gd/packet/iterator.h
index 56d8708..8d927a0 100644
--- a/gd/packet/iterator.h
+++ b/gd/packet/iterator.h
@@ -18,6 +18,7 @@
#include <cstdint>
#include <forward_list>
+#include <memory>
#include "packet/view.h"
@@ -60,10 +61,12 @@
size_t NumBytesRemaining() const;
+ Iterator Subrange(size_t index, size_t length) const;
+
// Get the next sizeof(FixedWidthPODType) bytes and return the filled type
template <typename FixedWidthPODType>
FixedWidthPODType extract() {
- static_assert(std::is_pod<FixedWidthPODType>::value, "Iterator::extract requires an fixed type.");
+ static_assert(std::is_pod<FixedWidthPODType>::value, "Iterator::extract requires a fixed-width type.");
FixedWidthPODType extracted_value;
uint8_t* value_ptr = (uint8_t*)&extracted_value;
@@ -77,7 +80,8 @@
private:
std::forward_list<View> data_;
size_t index_;
- size_t length_;
+ size_t begin_;
+ size_t end_;
};
} // namespace packet
diff --git a/gd/packet/packet_builder.h b/gd/packet/packet_builder.h
index 2a27cc4..3f6c627 100644
--- a/gd/packet/packet_builder.h
+++ b/gd/packet/packet_builder.h
@@ -22,11 +22,10 @@
#include <memory>
#include <vector>
-#include "common/address.h"
-#include "common/class_of_device.h"
#include "os/log.h"
#include "packet/base_packet_builder.h"
#include "packet/bit_inserter.h"
+#include "packet/endian_inserter.h"
namespace bluetooth {
namespace packet {
@@ -34,75 +33,13 @@
// Abstract base class that is subclassed to build specifc packets.
// The template parameter little_endian controls the generation of insert().
template <bool little_endian>
-class PacketBuilder : public BasePacketBuilder {
+class PacketBuilder : public BasePacketBuilder, protected EndianInserter<little_endian> {
public:
PacketBuilder() = default;
virtual ~PacketBuilder() = default;
// Classes which need fragmentation should define a function like this:
// std::forward_list<DerivedBuilder>& Fragment(size_t max_size);
-
- protected:
- // Write sizeof(FixedWidthIntegerType) bytes using the iterator
- template <typename FixedWidthIntegerType,
- typename std::enable_if<std::is_integral<FixedWidthIntegerType>::value, int>::type = 0>
- void insert(FixedWidthIntegerType value, BitInserter& it) const {
- for (size_t i = 0; i < sizeof(FixedWidthIntegerType); i++) {
- if (little_endian == true) {
- it.insert_byte(static_cast<uint8_t>(value >> (i * 8)));
- } else {
- it.insert_byte(static_cast<uint8_t>(value >> ((sizeof(FixedWidthIntegerType) - i - 1) * 8)));
- }
- }
- }
-
- // Write num_bits bits using the iterator
- template <typename FixedWidthIntegerType,
- typename std::enable_if<std::is_integral<FixedWidthIntegerType>::value, int>::type = 0>
- void insert(FixedWidthIntegerType value, BitInserter& it, size_t num_bits) const {
- ASSERT(num_bits <= (sizeof(FixedWidthIntegerType) * 8));
-
- for (size_t i = 0; i < num_bits / 8; i++) {
- if (little_endian == true) {
- it.insert_byte(static_cast<uint8_t>(value >> (i * 8)));
- } else {
- it.insert_byte(static_cast<uint8_t>(value >> (((num_bits / 8) - i - 1) * 8)));
- }
- }
- if (num_bits % 8) {
- it.insert_bits(static_cast<uint8_t>(value >> ((num_bits / 8) * 8)), num_bits % 8);
- }
- }
-
- // Specialized insert that allows inserting enums without casting
- template <typename Enum, typename std::enable_if<std::is_enum_v<Enum>, int>::type = 0>
- inline void insert(Enum value, BitInserter& it) const {
- using enum_type = typename std::underlying_type_t<Enum>;
- static_assert(std::is_unsigned_v<enum_type>, "Enum type is signed. Did you forget to specify the enum size?");
- insert<enum_type>(static_cast<enum_type>(value), it);
- }
-
- // Write a vector of FixedWidthIntegerType using the iterator
- template <typename FixedWidthIntegerType>
- void insert_vector(const std::vector<FixedWidthIntegerType>& vec, BitInserter& it) const {
- static_assert(std::is_integral<FixedWidthIntegerType>::value,
- "PacketBuilder::insert requires an integral type vector.");
- for (const auto& element : vec) {
- insert(element, it);
- }
- }
-
- void insert_address(const common::Address& addr, BitInserter& it) const {
- for (const auto& element : addr.address) {
- insert(element, it);
- }
- }
-
- void insert_class_of_device(const common::ClassOfDevice& cod, BitInserter& it) const {
- for (const auto& element : cod.cod) {
- insert(element, it);
- }
- }
};
} // namespace packet
diff --git a/gd/packet/packet_builder_unittest.cc b/gd/packet/packet_builder_unittest.cc
index 74a27e6..46647a3 100644
--- a/gd/packet/packet_builder_unittest.cc
+++ b/gd/packet/packet_builder_unittest.cc
@@ -99,9 +99,9 @@
template <typename T>
class VectorBuilder : public PacketBuilder<true> {
public:
- VectorBuilder(std::vector<uint64_t> vect) {
+ VectorBuilder(const std::vector<uint64_t> vect) {
for (uint64_t element : vect) {
- vect.push_back(static_cast<T>(element));
+ vect_.push_back(static_cast<T>(element));
}
}
~VectorBuilder() = default;
@@ -129,9 +129,9 @@
template <typename T>
class InsertElementsBuilder : public PacketBuilder<true> {
public:
- InsertElementsBuilder(std::vector<uint64_t> vect) {
+ InsertElementsBuilder(const std::vector<uint64_t> vect) {
for (uint64_t element : vect) {
- vect.push_back(static_cast<T>(element));
+ vect_.push_back(static_cast<T>(element));
}
}
virtual ~InsertElementsBuilder() = default;
diff --git a/gd/packet/packet_struct.h b/gd/packet/packet_struct.h
new file mode 100644
index 0000000..19bb0e5
--- /dev/null
+++ b/gd/packet/packet_struct.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <forward_list>
+#include <iterator>
+#include <memory>
+#include <vector>
+
+#include "os/log.h"
+#include "packet/base_struct.h"
+#include "packet/bit_inserter.h"
+#include "packet/endian_inserter.h"
+
+namespace bluetooth {
+namespace packet {
+
+// Abstract base class that is subclassed to build specifc structs.
+// The template parameter little_endian controls the generation of insert().
+template <bool little_endian>
+class PacketStruct : public BaseStruct, protected EndianInserter<little_endian> {
+ public:
+ PacketStruct() = default;
+ virtual ~PacketStruct() = default;
+};
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/packet_view.cc b/gd/packet/packet_view.cc
index 94522ae..badd641 100644
--- a/gd/packet/packet_view.cc
+++ b/gd/packet/packet_view.cc
@@ -99,6 +99,24 @@
return PacketView<false>(GetSubviewList(begin, end));
}
+template <bool little_endian>
+void PacketView<little_endian>::Append(PacketView to_add) {
+ auto insertion_point = fragments_.begin();
+ size_t remaining_length = length_;
+ while (remaining_length > 0) {
+ remaining_length -= insertion_point->size();
+ if (remaining_length > 0) {
+ insertion_point++;
+ }
+ }
+ ASSERT(insertion_point != fragments_.end());
+ for (const auto& fragment : to_add.fragments_) {
+ fragments_.insert_after(insertion_point, fragment);
+ insertion_point++;
+ }
+ length_ += to_add.length_;
+}
+
// Explicit instantiations for both types of PacketViews.
template class PacketView<true>;
template class PacketView<false>;
diff --git a/gd/packet/packet_view.h b/gd/packet/packet_view.h
index 4b2f191..304794c 100644
--- a/gd/packet/packet_view.h
+++ b/gd/packet/packet_view.h
@@ -52,6 +52,9 @@
PacketView<false> GetBigEndianSubview(size_t begin, size_t end) const;
+ protected:
+ void Append(PacketView to_add);
+
private:
std::forward_list<View> fragments_;
size_t length_;
diff --git a/gd/packet/packet_view_unittest.cc b/gd/packet/packet_view_unittest.cc
index e88c2cf..0ec2ef4 100644
--- a/gd/packet/packet_view_unittest.cc
+++ b/gd/packet/packet_view_unittest.cc
@@ -20,9 +20,9 @@
#include <forward_list>
#include <memory>
-#include "common/address.h"
+#include "hci/address.h"
-using bluetooth::common::Address;
+using bluetooth::hci::Address;
using bluetooth::packet::PacketView;
using bluetooth::packet::View;
using std::vector;
@@ -91,6 +91,36 @@
public:
PacketViewMultiViewTest() = default;
~PacketViewMultiViewTest() = default;
+
+ const PacketView<true> single_view =
+ PacketView<true>({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ const PacketView<true> multi_view = PacketView<true>({
+ View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
+ View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
+ });
+};
+
+class PacketViewMultiViewAppendTest : public ::testing::Test {
+ public:
+ PacketViewMultiViewAppendTest() = default;
+ ~PacketViewMultiViewAppendTest() = default;
+
+ class AppendedPacketView : public PacketView<true> {
+ public:
+ AppendedPacketView(PacketView<true> first, std::forward_list<PacketView<true>> to_append)
+ : PacketView<true>(first) {
+ for (const auto& packet_view : to_append) {
+ Append(packet_view);
+ }
+ }
+ };
+ const PacketView<true> single_view =
+ PacketView<true>({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
+ const PacketView<true> multi_view = AppendedPacketView(
+ PacketView<true>({View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size())}),
+ {PacketView<true>({View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size())}),
+ PacketView<true>({View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size())})});
};
class ViewTest : public ::testing::Test {
@@ -273,7 +303,7 @@
ASSERT_EQ(0x1f, (*(this->packet))[working_index]);
}
-TYPED_TEST(PacketViewTest, numBytesRemainingTest) {
+TYPED_TEST(IteratorTest, numBytesRemainingTest) {
auto all = this->packet->begin();
size_t remaining = all.NumBytesRemaining();
for (size_t n = remaining; n > 0; n--) {
@@ -288,6 +318,81 @@
ASSERT_DEATH(*(all++), "");
}
+TYPED_TEST(IteratorTest, subrangeTest) {
+ auto empty = this->packet->begin().Subrange(0, 0);
+ ASSERT_EQ(static_cast<size_t>(0), empty.NumBytesRemaining());
+ ASSERT_DEATH(*empty, "");
+
+ empty = this->packet->begin().Subrange(this->packet->size(), 1);
+ ASSERT_EQ(static_cast<size_t>(0), empty.NumBytesRemaining());
+ ASSERT_DEATH(*empty, "");
+
+ auto all = this->packet->begin();
+ auto fullrange = all.Subrange(0, all.NumBytesRemaining());
+ ASSERT_EQ(all.NumBytesRemaining(), fullrange.NumBytesRemaining());
+ ASSERT_EQ(*(all + 1), 1);
+
+ fullrange = all.Subrange(0, all.NumBytesRemaining() + 1);
+ ASSERT_EQ(all.NumBytesRemaining(), fullrange.NumBytesRemaining());
+ ASSERT_EQ(*(all + 1), 1);
+
+ fullrange = all.Subrange(0, all.NumBytesRemaining() + 10);
+ ASSERT_EQ(all.NumBytesRemaining(), fullrange.NumBytesRemaining());
+ ASSERT_EQ(*(all + 1), 1);
+
+ auto subrange = all.Subrange(0, 1);
+ ASSERT_EQ(1, subrange.NumBytesRemaining());
+ ASSERT_EQ(*(subrange), 0);
+
+ subrange = this->packet->begin().Subrange(0, 4);
+ ASSERT_EQ(4, subrange.NumBytesRemaining());
+ ASSERT_EQ(*(subrange + 1), 1);
+
+ subrange = all.Subrange(0, 3);
+ ASSERT_EQ(3, subrange.NumBytesRemaining());
+ ASSERT_EQ(*(subrange + 1), 1);
+
+ subrange = all.Subrange(0, all.NumBytesRemaining() - 1);
+ ASSERT_EQ(all.NumBytesRemaining() - 1, subrange.NumBytesRemaining());
+ ASSERT_EQ(*(subrange + 1), 1);
+
+ subrange = all.Subrange(0, all.NumBytesRemaining() - 2);
+ ASSERT_EQ(all.NumBytesRemaining() - 2, subrange.NumBytesRemaining());
+ ASSERT_EQ(*(subrange + 1), 1);
+
+ subrange = all.Subrange(1, all.NumBytesRemaining());
+ ASSERT_EQ(all.NumBytesRemaining() - 1, subrange.NumBytesRemaining());
+ ASSERT_EQ(*subrange, 1);
+
+ subrange = all.Subrange(2, all.NumBytesRemaining());
+ ASSERT_EQ(all.NumBytesRemaining() - 2, subrange.NumBytesRemaining());
+ ASSERT_EQ(*subrange, 2);
+
+ subrange = all.Subrange(1, all.NumBytesRemaining() - 1);
+ ASSERT_EQ(all.NumBytesRemaining() - 1, subrange.NumBytesRemaining());
+ ASSERT_EQ(*subrange, 1);
+
+ subrange = all.Subrange(2, all.NumBytesRemaining() - 2);
+ ASSERT_EQ(all.NumBytesRemaining() - 2, subrange.NumBytesRemaining());
+ ASSERT_EQ(*subrange, 2);
+
+ subrange = all.Subrange(1, 1);
+ ASSERT_EQ(1, subrange.NumBytesRemaining());
+ ASSERT_EQ(*(subrange), 1);
+
+ subrange = all.Subrange(1, 2);
+ ASSERT_EQ(2, subrange.NumBytesRemaining());
+ ASSERT_EQ(*(subrange), 1);
+
+ subrange = all.Subrange(2, 1);
+ ASSERT_EQ(1, subrange.NumBytesRemaining());
+ ASSERT_EQ(*(subrange), 2);
+
+ subrange = this->packet->begin().Subrange(this->packet->size() - 1, 2);
+ ASSERT_EQ(static_cast<size_t>(1), subrange.NumBytesRemaining());
+ ASSERT_EQ(*(subrange), this->packet->size() - 1);
+}
+
using SubviewTestParam = std::pair<size_t, size_t>;
class SubviewBaseTest : public ::testing::TestWithParam<SubviewTestParam> {
public:
@@ -408,23 +513,11 @@
}
}
-TEST(PacketViewMultiViewTest, sizeTest) {
- PacketView<true> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
- PacketView<true> multi_view({
- View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
- View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
- View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
- });
+TEST_F(PacketViewMultiViewTest, sizeTest) {
ASSERT_EQ(single_view.size(), multi_view.size());
}
-TEST(PacketViewMultiViewTest, dereferenceTestLittleEndian) {
- PacketView<true> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
- PacketView<true> multi_view({
- View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
- View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
- View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
- });
+TEST_F(PacketViewMultiViewTest, dereferenceTestLittleEndian) {
auto single_itr = single_view.begin();
auto multi_itr = multi_view.begin();
for (size_t i = 0; i < single_view.size(); i++) {
@@ -433,13 +526,7 @@
ASSERT_DEATH(*multi_itr, "");
}
-TEST(PacketViewMultiViewTest, dereferenceTestBigEndian) {
- PacketView<false> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
- PacketView<false> multi_view({
- View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
- View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
- View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
- });
+TEST_F(PacketViewMultiViewTest, dereferenceTestBigEndian) {
auto single_itr = single_view.begin();
auto multi_itr = multi_view.begin();
for (size_t i = 0; i < single_view.size(); i++) {
@@ -448,13 +535,36 @@
ASSERT_DEATH(*multi_itr, "");
}
-TEST(PacketViewMultiViewTest, arrayOperatorTest) {
- PacketView<true> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
- PacketView<true> multi_view({
- View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
- View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
- View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
- });
+TEST_F(PacketViewMultiViewTest, arrayOperatorTest) {
+ for (size_t i = 0; i < single_view.size(); i++) {
+ ASSERT_EQ(single_view[i], multi_view[i]);
+ }
+ ASSERT_DEATH(multi_view[single_view.size()], "");
+}
+
+TEST_F(PacketViewMultiViewAppendTest, sizeTestAppend) {
+ ASSERT_EQ(single_view.size(), multi_view.size());
+}
+
+TEST_F(PacketViewMultiViewAppendTest, dereferenceTestLittleEndianAppend) {
+ auto single_itr = single_view.begin();
+ auto multi_itr = multi_view.begin();
+ for (size_t i = 0; i < single_view.size(); i++) {
+ ASSERT_EQ(*(single_itr++), *(multi_itr++));
+ }
+ ASSERT_DEATH(*multi_itr, "");
+}
+
+TEST_F(PacketViewMultiViewAppendTest, dereferenceTestBigEndianAppend) {
+ auto single_itr = single_view.begin();
+ auto multi_itr = multi_view.begin();
+ for (size_t i = 0; i < single_view.size(); i++) {
+ ASSERT_EQ(*(single_itr++), *(multi_itr++));
+ }
+ ASSERT_DEATH(*multi_itr, "");
+}
+
+TEST_F(PacketViewMultiViewAppendTest, arrayOperatorTestAppend) {
for (size_t i = 0; i < single_view.size(); i++) {
ASSERT_EQ(single_view[i], multi_view[i]);
}
diff --git a/gd/packet/parser/Android.bp b/gd/packet/parser/Android.bp
new file mode 100644
index 0000000..97f323a
--- /dev/null
+++ b/gd/packet/parser/Android.bp
@@ -0,0 +1,52 @@
+cc_binary_host {
+ name: "bluetooth_packetgen",
+ srcs: [
+ "fields/array_field.cc",
+ "fields/vector_field.cc",
+ "fields/body_field.cc",
+ "fields/checksum_field.cc",
+ "fields/checksum_start_field.cc",
+ "fields/count_field.cc",
+ "fields/custom_field.cc",
+ "fields/custom_field_fixed_size.cc",
+ "fields/enum_field.cc",
+ "fields/fixed_enum_field.cc",
+ "fields/fixed_field.cc",
+ "fields/fixed_scalar_field.cc",
+ "fields/group_field.cc",
+ "fields/packet_field.cc",
+ "fields/padding_field.cc",
+ "fields/payload_field.cc",
+ "fields/reserved_field.cc",
+ "fields/scalar_field.cc",
+ "fields/size_field.cc",
+ "fields/struct_field.cc",
+ "fields/variable_length_struct_field.cc",
+ "checksum_def.cc",
+ "custom_field_def.cc",
+ "enum_def.cc",
+ "enum_gen.cc",
+ "packet_def.cc",
+ "parent_def.cc",
+ "struct_def.cc",
+ "struct_parser_generator.cc",
+ "main.cc",
+ "language_y.yy",
+ "language_l.ll",
+ ],
+ static_libs: [
+ "libc++fs",
+ ],
+ cppflags: [
+ "-fno-exceptions",
+ "-O0",
+ ],
+ ldflags: [
+ "-fuse-ld=ld",
+ "-O0",
+ ],
+ yacc: {
+ gen_location_hh: true,
+ gen_position_hh: true,
+ },
+}
diff --git a/gd/packet/parser/README b/gd/packet/parser/README
new file mode 100644
index 0000000..9006c94
--- /dev/null
+++ b/gd/packet/parser/README
@@ -0,0 +1,59 @@
+This file just contains some notes about the design and usage of the PDL language.
+
+-------
+ TERMS
+-------
+.pdl
+ The file type that defines packet definitions. You may think of each pdl file
+ as its own translation unit.
+
+Packet Views and Builders
+ Generated from a packet definition. Views are used to validate packets and
+ extract the fields that are defined in the pdl file. Builders check the input
+ arguments and can be serialized.
+
+Checksum types
+ checksum MyChecksumClass : 16 "path/to/the/class/"
+ Checksum fields need to implement the following three static methods:
+ static void Initialize(MyChecksumClass&);
+ static void AddByte(MyChecksumClass&, uint8_t);
+ // Assuming a 16-bit (uint16_t) checksum:
+ static uint16_t GetChecksum(MyChecksumClass&);
+-------------
+ LIMITATIONS
+-------------
+ - Size fields for a variable length field MUST come before the definition
+ of said field.
+
+ - Payload fields must be byte-aligned unless they have an unknown size.
+ Body fields are allowed to not be byte aligned.
+
+ - No conditionals
+
+ - Can not have to fields with the same name anywhere in the in an inheritence chain
+
+ - Can't handle size for Body type fields yet since they might not be byte aligned.
+
+ - Currently no arrays of custom types (might change later)
+
+-------
+ NOTES
+-------
+All field names should be in snake_case. Types should be in CamelCase.
+
+The _payload_ keyword generates a getter but _body_ doesn't. Therefore, a
+_payload_ must be byte aligned.
+
+Supports constraints on grandparents
+Supports multiple constraints
+Every field handles its own generation.
+One pdl file will result in one header file with all the packets
+
+Things to cover -
+ Constraints
+ Inheritence vs Contains
+
+Custom fields need the folowing functions:
+ static void Serialize(const Type&, MutableView&);
+ static std::optional<size_t> Size(Iterator);
+ static Type Parse(Iterator);
diff --git a/gd/packet/parser/checksum_def.cc b/gd/packet/parser/checksum_def.cc
new file mode 100644
index 0000000..8cb1803
--- /dev/null
+++ b/gd/packet/parser/checksum_def.cc
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2019 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 "checksum_def.h"
+#include "checksum_type_checker.h"
+#include "fields/checksum_field.h"
+#include "util.h"
+
+ChecksumDef::ChecksumDef(std::string name, std::string include, int size) : CustomFieldDef(name, include, size) {}
+
+PacketField* ChecksumDef::GetNewField(const std::string& name, ParseLocation loc) const {
+ return new ChecksumField(name, name_, size_, loc);
+}
+
+TypeDef::Type ChecksumDef::GetDefinitionType() const {
+ return TypeDef::Type::CHECKSUM;
+}
+
+void ChecksumDef::GenChecksumCheck(std::ostream& s) const {
+ s << "static_assert(ChecksumTypeChecker<" << name_ << "," << util::GetTypeForSize(size_) << ">::value, \"";
+ s << name_ << " is not a valid checksum type. Please see README for more details.\");";
+}
diff --git a/gd/packet/parser/checksum_def.h b/gd/packet/parser/checksum_def.h
new file mode 100644
index 0000000..f82b8c3
--- /dev/null
+++ b/gd/packet/parser/checksum_def.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <iostream>
+
+#include "custom_field_def.h"
+#include "fields/packet_field.h"
+#include "parse_location.h"
+#include "type_def.h"
+
+class ChecksumDef : public CustomFieldDef {
+ public:
+ ChecksumDef(std::string name, std::string include, int size);
+
+ virtual PacketField* GetNewField(const std::string& name, ParseLocation loc) const override;
+
+ virtual TypeDef::Type GetDefinitionType() const override;
+
+ void GenChecksumCheck(std::ostream& s) const;
+
+ const std::string include_;
+};
diff --git a/gd/packet/parser/checksum_type_checker.h b/gd/packet/parser/checksum_type_checker.h
new file mode 100644
index 0000000..3e384b1
--- /dev/null
+++ b/gd/packet/parser/checksum_type_checker.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <optional>
+
+namespace bluetooth {
+namespace packet {
+namespace parser {
+
+// Checks for Initialize(), AddByte(), and GetChecksum().
+// T and TRET are the checksum class Type and the checksum return type
+// C and CRET are the substituted types for T and TRET
+template <typename T, typename TRET>
+class ChecksumTypeChecker {
+ public:
+ template <class C, void (C::*)()>
+ struct InitializeChecker {};
+
+ template <class C, void (C::*)(uint8_t byte)>
+ struct AddByteChecker {};
+
+ template <class C, typename CRET, CRET (C::*)() const>
+ struct GetChecksumChecker {};
+
+ // If all the methods are defined, this one matches
+ template <class C, typename CRET>
+ static int Test(InitializeChecker<C, &C::Initialize>*, AddByteChecker<C, &C::AddByte>*,
+ GetChecksumChecker<C, CRET, &C::GetChecksum>*);
+
+ // This one matches everything else
+ template <class C, typename CRET>
+ static char Test(...);
+
+ // This checks which template was matched
+ static constexpr bool value = (sizeof(Test<T, TRET>(0, 0, 0)) == sizeof(int));
+};
+} // namespace parser
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/parser/custom_field_def.cc b/gd/packet/parser/custom_field_def.cc
new file mode 100644
index 0000000..3f2076d
--- /dev/null
+++ b/gd/packet/parser/custom_field_def.cc
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2019 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 "custom_field_def.h"
+
+#include "util.h"
+
+CustomFieldDef::CustomFieldDef(std::string name, std::string include) : TypeDef(name), include_(include) {}
+
+CustomFieldDef::CustomFieldDef(std::string name, std::string include, int size)
+ : TypeDef(name, size), include_(include) {
+ if (size % 8 != 0) {
+ ERROR() << "Custom fields must be byte aligned.";
+ }
+}
+
+PacketField* CustomFieldDef::GetNewField(const std::string& name, ParseLocation loc) const {
+ if (size_ == -1) {
+ return new CustomField(name, name_, loc);
+ } else {
+ return new CustomFieldFixedSize(name, name_, size_, loc);
+ }
+}
+
+TypeDef::Type CustomFieldDef::GetDefinitionType() const {
+ return TypeDef::Type::CUSTOM;
+}
+
+void CustomFieldDef::GenInclude(std::ostream& s) const {
+ s << "#include \"" << include_ << util::CamelCaseToUnderScore(GetTypeName()) << ".h\"\n";
+}
+
+void CustomFieldDef::GenUsing(std::ostream& s) const {
+ s << "using ::bluetooth::";
+ for (const auto& c : include_) {
+ switch (c) {
+ case '/':
+ s << "::";
+ break;
+ default:
+ s << c;
+ }
+ }
+ s << GetTypeName() << ";";
+}
+
+void CustomFieldDef::GenCustomFieldCheck(std::ostream& s, bool little_endian) const {
+ s << "static_assert(CustomTypeChecker<" << name_ << ", ";
+ s << (little_endian ? "" : "!") << "kLittleEndian>::value, \"";
+ s << name_ << " is not a valid custom field type. Please see README for more details.\");";
+}
diff --git a/gd/packet/parser/custom_field_def.h b/gd/packet/parser/custom_field_def.h
new file mode 100644
index 0000000..26b954f
--- /dev/null
+++ b/gd/packet/parser/custom_field_def.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <iostream>
+
+#include "fields/custom_field.h"
+#include "fields/custom_field_fixed_size.h"
+#include "parse_location.h"
+#include "type_def.h"
+
+class CustomFieldDef : public TypeDef {
+ public:
+ CustomFieldDef(std::string name, std::string include);
+
+ CustomFieldDef(std::string name, std::string include, int size);
+
+ virtual PacketField* GetNewField(const std::string& name, ParseLocation loc) const override;
+
+ virtual Type GetDefinitionType() const override;
+
+ void GenInclude(std::ostream& s) const;
+
+ void GenUsing(std::ostream& s) const;
+
+ void GenCustomFieldCheck(std::ostream& s, bool little_endian) const;
+
+ const std::string include_;
+};
diff --git a/gd/packet/parser/custom_type_checker.h b/gd/packet/parser/custom_type_checker.h
new file mode 100644
index 0000000..5d99622
--- /dev/null
+++ b/gd/packet/parser/custom_type_checker.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <array>
+
+#include "packet/bit_inserter.h"
+#include "packet/iterator.h"
+
+namespace bluetooth {
+namespace packet {
+// Checks a custom type has all the necessary functions with the correct signatures.
+template <typename T, bool packet_little_endian>
+class CustomTypeChecker {
+ public:
+ template <class C, void (C::*)(BitInserter&) const>
+ struct SerializeChecker {};
+
+ template <class C, size_t (C::*)() const>
+ struct SizeChecker {};
+
+ template <class C, bool little_endian, std::optional<Iterator<little_endian>> (*)(C* vec, Iterator<little_endian> it)>
+ struct ParseChecker {};
+
+ template <class C, bool little_endian>
+ static int Test(SerializeChecker<C, &C::Serialize>*, SizeChecker<C, &C::size>*,
+ ParseChecker<C, little_endian, &C::Parse>*);
+
+ template <class C, bool little_endian>
+ static char Test(...);
+
+ static constexpr bool value = (sizeof(Test<T, packet_little_endian>(0, 0, 0)) == sizeof(int));
+};
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/parser/declarations.h b/gd/packet/parser/declarations.h
new file mode 100644
index 0000000..549ddc4
--- /dev/null
+++ b/gd/packet/parser/declarations.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <deque>
+#include <map>
+#include <optional>
+
+#include "checksum_def.h"
+#include "custom_field_def.h"
+#include "enum_def.h"
+#include "enum_gen.h"
+#include "packet_def.h"
+#include "struct_def.h"
+
+class Declarations {
+ public:
+ void AddTypeDef(std::string name, TypeDef* def) {
+ auto it = type_defs_.find(name);
+ if (it != type_defs_.end()) {
+ ERROR() << "Redefinition of Type " << name;
+ }
+ type_defs_.insert(std::pair(name, def));
+ type_defs_queue_.push_back(std::pair(name, def));
+ }
+
+ TypeDef* GetTypeDef(const std::string& name) {
+ auto it = type_defs_.find(name);
+ if (it == type_defs_.end()) {
+ return nullptr;
+ }
+
+ return it->second;
+ }
+
+ void AddPacketDef(std::string name, PacketDef def) {
+ auto it = packet_defs_.find(name);
+ if (it != packet_defs_.end()) {
+ ERROR() << "Redefinition of Packet " << name;
+ }
+ packet_defs_.insert(std::pair(name, def));
+ packet_defs_queue_.push_back(std::pair(name, def));
+ }
+
+ PacketDef* GetPacketDef(const std::string& name) {
+ auto it = packet_defs_.find(name);
+ if (it == packet_defs_.end()) {
+ return nullptr;
+ }
+
+ return &(it->second);
+ }
+
+ void AddGroupDef(std::string name, FieldList* group_def) {
+ auto it = group_defs_.find(name);
+ if (it != group_defs_.end()) {
+ ERROR() << "Redefinition of group " << name;
+ }
+ group_defs_.insert(std::pair(name, group_def));
+ }
+
+ FieldList* GetGroupDef(std::string name) {
+ if (group_defs_.find(name) == group_defs_.end()) {
+ return nullptr;
+ }
+
+ return group_defs_.at(name);
+ }
+
+ std::map<std::string, FieldList*> group_defs_;
+
+ std::map<std::string, TypeDef*> type_defs_;
+ std::deque<std::pair<std::string, TypeDef*>> type_defs_queue_;
+ std::map<std::string, PacketDef> packet_defs_;
+ std::deque<std::pair<std::string, PacketDef>> packet_defs_queue_;
+ bool is_little_endian;
+};
diff --git a/gd/packet/parser/enum_def.cc b/gd/packet/parser/enum_def.cc
new file mode 100644
index 0000000..8b90426
--- /dev/null
+++ b/gd/packet/parser/enum_def.cc
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019 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 "enum_def.h"
+
+#include <iostream>
+#include <map>
+
+#include "fields/enum_field.h"
+#include "util.h"
+
+EnumDef::EnumDef(std::string name, int size) : TypeDef(name, size) {}
+
+void EnumDef::AddEntry(std::string name, uint32_t value) {
+ if (!util::IsEnumCase(name)) {
+ ERROR() << __func__ << ": Enum " << name << "(" << value << ") should be all uppercase with underscores";
+ }
+ if (value > util::GetMaxValueForBits(size_)) {
+ ERROR() << __func__ << ": Value of " << name << "(" << value << ") is greater than the max possible value for enum "
+ << name_ << "(" << util::GetMaxValueForBits(size_) << ")\n";
+ }
+
+ constants_.insert(std::pair(value, name));
+ entries_.insert(name);
+}
+
+PacketField* EnumDef::GetNewField(const std::string& name, ParseLocation loc) const {
+ return new EnumField(name, *this, "What is this for", loc);
+}
+
+bool EnumDef::HasEntry(std::string name) const {
+ return entries_.count(name) != 0;
+}
+
+TypeDef::Type EnumDef::GetDefinitionType() const {
+ return TypeDef::Type::ENUM;
+}
diff --git a/gd/packet/parser/enum_def.h b/gd/packet/parser/enum_def.h
new file mode 100644
index 0000000..5698d0f
--- /dev/null
+++ b/gd/packet/parser/enum_def.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <map>
+#include <set>
+#include <string>
+
+#include "fields/packet_field.h"
+#include "type_def.h"
+
+// Holds the definition of an enum.
+class EnumDef : public TypeDef {
+ public:
+ EnumDef(std::string name, int size);
+
+ virtual PacketField* GetNewField(const std::string& name, ParseLocation loc) const;
+
+ void AddEntry(std::string name, uint32_t value);
+
+ bool HasEntry(std::string name) const;
+
+ virtual Type GetDefinitionType() const override;
+
+ // data
+ std::map<uint32_t, std::string> constants_;
+ std::set<std::string> entries_;
+};
diff --git a/gd/packet/parser/enum_gen.cc b/gd/packet/parser/enum_gen.cc
new file mode 100644
index 0000000..4bd5a26
--- /dev/null
+++ b/gd/packet/parser/enum_gen.cc
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2019 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 "enum_gen.h"
+
+#include <iostream>
+
+#include "util.h"
+
+EnumGen::EnumGen(EnumDef e) : e_(std::move(e)) {}
+
+void EnumGen::GenDefinition(std::ostream& stream) {
+ stream << "enum class ";
+ stream << e_.name_;
+ stream << " : " << util::GetTypeForSize(e_.size_);
+ stream << " {";
+ for (const auto& pair : e_.constants_) {
+ stream << pair.second << " = 0x" << std::hex << pair.first << std::dec << ",";
+ }
+ stream << "};\n";
+}
+
+void EnumGen::GenDefinitionPybind11(std::ostream& stream) {
+ stream << "py::enum_<" << e_.name_ << ">(m, \"" << e_.name_ << "\")";
+ for (const auto& pair : e_.constants_) {
+ stream << ".value(\"" << pair.second << "\", " << e_.name_ << "::" << pair.second << ")";
+ }
+ stream << ";\n";
+}
+
+void EnumGen::GenLogging(std::ostream& stream) {
+ // Print out the switch statement that converts all the constants to strings.
+ stream << "inline std::string " << e_.name_ << "Text(const " << e_.name_ << "& param) {";
+ stream << "switch (param) {";
+ for (const auto& pair : e_.constants_) {
+ stream << "case " << e_.name_ << "::" << pair.second << ":";
+ stream << " return \"" << pair.second << "\";";
+ }
+ stream << "default:";
+ stream << " return std::string(\"Unknown " << e_.name_ << ": \") + std::to_string(static_cast<int>(param));";
+ stream << "}";
+ stream << "}\n\n";
+
+ // Print out the stream operator so that the constant can be written to streams.
+ stream << "inline std::ostream& operator<<(std::ostream& os, const " << e_.name_ << "& param) {";
+ stream << " return os << " << e_.name_ << "Text(param);";
+ stream << "}\n";
+}
diff --git a/gd/packet/parser/enum_gen.h b/gd/packet/parser/enum_gen.h
new file mode 100644
index 0000000..be16559
--- /dev/null
+++ b/gd/packet/parser/enum_gen.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <iostream>
+
+#include "enum_def.h"
+
+// Generates the C++ code for an enum.
+class EnumGen {
+ public:
+ EnumGen(EnumDef e);
+
+ void GenDefinition(std::ostream& stream);
+
+ void GenDefinitionPybind11(std::ostream& stream);
+
+ void GenLogging(std::ostream& stream);
+
+ EnumDef e_;
+};
diff --git a/gd/packet/parser/field_list.h b/gd/packet/parser/field_list.h
new file mode 100644
index 0000000..81fc0d7
--- /dev/null
+++ b/gd/packet/parser/field_list.h
@@ -0,0 +1,210 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include "fields/all_fields.h"
+#include "fields/packet_field.h"
+
+using FieldListIterator = std::vector<PacketField*>::const_iterator;
+using ReverseFieldListIterator = std::vector<PacketField*>::const_reverse_iterator;
+
+class FieldList {
+ public:
+ FieldList() = default;
+
+ FieldList(std::vector<PacketField*> fields) {
+ for (PacketField* field : fields) {
+ AppendField(field);
+ }
+ }
+
+ template <class Iterator>
+ FieldList(Iterator begin, Iterator end) {
+ while (begin != end) {
+ AppendField(*begin);
+ begin++;
+ }
+ }
+
+ PacketField* operator[](int index) const {
+ return field_list_[index];
+ }
+
+ PacketField* GetField(std::string field_name) const {
+ auto it = field_map_.find(field_name);
+ if (it == field_map_.end()) {
+ return nullptr;
+ }
+
+ return it->second;
+ }
+
+ void AppendField(PacketField* field) {
+ AddField(field);
+ field_list_.push_back(field);
+ }
+
+ void PrependField(PacketField* field) {
+ AddField(field);
+ field_list_.insert(field_list_.begin(), field);
+ }
+
+ FieldList GetFieldsBeforePayloadOrBody() const {
+ FieldList ret;
+ for (auto it = begin(); it != end(); it++) {
+ const auto& field = *it;
+ if (field->GetFieldType() == PayloadField::kFieldType || field->GetFieldType() == BodyField::kFieldType) {
+ break;
+ }
+ ret.AppendField(*it);
+ }
+
+ return ret;
+ }
+
+ FieldList GetFieldsAfterPayloadOrBody() const {
+ FieldListIterator it;
+ for (it = begin(); it != end(); it++) {
+ const auto& field = *it;
+ if (field->GetFieldType() == PayloadField::kFieldType || field->GetFieldType() == BodyField::kFieldType) {
+ // Increment it once to get first field after payload/body.
+ it++;
+ break;
+ }
+ }
+
+ return FieldList(it, end());
+ }
+
+ FieldList GetFieldsWithTypes(std::set<std::string> field_types) const {
+ FieldList ret;
+
+ for (const auto& field : field_list_) {
+ if (field_types.find(field->GetFieldType()) != field_types.end()) {
+ ret.AppendField(field);
+ }
+ }
+
+ return ret;
+ }
+
+ FieldList GetFieldsWithoutTypes(std::set<std::string> field_types) const {
+ FieldList ret;
+
+ for (const auto& field : field_list_) {
+ if (field_types.find(field->GetFieldType()) == field_types.end()) {
+ ret.AppendField(field);
+ }
+ }
+
+ return ret;
+ }
+
+ // Appends header fields of param to header fields of the current and
+ // prepends footer fields of the param to footer fields of the current.
+ // Ex. Assuming field_list_X has the layout:
+ // field_list_X_header
+ // payload/body
+ // field_list_X_footer
+ // The call to field_list_1.Merge(field_list_2) would result in
+ // field_list_1_header
+ // field_list_2_header
+ // payload/body (uses whatever was in field_list_2)
+ // field_list_2_footer
+ // field_list_1_footer
+ FieldList Merge(FieldList nested) const {
+ FieldList ret;
+
+ for (const auto& field : GetFieldsBeforePayloadOrBody()) {
+ ret.AppendField(field);
+ }
+
+ for (const auto& field : nested) {
+ ret.AppendField(field);
+ }
+
+ for (const auto& field : GetFieldsAfterPayloadOrBody()) {
+ ret.AppendField(field);
+ }
+
+ return ret;
+ }
+
+ bool HasPayloadOrBody() const {
+ return has_payload_ || has_body_;
+ }
+
+ bool HasPayload() const {
+ return has_payload_;
+ }
+
+ bool HasBody() const {
+ return has_body_;
+ }
+
+ FieldListIterator begin() const {
+ return field_list_.begin();
+ }
+
+ FieldListIterator end() const {
+ return field_list_.end();
+ }
+
+ ReverseFieldListIterator rbegin() const {
+ return field_list_.rbegin();
+ }
+
+ ReverseFieldListIterator rend() const {
+ return field_list_.rend();
+ }
+
+ size_t size() const {
+ return field_list_.size();
+ }
+
+ private:
+ void AddField(PacketField* field) {
+ if (field_map_.find(field->GetName()) != field_map_.end()) {
+ ERROR(field) << "Field with name \"" << field->GetName() << "\" was previously defined.\n";
+ }
+
+ if (field->GetFieldType() == PayloadField::kFieldType) {
+ if (has_body_) {
+ ERROR(field) << "Packet already has a body.";
+ }
+ has_payload_ = true;
+ }
+
+ if (field->GetFieldType() == BodyField::kFieldType) {
+ if (has_payload_) {
+ ERROR(field) << "Packet already has a payload.";
+ }
+ has_body_ = true;
+ }
+
+ field_map_.insert(std::pair(field->GetName(), field));
+ }
+
+ std::vector<PacketField*> field_list_;
+ std::map<std::string, PacketField*> field_map_;
+ bool has_payload_ = false;
+ bool has_body_ = false;
+};
diff --git a/gd/packet/parser/fields/all_fields.h b/gd/packet/parser/fields/all_fields.h
new file mode 100644
index 0000000..8c0aeee
--- /dev/null
+++ b/gd/packet/parser/fields/all_fields.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "fields/array_field.h"
+#include "fields/body_field.h"
+#include "fields/checksum_field.h"
+#include "fields/checksum_start_field.h"
+#include "fields/count_field.h"
+#include "fields/custom_field.h"
+#include "fields/custom_field_fixed_size.h"
+#include "fields/enum_field.h"
+#include "fields/fixed_enum_field.h"
+#include "fields/fixed_scalar_field.h"
+#include "fields/group_field.h"
+#include "fields/padding_field.h"
+#include "fields/payload_field.h"
+#include "fields/reserved_field.h"
+#include "fields/scalar_field.h"
+#include "fields/size_field.h"
+#include "fields/struct_field.h"
+#include "fields/variable_length_struct_field.h"
+#include "fields/vector_field.h"
diff --git a/gd/packet/parser/fields/array_field.cc b/gd/packet/parser/fields/array_field.cc
new file mode 100644
index 0000000..37dea16
--- /dev/null
+++ b/gd/packet/parser/fields/array_field.cc
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2019 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 "fields/array_field.h"
+
+#include "fields/custom_field.h"
+#include "fields/scalar_field.h"
+#include "util.h"
+
+const std::string ArrayField::kFieldType = "ArrayField";
+
+ArrayField::ArrayField(std::string name, int element_size, int array_size, ParseLocation loc)
+ : PacketField(name, loc), element_field_(new ScalarField("val", element_size, loc)), element_size_(element_size),
+ array_size_(array_size) {
+ if (element_size > 64 || element_size < 0)
+ ERROR(this) << __func__ << ": Not implemented for element size = " << element_size;
+ if (element_size % 8 != 0) {
+ ERROR(this) << "Can only have arrays with elements that are byte aligned (" << element_size << ")";
+ }
+}
+
+ArrayField::ArrayField(std::string name, TypeDef* type_def, int array_size, ParseLocation loc)
+ : PacketField(name, loc), element_field_(type_def->GetNewField("val", loc)),
+ element_size_(element_field_->GetSize()), array_size_(array_size) {
+ if (!element_size_.empty() && element_size_.bits() % 8 != 0) {
+ ERROR(this) << "Can only have arrays with elements that are byte aligned (" << element_size_ << ")";
+ }
+}
+
+const std::string& ArrayField::GetFieldType() const {
+ return ArrayField::kFieldType;
+}
+
+Size ArrayField::GetSize() const {
+ if (!element_size_.empty() && !element_size_.has_dynamic()) {
+ return Size(array_size_ * element_size_.bits());
+ }
+ return Size();
+}
+
+Size ArrayField::GetBuilderSize() const {
+ if (!element_size_.empty() && !element_size_.has_dynamic()) {
+ return GetSize();
+ } else if (element_field_->BuilderParameterMustBeMoved()) {
+ std::string ret = "[this](){ size_t length = 0; for (const auto& elem : " + GetName() +
+ "_) { length += elem->size() * 8; } return length; }()";
+ return ret;
+ } else {
+ std::string ret = "[this](){ size_t length = 0; for (const auto& elem : " + GetName() +
+ "_) { length += elem.size() * 8; } return length; }()";
+ return ret;
+ }
+}
+
+Size ArrayField::GetStructSize() const {
+ if (!element_size_.empty() && !element_size_.has_dynamic()) {
+ return GetSize();
+ } else if (element_field_->BuilderParameterMustBeMoved()) {
+ std::string ret = "[this](){ size_t length = 0; for (const auto& elem : to_fill->" + GetName() +
+ "_) { length += elem->size() * 8; } return length; }()";
+ return ret;
+ } else {
+ std::string ret = "[this](){ size_t length = 0; for (const auto& elem : to_fill->" + GetName() +
+ "_) { length += elem.size() * 8; } return length; }()";
+ return ret;
+ }
+}
+
+std::string ArrayField::GetDataType() const {
+ return "std::array<" + element_field_->GetDataType() + "," + std::to_string(array_size_) + ">";
+}
+
+void ArrayField::GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const {
+ s << GetDataType() << "::iterator ret_it = " << GetName() << "_ptr->begin();";
+ s << "auto " << element_field_->GetName() << "_it = " << GetName() << "_it;";
+ if (!element_size_.empty()) {
+ s << "while (" << element_field_->GetName() << "_it.NumBytesRemaining() >= " << element_size_.bytes();
+ s << " && ret_it < " << GetName() << "_ptr->end()) {";
+ } else {
+ s << "while (" << element_field_->GetName() << "_it.NumBytesRemaining() > 0 ";
+ s << " && ret_it < " << GetName() << "_ptr->end()) {";
+ }
+ if (element_field_->BuilderParameterMustBeMoved()) {
+ s << element_field_->GetDataType() << " " << element_field_->GetName() << "_ptr;";
+ } else {
+ s << element_field_->GetDataType() << "* " << element_field_->GetName() << "_ptr = ret_it;";
+ }
+ element_field_->GenExtractor(s, num_leading_bits, for_struct);
+ if (element_field_->BuilderParameterMustBeMoved()) {
+ s << "*ret_it = std::move(" << element_field_->GetName() << "_ptr);";
+ }
+ s << "ret_it++;";
+ s << "}";
+}
+
+std::string ArrayField::GetGetterFunctionName() const {
+ std::stringstream ss;
+ ss << "Get" << util::UnderscoreToCamelCase(GetName());
+ return ss.str();
+}
+
+void ArrayField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
+ s << GetDataType() << " " << GetGetterFunctionName() << "() {";
+ s << "ASSERT(was_validated_);";
+ s << "size_t end_index = size();";
+ s << "auto to_bound = begin();";
+
+ int num_leading_bits = GenBounds(s, start_offset, end_offset, GetSize());
+ s << GetDataType() << " " << GetName() << "_value;";
+ s << GetDataType() << "* " << GetName() << "_ptr = &" << GetName() << "_value;";
+ GenExtractor(s, num_leading_bits, false);
+
+ s << "return " << GetName() << "_value;";
+ s << "}\n";
+}
+
+std::string ArrayField::GetBuilderParameterType() const {
+ std::stringstream ss;
+ if (element_field_->BuilderParameterMustBeMoved()) {
+ ss << "std::array<" << element_field_->GetDataType() << "," << array_size_ << ">";
+ } else {
+ ss << "const std::array<" << element_field_->GetDataType() << "," << array_size_ << ">&";
+ }
+ return ss.str();
+}
+
+bool ArrayField::BuilderParameterMustBeMoved() const {
+ return element_field_->BuilderParameterMustBeMoved();
+}
+
+bool ArrayField::GenBuilderMember(std::ostream& s) const {
+ s << "std::array<" << element_field_->GetDataType() << "," << array_size_ << "> " << GetName();
+ return true;
+}
+
+bool ArrayField::HasParameterValidator() const {
+ return false;
+}
+
+void ArrayField::GenParameterValidator(std::ostream&) const {
+ // Array length is validated by the compiler
+}
+
+void ArrayField::GenInserter(std::ostream& s) const {
+ s << "for (const auto& val_ : " << GetName() << "_) {";
+ element_field_->GenInserter(s);
+ s << "}\n";
+}
+
+void ArrayField::GenValidator(std::ostream&) const {
+ // NOTE: We could check if the element size divides cleanly into the array size, but we decided to forgo that
+ // in favor of just returning as many elements as possible in a best effort style.
+ //
+ // Other than that there is nothing that arrays need to be validated on other than length so nothing needs to
+ // be done here.
+}
+
+bool ArrayField::IsContainerField() const {
+ return true;
+}
+
+const PacketField* ArrayField::GetElementField() const {
+ return element_field_;
+}
diff --git a/gd/packet/parser/fields/array_field.h b/gd/packet/parser/fields/array_field.h
new file mode 100644
index 0000000..dd49f26
--- /dev/null
+++ b/gd/packet/parser/fields/array_field.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "fields/packet_field.h"
+#include "parse_location.h"
+#include "type_def.h"
+
+class ArrayField : public PacketField {
+ public:
+ ArrayField(std::string name, int element_size, int fixed_size, ParseLocation loc);
+
+ ArrayField(std::string name, TypeDef* type_def, int fixed_size, ParseLocation loc);
+
+ static const std::string kFieldType;
+
+ virtual const std::string& GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual Size GetBuilderSize() const override;
+
+ virtual Size GetStructSize() const override;
+
+ virtual std::string GetDataType() const override;
+
+ virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+ virtual std::string GetGetterFunctionName() const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual std::string GetBuilderParameterType() const override;
+
+ virtual bool BuilderParameterMustBeMoved() const override;
+
+ virtual bool GenBuilderMember(std::ostream& s) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream& s) const override;
+
+ virtual void GenInserter(std::ostream& s) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ virtual bool IsContainerField() const override;
+
+ virtual const PacketField* GetElementField() const override;
+
+ const std::string name_;
+
+ const PacketField* element_field_{nullptr};
+
+ const Size element_size_{};
+
+ const int array_size_{-1};
+};
diff --git a/gd/packet/parser/fields/body_field.cc b/gd/packet/parser/fields/body_field.cc
new file mode 100644
index 0000000..5e00b68
--- /dev/null
+++ b/gd/packet/parser/fields/body_field.cc
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2019 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 "fields/body_field.h"
+
+const std::string BodyField::kFieldType = "BodyField";
+
+BodyField::BodyField(ParseLocation loc) : PacketField("body", loc) {}
+
+const std::string& BodyField::GetFieldType() const {
+ return BodyField::kFieldType;
+}
+
+Size BodyField::GetSize() const {
+ return Size(0);
+}
+
+std::string BodyField::GetDataType() const {
+ ERROR(this) << "No need to know the type of a body field.";
+ return "BodyType";
+}
+
+void BodyField::GenExtractor(std::ostream&, int, bool) const {}
+
+std::string BodyField::GetGetterFunctionName() const {
+ return "";
+}
+
+void BodyField::GenGetter(std::ostream&, Size, Size) const {}
+
+std::string BodyField::GetBuilderParameterType() const {
+ return "";
+}
+
+bool BodyField::HasParameterValidator() const {
+ return false;
+}
+
+void BodyField::GenParameterValidator(std::ostream&) const {
+ // There is no validation needed for a payload
+}
+
+void BodyField::GenInserter(std::ostream&) const {
+ // Do nothing
+}
+
+void BodyField::GenValidator(std::ostream&) const {
+ // Do nothing
+}
diff --git a/gd/packet/parser/fields/body_field.h b/gd/packet/parser/fields/body_field.h
new file mode 100644
index 0000000..ce4ede7
--- /dev/null
+++ b/gd/packet/parser/fields/body_field.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "fields/packet_field.h"
+#include "fields/size_field.h"
+#include "parse_location.h"
+
+class BodyField : public PacketField {
+ public:
+ BodyField(ParseLocation loc);
+
+ static const std::string kFieldType;
+
+ virtual const std::string& GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual std::string GetDataType() const override;
+
+ virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+ virtual std::string GetGetterFunctionName() const override;
+
+ virtual void GenGetter(std::ostream&, Size, Size) const override;
+
+ virtual std::string GetBuilderParameterType() const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream&) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+};
diff --git a/gd/packet/parser/fields/checksum_field.cc b/gd/packet/parser/fields/checksum_field.cc
new file mode 100644
index 0000000..4647992
--- /dev/null
+++ b/gd/packet/parser/fields/checksum_field.cc
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019 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 "fields/checksum_field.h"
+#include "util.h"
+
+const std::string ChecksumField::kFieldType = "ChecksumField";
+
+ChecksumField::ChecksumField(std::string name, std::string type_name, int size, ParseLocation loc)
+ : ScalarField(name, size, loc), type_name_(type_name) {}
+
+const std::string& ChecksumField::GetFieldType() const {
+ return ChecksumField::kFieldType;
+}
+
+std::string ChecksumField::GetDataType() const {
+ return type_name_;
+}
+
+void ChecksumField::GenExtractor(std::ostream&, int, bool) const {}
+
+std::string ChecksumField::GetGetterFunctionName() const {
+ return "";
+}
+
+void ChecksumField::GenGetter(std::ostream&, Size, Size) const {}
+
+bool ChecksumField::GenBuilderParameter(std::ostream&) const {
+ return false;
+}
+
+bool ChecksumField::HasParameterValidator() const {
+ return false;
+}
+
+void ChecksumField::GenParameterValidator(std::ostream&) const {
+ // Do nothing.
+}
+
+void ChecksumField::GenInserter(std::ostream& s) const {
+ s << "packet::ByteObserver observer = i.UnregisterObserver();";
+ s << "insert(static_cast<" << util::GetTypeForSize(GetSize().bits()) << ">(observer.GetValue()), i);";
+}
+
+void ChecksumField::GenValidator(std::ostream&) const {
+ // Done in packet_def.cc
+}
diff --git a/gd/packet/parser/fields/checksum_field.h b/gd/packet/parser/fields/checksum_field.h
new file mode 100644
index 0000000..c15f023
--- /dev/null
+++ b/gd/packet/parser/fields/checksum_field.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "fields/packet_field.h"
+#include "fields/scalar_field.h"
+#include "parse_location.h"
+
+class ChecksumField : public ScalarField {
+ public:
+ ChecksumField(std::string name, std::string type_name, int size, ParseLocation loc);
+
+ static const std::string kFieldType;
+
+ virtual const std::string& GetFieldType() const override;
+
+ virtual std::string GetDataType() const override;
+
+ virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+ virtual std::string GetGetterFunctionName() const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual bool GenBuilderParameter(std::ostream& s) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream& s) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ private:
+ std::string type_name_;
+};
diff --git a/gd/packet/parser/fields/checksum_start_field.cc b/gd/packet/parser/fields/checksum_start_field.cc
new file mode 100644
index 0000000..5531c5a
--- /dev/null
+++ b/gd/packet/parser/fields/checksum_start_field.cc
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2019 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 "fields/checksum_start_field.h"
+#include "util.h"
+
+const std::string ChecksumStartField::kFieldType = "ChecksumStartField";
+
+ChecksumStartField::ChecksumStartField(std::string name, ParseLocation loc)
+ : PacketField(name + "_start", loc), started_field_name_(name) {}
+
+const std::string& ChecksumStartField::GetFieldType() const {
+ return ChecksumStartField::kFieldType;
+}
+
+Size ChecksumStartField::GetSize() const {
+ return Size(0);
+}
+
+std::string ChecksumStartField::GetDataType() const {
+ return "There's no type for Checksum Start fields";
+}
+
+void ChecksumStartField::GenExtractor(std::ostream&, int, bool) const {}
+
+std::string ChecksumStartField::GetGetterFunctionName() const {
+ return "";
+}
+
+void ChecksumStartField::GenGetter(std::ostream&, Size, Size) const {}
+
+std::string ChecksumStartField::GetBuilderParameterType() const {
+ return "";
+}
+
+bool ChecksumStartField::HasParameterValidator() const {
+ return false;
+}
+
+void ChecksumStartField::GenParameterValidator(std::ostream&) const {}
+
+void ChecksumStartField::GenInserter(std::ostream&) const {
+ ERROR(this) << __func__ << ": This should not be called for checksum start fields";
+}
+
+void ChecksumStartField::GenValidator(std::ostream&) const {}
+
+std::string ChecksumStartField::GetStartedFieldName() const {
+ return started_field_name_;
+}
diff --git a/gd/packet/parser/fields/checksum_start_field.h b/gd/packet/parser/fields/checksum_start_field.h
new file mode 100644
index 0000000..c63806b
--- /dev/null
+++ b/gd/packet/parser/fields/checksum_start_field.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "fields/packet_field.h"
+#include "parse_location.h"
+
+class ChecksumStartField : public PacketField {
+ public:
+ ChecksumStartField(std::string name, ParseLocation loc);
+
+ static const std::string kFieldType;
+
+ std::string GetField() const;
+
+ virtual const std::string& GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual std::string GetDataType() const override;
+
+ virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+ virtual std::string GetGetterFunctionName() const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual std::string GetBuilderParameterType() const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream&) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ virtual std::string GetStartedFieldName() const;
+
+ private:
+ std::string started_field_name_;
+};
diff --git a/gd/packet/parser/fields/count_field.cc b/gd/packet/parser/fields/count_field.cc
new file mode 100644
index 0000000..8e1cf09
--- /dev/null
+++ b/gd/packet/parser/fields/count_field.cc
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2019 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 "fields/count_field.h"
+#include "util.h"
+
+const std::string CountField::kFieldType = "CountField";
+
+CountField::CountField(std::string name, int size, ParseLocation loc)
+ : ScalarField(name + "_count", size, loc), sized_field_name_(name) {}
+
+const std::string& CountField::GetFieldType() const {
+ return CountField::kFieldType;
+}
+
+void CountField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
+ s << "protected:";
+ ScalarField::GenGetter(s, start_offset, end_offset);
+ s << "public:\n";
+}
+
+bool CountField::GenBuilderParameter(std::ostream&) const {
+ // There is no builder parameter for a size field
+ return false;
+}
+
+bool CountField::HasParameterValidator() const {
+ return false;
+}
+
+void CountField::GenParameterValidator(std::ostream&) const {
+ // There is no builder parameter for a size field
+ // TODO: Check if the payload fits in the packet?
+}
+
+void CountField::GenInserter(std::ostream&) const {
+ ERROR(this) << __func__ << ": This should not be called for count fields";
+}
+
+void CountField::GenValidator(std::ostream&) const {
+ // Do nothing since the fixed count fields will be handled specially.
+}
+
+std::string CountField::GetSizedFieldName() const {
+ return sized_field_name_;
+}
diff --git a/gd/packet/parser/fields/count_field.h b/gd/packet/parser/fields/count_field.h
new file mode 100644
index 0000000..c9cb673
--- /dev/null
+++ b/gd/packet/parser/fields/count_field.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "fields/packet_field.h"
+#include "fields/scalar_field.h"
+#include "parse_location.h"
+
+class CountField : public ScalarField {
+ public:
+ CountField(std::string name, int size, ParseLocation loc);
+
+ static const std::string kFieldType;
+
+ std::string GetField() const;
+
+ virtual const std::string& GetFieldType() const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual bool GenBuilderParameter(std::ostream&) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream&) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ virtual std::string GetSizedFieldName() const;
+
+ private:
+ int size_;
+ std::string sized_field_name_;
+};
diff --git a/gd/packet/parser/fields/custom_field.cc b/gd/packet/parser/fields/custom_field.cc
new file mode 100644
index 0000000..4e387f8
--- /dev/null
+++ b/gd/packet/parser/fields/custom_field.cc
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2019 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 "fields/custom_field.h"
+#include "util.h"
+
+const std::string CustomField::kFieldType = "CustomField";
+
+CustomField::CustomField(std::string name, std::string type_name, ParseLocation loc)
+ : PacketField(name, loc), type_name_(type_name) {}
+
+const std::string& CustomField::GetFieldType() const {
+ return CustomField::kFieldType;
+}
+
+Size CustomField::GetSize() const {
+ return Size();
+}
+
+Size CustomField::GetBuilderSize() const {
+ std::string ret = "(" + GetName() + "_.size() * 8) ";
+ return ret;
+}
+
+std::string CustomField::GetDataType() const {
+ return type_name_;
+}
+
+void CustomField::GenExtractor(std::ostream& s, int, bool) const {
+ s << "auto optional_it = ";
+ s << GetDataType() << "::Parse( " << GetName() << "_ptr, " << GetName() << "_it);";
+ s << "if (optional_it) {";
+ s << GetName() << "_it = *optional_it;";
+ s << "} else {";
+ s << GetName() << "_it = " << GetName() << "_it + " << GetName() << "_it.NumBytesRemaining();";
+ s << GetName() << "_ptr = nullptr;";
+ s << "}";
+}
+
+std::string CustomField::GetGetterFunctionName() const {
+ std::stringstream ss;
+ ss << "Get" << util::UnderscoreToCamelCase(GetName());
+ return ss.str();
+}
+
+void CustomField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
+ s << "std::unique_ptr<" << GetDataType() << "> " << GetGetterFunctionName() << "() const {";
+ s << "ASSERT(was_validated_);";
+ s << "size_t end_index = size();";
+ s << "auto to_bound = begin();";
+
+ int num_leading_bits = GenBounds(s, start_offset, end_offset, GetSize());
+ s << "std::unique_ptr<" << GetDataType() << "> " << GetName() << "_value";
+ s << " = std::make_unique<" << GetDataType() << ">();";
+ s << GetDataType() << "* " << GetName() << "_ptr = " << GetName() << "_value.get();";
+ GenExtractor(s, num_leading_bits, false);
+ s << "if (" << GetName() << "_ptr == nullptr) {" << GetName() << "_value.reset(); }";
+ s << "return " << GetName() << "_value;";
+ s << "}\n";
+}
+
+std::string CustomField::GetBuilderParameterType() const {
+ return GetDataType();
+}
+
+bool CustomField::HasParameterValidator() const {
+ return false;
+}
+
+void CustomField::GenParameterValidator(std::ostream&) const {
+ // Do nothing.
+}
+
+void CustomField::GenInserter(std::ostream& s) const {
+ s << GetName() << "_.Serialize(i);";
+}
+
+void CustomField::GenValidator(std::ostream&) const {
+ // Do nothing.
+}
diff --git a/gd/packet/parser/fields/custom_field.h b/gd/packet/parser/fields/custom_field.h
new file mode 100644
index 0000000..621a3c8
--- /dev/null
+++ b/gd/packet/parser/fields/custom_field.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "fields/packet_field.h"
+#include "parse_location.h"
+
+class CustomField : public PacketField {
+ public:
+ CustomField(std::string name, std::string type_name, ParseLocation loc);
+
+ static const std::string kFieldType;
+
+ virtual const std::string& GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual Size GetBuilderSize() const override;
+
+ virtual std::string GetDataType() const override;
+
+ virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+ virtual std::string GetGetterFunctionName() const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual std::string GetBuilderParameterType() const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream& s) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ private:
+ std::string type_name_;
+};
diff --git a/gd/packet/parser/fields/custom_field_fixed_size.cc b/gd/packet/parser/fields/custom_field_fixed_size.cc
new file mode 100644
index 0000000..687d48d
--- /dev/null
+++ b/gd/packet/parser/fields/custom_field_fixed_size.cc
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2019 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 "fields/custom_field_fixed_size.h"
+#include "util.h"
+
+const std::string CustomFieldFixedSize::kFieldType = "CustomField";
+
+CustomFieldFixedSize::CustomFieldFixedSize(std::string name, std::string type_name, int size, ParseLocation loc)
+ : ScalarField(name, size, loc), type_name_(type_name) {}
+
+const std::string& CustomFieldFixedSize::GetFieldType() const {
+ return CustomFieldFixedSize::kFieldType;
+}
+
+std::string CustomFieldFixedSize::GetDataType() const {
+ return type_name_;
+}
+
+int CustomFieldFixedSize::GenBounds(std::ostream& s, Size start_offset, Size end_offset, Size size) const {
+ if (!start_offset.empty()) {
+ // Default to start if available.
+ s << "auto " << GetName() << "_it = to_bound + (" << start_offset << ") / 8;";
+ } else if (!end_offset.empty()) {
+ Size byte_offset = size + end_offset;
+ s << "auto " << GetName() << "_it = to_bound (+ to_bound.NumBytesRemaining() - (" << byte_offset << ") / 8);";
+ } else {
+ ERROR(this) << "Ambiguous offset for field.";
+ }
+ return 0; // num_leading_bits
+}
+
+void CustomFieldFixedSize::GenExtractor(std::ostream& s, int, bool) const {
+ s << "*" << GetName() << "_ptr = " << GetName() << "_it.extract<" << GetDataType() << ">();";
+}
+
+bool CustomFieldFixedSize::HasParameterValidator() const {
+ return false;
+}
+
+void CustomFieldFixedSize::GenParameterValidator(std::ostream&) const {
+ // Do nothing.
+}
+
+void CustomFieldFixedSize::GenInserter(std::ostream& s) const {
+ s << "insert(" << GetName() << "_, i);";
+}
+
+void CustomFieldFixedSize::GenValidator(std::ostream&) const {
+ // Do nothing.
+}
diff --git a/gd/packet/parser/fields/custom_field_fixed_size.h b/gd/packet/parser/fields/custom_field_fixed_size.h
new file mode 100644
index 0000000..97acff9
--- /dev/null
+++ b/gd/packet/parser/fields/custom_field_fixed_size.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "fields/scalar_field.h"
+#include "parse_location.h"
+
+class CustomFieldFixedSize : public ScalarField {
+ public:
+ CustomFieldFixedSize(std::string name, std::string type_name, int size, ParseLocation loc);
+
+ static const std::string kFieldType;
+
+ virtual const std::string& GetFieldType() const override;
+
+ virtual std::string GetDataType() const override;
+
+ virtual int GenBounds(std::ostream& s, Size start_offset, Size end_offset, Size size) const override;
+
+ virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream& s) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ std::string type_name_;
+};
diff --git a/gd/packet/parser/fields/enum_field.cc b/gd/packet/parser/fields/enum_field.cc
new file mode 100644
index 0000000..3080d43
--- /dev/null
+++ b/gd/packet/parser/fields/enum_field.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 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 "fields/enum_field.h"
+
+#include "util.h"
+
+const std::string EnumField::kFieldType = "EnumField";
+
+EnumField::EnumField(std::string name, EnumDef enum_def, std::string value, ParseLocation loc)
+ : ScalarField(name, enum_def.size_, loc), enum_def_(enum_def), value_(value) {}
+
+const std::string& EnumField::GetFieldType() const {
+ return EnumField::kFieldType;
+}
+
+EnumDef EnumField::GetEnumDef() {
+ return enum_def_;
+}
+
+std::string EnumField::GetDataType() const {
+ return enum_def_.name_;
+}
+
+bool EnumField::HasParameterValidator() const {
+ return false;
+}
+
+void EnumField::GenParameterValidator(std::ostream&) const {
+ // Validated at compile time.
+}
+
+void EnumField::GenInserter(std::ostream& s) const {
+ s << "insert(static_cast<" << util::GetTypeForSize(GetSize().bits()) << ">(";
+ s << GetName() << "_), i, " << GetSize().bits() << ");";
+}
+
+void EnumField::GenValidator(std::ostream&) const {
+ // Do nothing
+}
diff --git a/gd/packet/parser/fields/enum_field.h b/gd/packet/parser/fields/enum_field.h
new file mode 100644
index 0000000..11c64e0
--- /dev/null
+++ b/gd/packet/parser/fields/enum_field.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "enum_def.h"
+#include "fields/packet_field.h"
+#include "fields/scalar_field.h"
+#include "parse_location.h"
+
+class EnumField : public ScalarField {
+ public:
+ EnumField(std::string name, EnumDef enum_def, std::string value, ParseLocation loc);
+
+ EnumDef GetEnumDef();
+
+ static const std::string kFieldType;
+
+ virtual const std::string& GetFieldType() const override;
+
+ virtual std::string GetDataType() const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream& s) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ private:
+ EnumDef enum_def_;
+ std::string value_;
+};
diff --git a/gd/packet/parser/fields/fixed_enum_field.cc b/gd/packet/parser/fields/fixed_enum_field.cc
new file mode 100644
index 0000000..0cc35c0
--- /dev/null
+++ b/gd/packet/parser/fields/fixed_enum_field.cc
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2019 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 "fields/fixed_enum_field.h"
+#include "util.h"
+
+const std::string FixedEnumField::kFieldType = "FixedEnumField";
+
+FixedEnumField::FixedEnumField(EnumDef* enum_def, std::string value, ParseLocation loc)
+ : FixedField("fixed_enum", enum_def->size_, loc), enum_(enum_def), value_(value) {}
+
+const std::string& FixedEnumField::GetFieldType() const {
+ return FixedEnumField::kFieldType;
+}
+
+std::string FixedEnumField::GetDataType() const {
+ return enum_->name_;
+}
+
+void FixedEnumField::GenValue(std::ostream& s) const {
+ s << enum_->name_ << "::" << value_;
+}
diff --git a/gd/packet/parser/fields/fixed_enum_field.h b/gd/packet/parser/fields/fixed_enum_field.h
new file mode 100644
index 0000000..2c6c3f3
--- /dev/null
+++ b/gd/packet/parser/fields/fixed_enum_field.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <variant>
+
+#include "enum_def.h"
+#include "fields/fixed_field.h"
+#include "fields/packet_field.h"
+#include "parse_location.h"
+
+class FixedEnumField : public FixedField {
+ public:
+ FixedEnumField(EnumDef* enum_def, std::string value, ParseLocation loc);
+
+ static const std::string kFieldType;
+
+ virtual const std::string& GetFieldType() const override;
+
+ virtual std::string GetDataType() const override;
+
+ static const std::string field_type;
+
+ private:
+ void GenValue(std::ostream& s) const;
+
+ EnumDef* enum_;
+ std::string value_;
+};
diff --git a/gd/packet/parser/fields/fixed_field.cc b/gd/packet/parser/fields/fixed_field.cc
new file mode 100644
index 0000000..c728797
--- /dev/null
+++ b/gd/packet/parser/fields/fixed_field.cc
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 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 "fields/fixed_field.h"
+#include "util.h"
+
+int FixedField::unique_id_ = 0;
+
+FixedField::FixedField(std::string name, int size, ParseLocation loc)
+ : ScalarField(name + std::to_string(unique_id_++), size, loc) {}
+
+void FixedField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
+ s << "protected:";
+ ScalarField::GenGetter(s, start_offset, end_offset);
+ s << "public:\n";
+}
+
+bool FixedField::GenBuilderParameter(std::ostream&) const {
+ // No parameter needed for a fixed field.
+ return false;
+}
+
+bool FixedField::HasParameterValidator() const {
+ return false;
+}
+
+void FixedField::GenParameterValidator(std::ostream&) const {
+ // No parameter validator needed for a fixed field.
+}
+
+void FixedField::GenInserter(std::ostream& s) const {
+ s << "insert(";
+ GenValue(s);
+ s << ", i , " << GetSize().bits() << ");";
+}
+
+void FixedField::GenValidator(std::ostream& s) const {
+ s << "if (Get" << util::UnderscoreToCamelCase(GetName()) << "() != ";
+ GenValue(s);
+ s << ") return false;";
+}
diff --git a/gd/packet/parser/fields/fixed_field.h b/gd/packet/parser/fields/fixed_field.h
new file mode 100644
index 0000000..41ffa0f
--- /dev/null
+++ b/gd/packet/parser/fields/fixed_field.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <variant>
+
+#include "enum_def.h"
+#include "fields/packet_field.h"
+#include "fields/scalar_field.h"
+#include "parse_location.h"
+
+class FixedField : public ScalarField {
+ public:
+ FixedField(std::string name, int size, ParseLocation loc);
+
+ static const std::string kFieldType;
+
+ virtual std::string GetDataType() const override = 0;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual bool GenBuilderParameter(std::ostream&) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream& s) const override;
+
+ virtual void GenValidator(std::ostream& s) const override;
+
+ private:
+ virtual void GenValue(std::ostream& s) const = 0;
+
+ static int unique_id_;
+};
diff --git a/gd/packet/parser/fields/fixed_scalar_field.cc b/gd/packet/parser/fields/fixed_scalar_field.cc
new file mode 100644
index 0000000..9bfdf0e
--- /dev/null
+++ b/gd/packet/parser/fields/fixed_scalar_field.cc
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2019 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 "fields/fixed_scalar_field.h"
+#include "util.h"
+
+const std::string FixedScalarField::kFieldType = "FixedScalarField";
+
+FixedScalarField::FixedScalarField(int size, int64_t value, ParseLocation loc)
+ : FixedField("fixed_scalar", size, loc), value_(value) {}
+
+const std::string& FixedScalarField::GetFieldType() const {
+ return FixedScalarField::kFieldType;
+}
+
+std::string FixedScalarField::GetDataType() const {
+ return util::GetTypeForSize(GetSize().bits());
+}
+
+void FixedScalarField::GenValue(std::ostream& s) const {
+ s << value_;
+}
diff --git a/gd/packet/parser/fields/fixed_scalar_field.h b/gd/packet/parser/fields/fixed_scalar_field.h
new file mode 100644
index 0000000..0070f6c
--- /dev/null
+++ b/gd/packet/parser/fields/fixed_scalar_field.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <variant>
+
+#include "enum_def.h"
+#include "fields/fixed_field.h"
+#include "fields/packet_field.h"
+#include "parse_location.h"
+
+class FixedScalarField : public FixedField {
+ public:
+ FixedScalarField(int size, int64_t value, ParseLocation loc);
+
+ static const std::string kFieldType;
+
+ virtual const std::string& GetFieldType() const override;
+
+ virtual std::string GetDataType() const override;
+
+ static const std::string field_type;
+
+ private:
+ void GenValue(std::ostream& s) const;
+
+ const int64_t value_;
+};
diff --git a/gd/packet/parser/fields/group_field.cc b/gd/packet/parser/fields/group_field.cc
new file mode 100644
index 0000000..6c9ade9
--- /dev/null
+++ b/gd/packet/parser/fields/group_field.cc
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2019 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 "fields/group_field.h"
+
+GroupField::GroupField(ParseLocation loc, std::list<PacketField*>* fields)
+ : PacketField("Groups have no name", loc), fields_(fields) {}
+
+GroupField::~GroupField() {
+ delete fields_;
+}
+
+const std::string GroupField::kFieldType = "GroupField";
+
+std::string GroupField::GetName() const {
+ ERROR(this) << "GetName should never be called.";
+ return "";
+}
+
+const std::string& GroupField::GetFieldType() const {
+ return GroupField::kFieldType;
+}
+
+Size GroupField::GetSize() const {
+ ERROR(this) << "GetSize should never be called.";
+ return Size();
+}
+
+std::string GroupField::GetDataType() const {
+ ERROR(this) << "GetType should never be called.";
+ return "";
+}
+
+void GroupField::GenExtractor(std::ostream&, int, bool) const {
+ ERROR(this) << "GenExtractor should never be called.";
+}
+
+std::string GroupField::GetGetterFunctionName() const {
+ ERROR(this) << "GetGetterFunctionName should never be called.";
+ return "";
+}
+
+void GroupField::GenGetter(std::ostream&, Size, Size) const {
+ ERROR(this) << "GenGetter should never be called.";
+}
+
+std::string GroupField::GetBuilderParameterType() const {
+ ERROR(this) << "GetBuilderParameterType should never be called";
+ return "";
+}
+
+bool GroupField::HasParameterValidator() const {
+ ERROR(this) << "HasParameterValidator should never be called";
+ return false;
+}
+
+void GroupField::GenParameterValidator(std::ostream&) const {
+ ERROR(this) << "Not implemented";
+}
+
+void GroupField::GenInserter(std::ostream&) const {
+ ERROR(this) << "GenInserter should never be called.";
+}
+
+void GroupField::GenValidator(std::ostream&) const {
+ ERROR(this) << "GenValidator should never be called.";
+}
+
+const std::list<PacketField*>* GroupField::GetFields() const {
+ return fields_;
+}
diff --git a/gd/packet/parser/fields/group_field.h b/gd/packet/parser/fields/group_field.h
new file mode 100644
index 0000000..57e0165
--- /dev/null
+++ b/gd/packet/parser/fields/group_field.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <list>
+
+#include "fields/packet_field.h"
+#include "parse_location.h"
+
+class GroupField : public PacketField {
+ public:
+ GroupField(ParseLocation loc, std::list<PacketField*>* fields);
+
+ ~GroupField();
+
+ virtual std::string GetName() const override;
+
+ static const std::string kFieldType;
+
+ virtual const std::string& GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual std::string GetDataType() const override;
+
+ virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+ virtual std::string GetGetterFunctionName() const override;
+
+ virtual void GenGetter(std::ostream&, Size, Size) const override;
+
+ virtual std::string GetBuilderParameterType() const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream&) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ const std::list<PacketField*>* GetFields() const;
+
+ private:
+ std::list<PacketField*>* fields_;
+};
diff --git a/gd/packet/parser/fields/packet_field.cc b/gd/packet/parser/fields/packet_field.cc
new file mode 100644
index 0000000..7b0bdb7
--- /dev/null
+++ b/gd/packet/parser/fields/packet_field.cc
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2019 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 "fields/packet_field.h"
+
+#include "util.h"
+
+PacketField::PacketField(std::string name, ParseLocation loc) : loc_(loc), name_(name) {}
+
+std::string PacketField::GetDebugName() const {
+ return "Field{Type:" + GetFieldType() + ", Name:" + GetName() + "}";
+}
+
+ParseLocation PacketField::GetLocation() const {
+ return loc_;
+}
+
+std::string PacketField::GetName() const {
+ return name_;
+}
+
+Size PacketField::GetBuilderSize() const {
+ return GetSize();
+}
+
+Size PacketField::GetStructSize() const {
+ return GetSize();
+}
+
+int PacketField::GenBounds(std::ostream& s, Size start_offset, Size end_offset, Size size) const {
+ // In order to find field_begin and field_end, we must have two of the three Sizes.
+ if ((start_offset.empty() && size.empty()) || (start_offset.empty() && end_offset.empty()) ||
+ (end_offset.empty() && size.empty())) {
+ ERROR(this) << "GenBounds called without enough information. " << start_offset << end_offset << size;
+ }
+
+ if (start_offset.bits() % 8 != 0 || end_offset.bits() % 8 != 0) {
+ ERROR(this) << "Can not find the bounds of a field at a non byte-aligned offset." << start_offset << end_offset;
+ }
+
+ if (!start_offset.empty()) {
+ s << "size_t field_begin = (" << start_offset << ") / 8;";
+ } else {
+ s << "size_t field_begin = end_index - (" << end_offset << " + " << size << ") / 8;";
+ }
+
+ if (!end_offset.empty()) {
+ s << "size_t field_end = end_index - (" << end_offset << ") / 8;";
+ // If the field has a known size, use the minimum for the end
+ if (!size.empty()) {
+ s << "size_t field_sized_end = field_begin + (" << size << ") / 8;";
+ s << "if (field_sized_end < field_end) { field_end = field_sized_end; }";
+ }
+ } else {
+ s << "size_t field_end = field_begin + (" << size << ") / 8;";
+ s << "if (field_end > end_index) { field_end = end_index; }";
+ }
+ s << "auto " << name_ << "_it = to_bound.Subrange(field_begin, field_end - field_begin); ";
+ return 0; // num_leading_bits
+}
+
+bool PacketField::GenBuilderParameter(std::ostream& s) const {
+ auto param_type = GetBuilderParameterType();
+ if (param_type.empty()) {
+ return false;
+ }
+ s << param_type << " " << GetName();
+ return true;
+}
+
+bool PacketField::BuilderParameterMustBeMoved() const {
+ return false;
+}
+
+bool PacketField::GenBuilderMember(std::ostream& s) const {
+ return GenBuilderParameter(s);
+}
+
+void PacketField::GenBuilderParameterFromView(std::ostream& s) const {
+ s << "view.Get" << util::UnderscoreToCamelCase(GetName()) << "()";
+}
+
+bool PacketField::IsContainerField() const {
+ return false;
+}
+
+const PacketField* PacketField::GetElementField() const {
+ return nullptr;
+}
diff --git a/gd/packet/parser/fields/packet_field.h b/gd/packet/parser/fields/packet_field.h
new file mode 100644
index 0000000..d369a92
--- /dev/null
+++ b/gd/packet/parser/fields/packet_field.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <iostream>
+#include <string>
+
+#include "logging.h"
+#include "parse_location.h"
+#include "size.h"
+
+// The base field that every packet needs to inherit from.
+class PacketField : public Loggable {
+ public:
+ virtual ~PacketField() = default;
+
+ PacketField(std::string name, ParseLocation loc);
+
+ // Get the type for this field.
+ virtual const std::string& GetFieldType() const = 0;
+
+ // Returns the size of the field in bits.
+ virtual Size GetSize() const = 0;
+
+ // Returns the size of the field in bits given the information in the builder.
+ // For most field types, this will be the same as GetSize();
+ virtual Size GetBuilderSize() const;
+
+ // Returns the size of the field in bits given the information in the parsed struct.
+ // For most field types, this will be the same as GetSize();
+ virtual Size GetStructSize() const;
+
+ // Get the type of the field to be used in the builders constructor and
+ // variables.
+ virtual std::string GetDataType() const = 0;
+
+ // Given an iterator {name}_it, extract the type.
+ virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const = 0;
+
+ // Calculate field_begin and field_end using the given offsets and size, return the number of leading bits
+ virtual int GenBounds(std::ostream& s, Size start_offset, Size end_offset, Size size) const;
+
+ // Get the name of the getter function, return empty string if there is a getter function
+ virtual std::string GetGetterFunctionName() const = 0;
+
+ // Get parser getter definition. Start_offset points to the first bit of the
+ // field. end_offset is the first bit after the field. If an offset is empty
+ // that means that there was a field with an unknown size when trying to
+ // calculate the offset.
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const = 0;
+
+ // Get the type of parameter used in Create(), return empty string if a parameter type was NOT generated
+ virtual std::string GetBuilderParameterType() const = 0;
+
+ // Generate the parameter for Create(), return true if a parameter was added.
+ virtual bool GenBuilderParameter(std::ostream& s) const;
+
+ // Return true if the Builder parameter has to be moved.
+ virtual bool BuilderParameterMustBeMoved() const;
+
+ // Generate the actual storage for the parameter, return true if it was added.
+ virtual bool GenBuilderMember(std::ostream& s) const;
+
+ // Helper for reflection tests.
+ virtual void GenBuilderParameterFromView(std::ostream& s) const;
+
+ // Returns whether or not the field must be validated.
+ virtual bool HasParameterValidator() const = 0;
+
+ // Fail if the value doesn't fit in the field.
+ virtual void GenParameterValidator(std::ostream& s) const = 0;
+
+ // Generate the inserter for pushing the data in the builder.
+ virtual void GenInserter(std::ostream& s) const = 0;
+
+ // Generate the validator for a field for the IsValid() function.
+ //
+ // The way this function works is by assuming that there is an iterator |it|
+ // that was defined earlier. The implementer of the function will then move
+ // it forward based on the dynamic size of the field and then check to see if
+ // its past the end of the packet.
+ // It should be unused for fixed size fields unless special consideration is
+ // needed. This is because all fixed size fields are tallied together with
+ // GetSize() and used as an initial offset. One special consideration is for
+ // enums where instead of checking if they can be read, they are checked to
+ // see if they contain the correct value.
+ virtual void GenValidator(std::ostream& s) const = 0;
+
+ // Some fields are containers of other fields, e.g. array, vector, etc.
+ // Assume STL containers that support swap()
+ virtual bool IsContainerField() const;
+
+ // Get field of nested elements if this is a container field, nullptr if none
+ virtual const PacketField* GetElementField() const;
+
+ std::string GetDebugName() const override;
+
+ ParseLocation GetLocation() const override;
+
+ virtual std::string GetName() const;
+
+ private:
+ ParseLocation loc_;
+ std::string name_;
+};
diff --git a/gd/packet/parser/fields/padding_field.cc b/gd/packet/parser/fields/padding_field.cc
new file mode 100644
index 0000000..5f438f8
--- /dev/null
+++ b/gd/packet/parser/fields/padding_field.cc
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2019 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 "fields/padding_field.h"
+#include "util.h"
+
+const std::string PaddingField::kFieldType = "PaddingField";
+
+PaddingField::PaddingField(int size, ParseLocation loc)
+ : PacketField("padding_" + std::to_string(size * 8), loc), size_(size * 8) {}
+
+const std::string& PaddingField::GetFieldType() const {
+ return PaddingField::kFieldType;
+}
+
+Size PaddingField::GetSize() const {
+ return size_;
+}
+
+Size PaddingField::GetBuilderSize() const {
+ return 0;
+}
+
+std::string PaddingField::GetDataType() const {
+ return "There's no type for Padding fields";
+}
+
+void PaddingField::GenExtractor(std::ostream&, int, bool) const {}
+
+std::string PaddingField::GetGetterFunctionName() const {
+ return "";
+}
+
+void PaddingField::GenGetter(std::ostream&, Size, Size) const {}
+
+std::string PaddingField::GetBuilderParameterType() const {
+ return "";
+}
+
+bool PaddingField::HasParameterValidator() const {
+ return false;
+}
+
+void PaddingField::GenParameterValidator(std::ostream&) const {}
+
+void PaddingField::GenInserter(std::ostream&) const {
+ ERROR(this) << __func__ << ": This should not be called for padding fields";
+}
+
+void PaddingField::GenValidator(std::ostream&) const {}
diff --git a/gd/packet/parser/fields/padding_field.h b/gd/packet/parser/fields/padding_field.h
new file mode 100644
index 0000000..bb99d42
--- /dev/null
+++ b/gd/packet/parser/fields/padding_field.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "fields/packet_field.h"
+#include "parse_location.h"
+
+class PaddingField : public PacketField {
+ public:
+ PaddingField(int size, ParseLocation loc);
+
+ static const std::string kFieldType;
+
+ std::string GetField() const;
+
+ virtual const std::string& GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual Size GetBuilderSize() const override;
+
+ virtual std::string GetDataType() const override;
+
+ virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+ virtual std::string GetGetterFunctionName() const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual std::string GetBuilderParameterType() const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream&) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ private:
+ Size size_;
+};
diff --git a/gd/packet/parser/fields/payload_field.cc b/gd/packet/parser/fields/payload_field.cc
new file mode 100644
index 0000000..c075996
--- /dev/null
+++ b/gd/packet/parser/fields/payload_field.cc
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2019 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 "fields/payload_field.h"
+#include "util.h"
+
+const std::string PayloadField::kFieldType = "PayloadField";
+
+PayloadField::PayloadField(std::string modifier, ParseLocation loc)
+ : PacketField("payload", loc), size_field_(nullptr), size_modifier_(modifier) {}
+
+void PayloadField::SetSizeField(const SizeField* size_field) {
+ if (size_field_ != nullptr) {
+ ERROR(this, size_field_, size_field) << "The size field for the payload has already been assigned.";
+ }
+
+ size_field_ = size_field;
+}
+
+const std::string& PayloadField::GetFieldType() const {
+ return PayloadField::kFieldType;
+}
+
+Size PayloadField::GetSize() const {
+ if (size_field_ == nullptr) {
+ if (!size_modifier_.empty()) {
+ ERROR(this) << "Missing size field for payload with size modifier.";
+ }
+ return Size();
+ }
+
+ std::string dynamic_size = "(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "() * 8)";
+ if (!size_modifier_.empty()) {
+ dynamic_size += "- (" + size_modifier_ + ")";
+ }
+
+ return dynamic_size;
+}
+
+std::string PayloadField::GetDataType() const {
+ return "PacketView";
+}
+
+void PayloadField::GenExtractor(std::ostream&, int, bool) const {
+ ERROR(this) << __func__ << " should never be called. ";
+}
+
+std::string PayloadField::GetGetterFunctionName() const {
+ return "GetPayload";
+}
+
+void PayloadField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
+ s << "PacketView<kLittleEndian> " << GetGetterFunctionName() << "() const {";
+ s << "ASSERT(was_validated_);";
+ s << "size_t end_index = size();";
+ s << "auto to_bound = begin();";
+ GenBounds(s, start_offset, end_offset, GetSize());
+ s << "return GetLittleEndianSubview(field_begin, field_end);";
+ s << "}\n\n";
+
+ s << "PacketView<!kLittleEndian> " << GetGetterFunctionName() << "BigEndian() const {";
+ s << "ASSERT(was_validated_);";
+ s << "size_t end_index = size();";
+ s << "auto to_bound = begin();";
+ GenBounds(s, start_offset, end_offset, GetSize());
+ s << "return GetBigEndianSubview(field_begin, field_end);";
+ s << "}\n";
+}
+
+std::string PayloadField::GetBuilderParameterType() const {
+ return "std::unique_ptr<BasePacketBuilder>";
+}
+
+bool PayloadField::BuilderParameterMustBeMoved() const {
+ return true;
+}
+
+void PayloadField::GenBuilderParameterFromView(std::ostream& s) const {
+ s << "std::make_unique<RawBuilder>(std::vector<uint8_t>(view.GetPayload().begin(), view.GetPayload().end()))";
+}
+
+bool PayloadField::HasParameterValidator() const {
+ return false;
+}
+
+void PayloadField::GenParameterValidator(std::ostream&) const {
+ // There is no validation needed for a payload
+}
+
+void PayloadField::GenInserter(std::ostream&) const {
+ ERROR() << __func__ << " Should never be called.";
+}
+
+void PayloadField::GenValidator(std::ostream&) const {
+ // Do nothing
+}
diff --git a/gd/packet/parser/fields/payload_field.h b/gd/packet/parser/fields/payload_field.h
new file mode 100644
index 0000000..11e6267
--- /dev/null
+++ b/gd/packet/parser/fields/payload_field.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "fields/packet_field.h"
+#include "fields/size_field.h"
+#include "parse_location.h"
+
+class PayloadField : public PacketField {
+ public:
+ PayloadField(std::string modifier, ParseLocation loc);
+
+ static const std::string kFieldType;
+
+ virtual const std::string& GetFieldType() const override;
+
+ void SetSizeField(const SizeField* size_field);
+
+ virtual Size GetSize() const override;
+
+ virtual std::string GetDataType() const override;
+
+ virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+ virtual std::string GetGetterFunctionName() const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual std::string GetBuilderParameterType() const override;
+
+ virtual bool BuilderParameterMustBeMoved() const override;
+
+ virtual void GenBuilderParameterFromView(std::ostream& s) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream&) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ // Payload fields can only be dynamically sized.
+ const SizeField* size_field_;
+ // Only used if the size of the payload is based on another field.
+ std::string size_modifier_;
+};
diff --git a/gd/packet/parser/fields/reserved_field.cc b/gd/packet/parser/fields/reserved_field.cc
new file mode 100644
index 0000000..0acf7b7
--- /dev/null
+++ b/gd/packet/parser/fields/reserved_field.cc
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2019 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 "fields/reserved_field.h"
+#include "util.h"
+
+int ReservedField::unique_id_ = 0;
+
+const std::string ReservedField::kFieldType = "ReservedField";
+
+ReservedField::ReservedField(int size, ParseLocation loc)
+ : PacketField("ReservedScalar" + std::to_string(unique_id_++), loc), size_(size) {}
+
+const std::string& ReservedField::GetFieldType() const {
+ return ReservedField::kFieldType;
+}
+
+Size ReservedField::GetSize() const {
+ return size_;
+}
+
+std::string ReservedField::GetDataType() const {
+ return util::GetTypeForSize(size_);
+}
+
+void ReservedField::GenExtractor(std::ostream&, int, bool) const {}
+
+std::string ReservedField::GetGetterFunctionName() const {
+ return "";
+}
+
+void ReservedField::GenGetter(std::ostream&, Size, Size) const {
+ // There is no Getter for a reserved field
+}
+
+std::string ReservedField::GetBuilderParameterType() const {
+ // There is no builder parameter for a reserved field
+ return "";
+}
+
+bool ReservedField::HasParameterValidator() const {
+ return false;
+}
+
+void ReservedField::GenParameterValidator(std::ostream&) const {
+ // There is no builder parameter for a reserved field
+}
+
+void ReservedField::GenInserter(std::ostream& s) const {
+ s << "insert(static_cast<" << util::GetTypeForSize(GetSize().bits()) << ">(0) /* Reserved */, i, " << GetSize().bits()
+ << " );\n";
+}
+
+void ReservedField::GenValidator(std::ostream&) const {
+ // There is no need to validate the value of a reserved field
+}
diff --git a/gd/packet/parser/fields/reserved_field.h b/gd/packet/parser/fields/reserved_field.h
new file mode 100644
index 0000000..7d36352
--- /dev/null
+++ b/gd/packet/parser/fields/reserved_field.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "fields/packet_field.h"
+#include "parse_location.h"
+
+class ReservedField : public PacketField {
+ public:
+ ReservedField(int size, ParseLocation loc);
+
+ static const std::string kFieldType;
+
+ virtual const std::string& GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual std::string GetDataType() const override;
+
+ virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+ virtual std::string GetGetterFunctionName() const override;
+
+ virtual void GenGetter(std::ostream&, Size, Size) const override;
+
+ virtual std::string GetBuilderParameterType() const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream& s) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ private:
+ std::string name_;
+ int size_;
+ static int unique_id_;
+};
diff --git a/gd/packet/parser/fields/scalar_field.cc b/gd/packet/parser/fields/scalar_field.cc
new file mode 100644
index 0000000..320534a
--- /dev/null
+++ b/gd/packet/parser/fields/scalar_field.cc
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2019 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 "fields/scalar_field.h"
+
+#include "util.h"
+
+const std::string ScalarField::kFieldType = "ScalarField";
+
+ScalarField::ScalarField(std::string name, int size, ParseLocation loc) : PacketField(name, loc), size_(size) {
+ if (size_ > 64 || size_ < 0) {
+ ERROR(this) << "Not implemented for size_ = " << size_;
+ }
+}
+
+const std::string& ScalarField::GetFieldType() const {
+ return ScalarField::kFieldType;
+}
+
+Size ScalarField::GetSize() const {
+ return size_;
+}
+
+std::string ScalarField::GetDataType() const {
+ return util::GetTypeForSize(size_);
+}
+
+int GetShiftBits(int i) {
+ int bits_past_byte_boundary = i % 8;
+ if (bits_past_byte_boundary == 0) {
+ return 0;
+ } else {
+ return 8 - bits_past_byte_boundary;
+ }
+}
+
+int ScalarField::GenBounds(std::ostream& s, Size start_offset, Size end_offset, Size size) const {
+ int num_leading_bits = 0;
+
+ if (!start_offset.empty()) {
+ // Default to start if available.
+ num_leading_bits = start_offset.bits() % 8;
+ s << "auto " << GetName() << "_it = to_bound + (" << start_offset << ") / 8;";
+ } else if (!end_offset.empty()) {
+ num_leading_bits = GetShiftBits(end_offset.bits() + size.bits());
+ Size byte_offset = Size(num_leading_bits + size.bits()) + end_offset;
+ s << "auto " << GetName() << "_it = to_bound + (to_bound.NumBytesRemaining() - (" << byte_offset << ") / 8);";
+ } else {
+ ERROR(this) << "Ambiguous offset for field.";
+ }
+ return num_leading_bits;
+}
+
+void ScalarField::GenExtractor(std::ostream& s, int num_leading_bits, bool) const {
+ Size size = GetSize();
+ // Extract the correct number of bytes. The return type could be different
+ // from the extract type if an earlier field causes the beginning of the
+ // current field to start in the middle of a byte.
+ std::string extract_type = util::GetTypeForSize(size.bits() + num_leading_bits);
+ s << "auto extracted_value = " << GetName() << "_it.extract<" << extract_type << ">();";
+
+ // Right shift the result to remove leading bits.
+ if (num_leading_bits != 0) {
+ s << "extracted_value >>= " << num_leading_bits << ";";
+ }
+ // Mask the result if necessary.
+ if (util::RoundSizeUp(size.bits()) != size.bits()) {
+ uint64_t mask = 0;
+ for (int i = 0; i < size.bits(); i++) {
+ mask <<= 1;
+ mask |= 1;
+ }
+ s << "extracted_value &= 0x" << std::hex << mask << std::dec << ";";
+ }
+ s << "*" << GetName() << "_ptr = static_cast<" << GetDataType() << ">(extracted_value);";
+}
+
+std::string ScalarField::GetGetterFunctionName() const {
+ std::stringstream ss;
+ ss << "Get" << util::UnderscoreToCamelCase(GetName());
+ return ss.str();
+}
+
+void ScalarField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
+ s << GetDataType() << " " << GetGetterFunctionName() << "() const {";
+ s << "ASSERT(was_validated_);";
+ s << "auto to_bound = begin();";
+ int num_leading_bits = GenBounds(s, start_offset, end_offset, GetSize());
+ s << GetDataType() << " " << GetName() << "_value;";
+ s << GetDataType() << "* " << GetName() << "_ptr = &" << GetName() << "_value;";
+ GenExtractor(s, num_leading_bits, false);
+ s << "return " << GetName() << "_value;";
+ s << "}";
+}
+
+std::string ScalarField::GetBuilderParameterType() const {
+ return GetDataType();
+}
+
+bool ScalarField::HasParameterValidator() const {
+ return util::RoundSizeUp(GetSize().bits()) != GetSize().bits();
+}
+
+void ScalarField::GenParameterValidator(std::ostream& s) const {
+ s << "ASSERT(" << GetName() << " < (static_cast<uint64_t>(1) << " << GetSize().bits() << "));";
+}
+
+void ScalarField::GenInserter(std::ostream& s) const {
+ if (GetSize().bits() == 8) {
+ s << "i.insert_byte(" << GetName() << "_);";
+ } else {
+ s << "insert(" << GetName() << "_, i," << GetSize().bits() << ");";
+ }
+}
+
+void ScalarField::GenValidator(std::ostream&) const {
+ // Do nothing
+}
diff --git a/gd/packet/parser/fields/scalar_field.h b/gd/packet/parser/fields/scalar_field.h
new file mode 100644
index 0000000..65f897e
--- /dev/null
+++ b/gd/packet/parser/fields/scalar_field.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "fields/packet_field.h"
+#include "parse_location.h"
+
+class ScalarField : public PacketField {
+ public:
+ ScalarField(std::string name, int size, ParseLocation loc);
+
+ static const std::string kFieldType;
+
+ virtual const std::string& GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual std::string GetDataType() const override;
+
+ virtual int GenBounds(std::ostream& s, Size start_offset, Size end_offset, Size size) const override;
+
+ virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+ virtual std::string GetGetterFunctionName() const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual std::string GetBuilderParameterType() const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream& s) const override;
+
+ virtual void GenInserter(std::ostream& s) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ private:
+ const int size_;
+};
diff --git a/gd/packet/parser/fields/size_field.cc b/gd/packet/parser/fields/size_field.cc
new file mode 100644
index 0000000..eafb139
--- /dev/null
+++ b/gd/packet/parser/fields/size_field.cc
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2019 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 "fields/size_field.h"
+#include "util.h"
+
+const std::string SizeField::kFieldType = "SizeField";
+
+SizeField::SizeField(std::string name, int size, ParseLocation loc)
+ : ScalarField(name + "_size", size, loc), sized_field_name_(name) {}
+
+const std::string& SizeField::GetFieldType() const {
+ return SizeField::kFieldType;
+}
+
+void SizeField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
+ s << "protected:";
+ ScalarField::GenGetter(s, start_offset, end_offset);
+ s << "public:\n";
+}
+
+bool SizeField::GenBuilderParameter(std::ostream&) const {
+ // There is no builder parameter for a size field
+ return false;
+}
+
+bool SizeField::HasParameterValidator() const {
+ return false;
+}
+
+void SizeField::GenParameterValidator(std::ostream&) const {
+ // There is no builder parameter for a size field
+ // TODO: Check if the payload fits in the packet?
+}
+
+void SizeField::GenInserter(std::ostream&) const {
+ ERROR(this) << __func__ << ": This should not be called for size fields";
+}
+
+void SizeField::GenValidator(std::ostream&) const {
+ // Do nothing since the fixed size fields will be handled specially.
+}
+
+std::string SizeField::GetSizedFieldName() const {
+ return sized_field_name_;
+}
diff --git a/gd/packet/parser/fields/size_field.h b/gd/packet/parser/fields/size_field.h
new file mode 100644
index 0000000..859be5a
--- /dev/null
+++ b/gd/packet/parser/fields/size_field.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "fields/packet_field.h"
+#include "fields/scalar_field.h"
+#include "parse_location.h"
+
+class SizeField : public ScalarField {
+ public:
+ SizeField(std::string name, int size, ParseLocation loc);
+
+ static const std::string kFieldType;
+
+ std::string GetField() const;
+
+ virtual const std::string& GetFieldType() const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual bool GenBuilderParameter(std::ostream&) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream&) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ virtual std::string GetSizedFieldName() const;
+
+ private:
+ int size_;
+ std::string sized_field_name_;
+};
diff --git a/gd/packet/parser/fields/struct_field.cc b/gd/packet/parser/fields/struct_field.cc
new file mode 100644
index 0000000..fbdafcf
--- /dev/null
+++ b/gd/packet/parser/fields/struct_field.cc
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2019 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 "fields/struct_field.h"
+#include "util.h"
+
+const std::string StructField::kFieldType = "StructField";
+
+StructField::StructField(std::string name, std::string type_name, Size size, ParseLocation loc)
+ : PacketField(name, loc), type_name_(type_name), size_(size) {}
+
+const std::string& StructField::GetFieldType() const {
+ return StructField::kFieldType;
+}
+
+Size StructField::GetSize() const {
+ return size_;
+}
+
+Size StructField::GetBuilderSize() const {
+ std::string ret = "(" + GetName() + "_.size() * 8)";
+ return ret;
+}
+
+std::string StructField::GetDataType() const {
+ return type_name_;
+}
+
+void StructField::GenExtractor(std::ostream& s, int, bool) const {
+ s << GetName() << "_it = ";
+ s << GetDataType() << "::Parse(" << GetName() << "_ptr, " << GetName() << "_it);";
+}
+
+std::string StructField::GetGetterFunctionName() const {
+ std::stringstream ss;
+ ss << "Get" << util::UnderscoreToCamelCase(GetName());
+ return ss.str();
+}
+
+void StructField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
+ s << GetDataType() << " " << GetGetterFunctionName() << "() const {";
+ s << "ASSERT(was_validated_);";
+ s << "size_t end_index = size();";
+ s << "auto to_bound = begin();";
+ int num_leading_bits = GenBounds(s, start_offset, end_offset, GetSize());
+ s << GetDataType() << " " << GetName() << "_value;";
+ s << GetDataType() << "* " << GetName() << "_ptr = &" << GetName() << "_value;";
+ GenExtractor(s, num_leading_bits, false);
+
+ s << "return " << GetName() << "_value;";
+ s << "}\n";
+}
+
+std::string StructField::GetBuilderParameterType() const {
+ return GetDataType();
+}
+
+bool StructField::HasParameterValidator() const {
+ return false;
+}
+
+void StructField::GenParameterValidator(std::ostream&) const {
+ // Validated at compile time.
+}
+
+void StructField::GenInserter(std::ostream& s) const {
+ s << GetName() << "_.Serialize(i);";
+}
+
+void StructField::GenValidator(std::ostream&) const {
+ // Do nothing
+}
diff --git a/gd/packet/parser/fields/struct_field.h b/gd/packet/parser/fields/struct_field.h
new file mode 100644
index 0000000..1f4f100
--- /dev/null
+++ b/gd/packet/parser/fields/struct_field.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "fields/packet_field.h"
+#include "parse_location.h"
+
+class StructField : public PacketField {
+ public:
+ StructField(std::string name, std::string type_name, Size size, ParseLocation loc);
+
+ static const std::string kFieldType;
+
+ virtual const std::string& GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual Size GetBuilderSize() const override;
+
+ virtual std::string GetDataType() const override;
+
+ virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+ virtual std::string GetGetterFunctionName() const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual std::string GetBuilderParameterType() const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream& s) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ private:
+ std::string type_name_;
+
+ public:
+ const Size size_{};
+};
diff --git a/gd/packet/parser/fields/variable_length_struct_field.cc b/gd/packet/parser/fields/variable_length_struct_field.cc
new file mode 100644
index 0000000..51a46e4
--- /dev/null
+++ b/gd/packet/parser/fields/variable_length_struct_field.cc
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2019 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 "fields/variable_length_struct_field.h"
+#include "util.h"
+
+const std::string VariableLengthStructField::kFieldType = "VariableLengthStructField";
+
+VariableLengthStructField::VariableLengthStructField(std::string name, std::string type_name, ParseLocation loc)
+ : PacketField(name, loc), type_name_(type_name) {}
+
+const std::string& VariableLengthStructField::GetFieldType() const {
+ return VariableLengthStructField::kFieldType;
+}
+
+Size VariableLengthStructField::GetSize() const {
+ return Size();
+}
+
+Size VariableLengthStructField::GetBuilderSize() const {
+ std::string ret = "(" + GetName() + "_->size() * 8) ";
+ return ret;
+}
+
+std::string VariableLengthStructField::GetDataType() const {
+ std::string ret = "std::unique_ptr<" + type_name_ + ">";
+ return ret;
+}
+
+void VariableLengthStructField::GenExtractor(std::ostream& s, int, bool) const {
+ s << GetName() << "_ptr = Parse" << type_name_ << "(" << GetName() << "_it);";
+ s << "if (" << GetName() << "_ptr != nullptr) {";
+ s << GetName() << "_it = " << GetName() << "_it + " << GetName() << "_ptr->size();";
+ s << "} else {";
+ s << GetName() << "_it = " << GetName() << "_it + " << GetName() << "_it.NumBytesRemaining();";
+ s << "}";
+}
+
+std::string VariableLengthStructField::GetGetterFunctionName() const {
+ std::stringstream ss;
+ ss << "Get" << util::UnderscoreToCamelCase(GetName());
+ return ss.str();
+}
+
+void VariableLengthStructField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
+ s << GetDataType() << " " << GetGetterFunctionName() << "() const {";
+ s << "ASSERT(was_validated_);";
+ s << "size_t end_index = size();";
+ s << "auto to_bound = begin();";
+ int num_leading_bits = GenBounds(s, start_offset, end_offset, GetSize());
+ s << "std::unique_ptr<" << type_name_ << "> " << GetName() << "_ptr;";
+ GenExtractor(s, num_leading_bits, false);
+ s << "return " << GetName() << "_ptr;";
+ s << "}\n";
+}
+
+std::string VariableLengthStructField::GetBuilderParameterType() const {
+ return GetDataType();
+}
+
+bool VariableLengthStructField::BuilderParameterMustBeMoved() const {
+ return true;
+}
+
+bool VariableLengthStructField::HasParameterValidator() const {
+ return false;
+}
+
+void VariableLengthStructField::GenParameterValidator(std::ostream&) const {
+ // Validated at compile time.
+}
+
+void VariableLengthStructField::GenInserter(std::ostream& s) const {
+ s << GetName() << "_->Serialize(i);";
+}
+
+void VariableLengthStructField::GenValidator(std::ostream&) const {
+ // Do nothing
+}
diff --git a/gd/packet/parser/fields/variable_length_struct_field.h b/gd/packet/parser/fields/variable_length_struct_field.h
new file mode 100644
index 0000000..0b1b97f
--- /dev/null
+++ b/gd/packet/parser/fields/variable_length_struct_field.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "fields/packet_field.h"
+#include "parse_location.h"
+
+class VariableLengthStructField : public PacketField {
+ public:
+ VariableLengthStructField(std::string name, std::string type_name, ParseLocation loc);
+
+ static const std::string kFieldType;
+
+ virtual const std::string& GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual Size GetBuilderSize() const override;
+
+ virtual std::string GetDataType() const override;
+
+ virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+ virtual std::string GetGetterFunctionName() const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual std::string GetBuilderParameterType() const override;
+
+ virtual bool BuilderParameterMustBeMoved() const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream&) const override;
+
+ virtual void GenInserter(std::ostream& s) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ private:
+ std::string type_name_;
+};
diff --git a/gd/packet/parser/fields/vector_field.cc b/gd/packet/parser/fields/vector_field.cc
new file mode 100644
index 0000000..ab47c4f
--- /dev/null
+++ b/gd/packet/parser/fields/vector_field.cc
@@ -0,0 +1,232 @@
+/*
+ * Copyright 2019 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 "fields/vector_field.h"
+
+#include "fields/count_field.h"
+#include "fields/custom_field.h"
+#include "util.h"
+
+const std::string VectorField::kFieldType = "VectorField";
+
+VectorField::VectorField(std::string name, int element_size, std::string size_modifier, ParseLocation loc)
+ : PacketField(name, loc), element_field_(new ScalarField("val", element_size, loc)), element_size_(element_size),
+ size_modifier_(size_modifier) {
+ if (element_size > 64 || element_size < 0)
+ ERROR(this) << __func__ << ": Not implemented for element size = " << element_size;
+ if (element_size % 8 != 0) {
+ ERROR(this) << "Can only have arrays with elements that are byte aligned (" << element_size << ")";
+ }
+}
+
+VectorField::VectorField(std::string name, TypeDef* type_def, std::string size_modifier, ParseLocation loc)
+ : PacketField(name, loc), element_field_(type_def->GetNewField("val", loc)),
+ element_size_(element_field_->GetSize()), size_modifier_(size_modifier) {
+ if (!element_size_.empty() && element_size_.bits() % 8 != 0) {
+ ERROR(this) << "Can only have arrays with elements that are byte aligned (" << element_size_ << ")";
+ }
+}
+
+const std::string& VectorField::GetFieldType() const {
+ return VectorField::kFieldType;
+}
+
+Size VectorField::GetSize() const {
+ // If there is no size field, then it is of unknown size.
+ if (size_field_ == nullptr) {
+ return Size();
+ }
+
+ // size_field_ is of type SIZE
+ if (size_field_->GetFieldType() == SizeField::kFieldType) {
+ std::string ret = "(static_cast<size_t>(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "()) * 8)";
+ if (!size_modifier_.empty()) ret += size_modifier_;
+ return ret;
+ }
+
+ // size_field_ is of type COUNT and elements have a fixed size
+ if (!element_size_.empty() && !element_size_.has_dynamic()) {
+ return "(static_cast<size_t>(Get" + util::UnderscoreToCamelCase(size_field_->GetName()) + "()) * " +
+ std::to_string(element_size_.bits()) + ")";
+ }
+
+ return Size();
+}
+
+Size VectorField::GetBuilderSize() const {
+ if (!element_size_.empty() && !element_size_.has_dynamic()) {
+ std::string ret = "(static_cast<size_t>(" + GetName() + "_.size()) * " + std::to_string(element_size_.bits()) + ")";
+ return ret;
+ } else if (element_field_->BuilderParameterMustBeMoved()) {
+ std::string ret = "[this](){ size_t length = 0; for (const auto& elem : " + GetName() +
+ "_) { length += elem->size() * 8; } return length; }()";
+ return ret;
+ } else {
+ std::string ret = "[this](){ size_t length = 0; for (const auto& elem : " + GetName() +
+ "_) { length += elem.size() * 8; } return length; }()";
+ return ret;
+ }
+}
+
+Size VectorField::GetStructSize() const {
+ // If there is no size field, then it is of unknown size.
+ if (size_field_ == nullptr) {
+ return Size();
+ }
+
+ // size_field_ is of type SIZE
+ if (size_field_->GetFieldType() == SizeField::kFieldType) {
+ std::string ret = "(static_cast<size_t>(" + size_field_->GetName() + "_extracted) * 8)";
+ if (!size_modifier_.empty()) ret += "-" + size_modifier_;
+ return ret;
+ }
+
+ // size_field_ is of type COUNT and elements have a fixed size
+ if (!element_size_.empty() && !element_size_.has_dynamic()) {
+ return "(static_cast<size_t>(" + size_field_->GetName() + "_extracted) * " + std::to_string(element_size_.bits()) +
+ ")";
+ }
+
+ return Size();
+}
+
+std::string VectorField::GetDataType() const {
+ return "std::vector<" + element_field_->GetDataType() + ">";
+}
+
+void VectorField::GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const {
+ s << "auto " << element_field_->GetName() << "_it = " << GetName() << "_it;";
+ if (size_field_ != nullptr && size_field_->GetFieldType() == CountField::kFieldType) {
+ s << "size_t " << element_field_->GetName() << "_count = ";
+ if (for_struct) {
+ s << size_field_->GetName() << "_extracted;";
+ } else {
+ s << "Get" << util::UnderscoreToCamelCase(size_field_->GetName()) << "();";
+ }
+ }
+ s << "while (";
+ if (size_field_ != nullptr && size_field_->GetFieldType() == CountField::kFieldType) {
+ s << "(" << element_field_->GetName() << "_count-- > 0) && ";
+ }
+ if (!element_size_.empty()) {
+ s << element_field_->GetName() << "_it.NumBytesRemaining() >= " << element_size_.bytes() << ") {";
+ } else {
+ s << element_field_->GetName() << "_it.NumBytesRemaining() > 0) {";
+ }
+ if (element_field_->BuilderParameterMustBeMoved()) {
+ s << element_field_->GetDataType() << " " << element_field_->GetName() << "_ptr;";
+ } else {
+ s << element_field_->GetDataType() << " " << element_field_->GetName() << "_value;";
+ s << element_field_->GetDataType() << "* " << element_field_->GetName() << "_ptr = &" << element_field_->GetName()
+ << "_value;";
+ }
+ element_field_->GenExtractor(s, num_leading_bits, for_struct);
+ s << "if (" << element_field_->GetName() << "_ptr != nullptr) { ";
+ if (element_field_->BuilderParameterMustBeMoved()) {
+ s << GetName() << "_ptr->push_back(std::move(" << element_field_->GetName() << "_ptr));";
+ } else {
+ s << GetName() << "_ptr->push_back(" << element_field_->GetName() << "_value);";
+ }
+ s << "}";
+ s << "}";
+}
+
+std::string VectorField::GetGetterFunctionName() const {
+ std::stringstream ss;
+ ss << "Get" << util::UnderscoreToCamelCase(GetName());
+ return ss.str();
+}
+
+void VectorField::GenGetter(std::ostream& s, Size start_offset, Size end_offset) const {
+ s << GetDataType() << " " << GetGetterFunctionName() << "() {";
+ s << "ASSERT(was_validated_);";
+ s << "size_t end_index = size();";
+ s << "auto to_bound = begin();";
+
+ int num_leading_bits = GenBounds(s, start_offset, end_offset, GetSize());
+ s << GetDataType() << " " << GetName() << "_value;";
+ s << GetDataType() << "* " << GetName() << "_ptr = &" << GetName() << "_value;";
+ GenExtractor(s, num_leading_bits, false);
+
+ s << "return " << GetName() << "_value;";
+ s << "}\n";
+}
+
+std::string VectorField::GetBuilderParameterType() const {
+ std::stringstream ss;
+ if (element_field_->BuilderParameterMustBeMoved()) {
+ ss << "std::vector<" << element_field_->GetDataType() << ">";
+ } else {
+ ss << "const std::vector<" << element_field_->GetDataType() << ">&";
+ }
+ return ss.str();
+}
+
+bool VectorField::BuilderParameterMustBeMoved() const {
+ return element_field_->BuilderParameterMustBeMoved();
+}
+
+bool VectorField::GenBuilderMember(std::ostream& s) const {
+ s << "std::vector<" << element_field_->GetDataType() << "> " << GetName();
+ return true;
+}
+
+bool VectorField::HasParameterValidator() const {
+ // Does not have parameter validator yet.
+ // TODO: See comment in GenParameterValidator
+ return false;
+}
+
+void VectorField::GenParameterValidator(std::ostream&) const {
+ // No Parameter validator if its dynamically size.
+ // TODO: Maybe add a validator to ensure that the size isn't larger than what the size field can hold.
+ return;
+}
+
+void VectorField::GenInserter(std::ostream& s) const {
+ s << "for (const auto& val_ : " << GetName() << "_) {";
+ element_field_->GenInserter(s);
+ s << "}\n";
+}
+
+void VectorField::GenValidator(std::ostream&) const {
+ // NOTE: We could check if the element size divides cleanly into the array size, but we decided to forgo that
+ // in favor of just returning as many elements as possible in a best effort style.
+ //
+ // Other than that there is nothing that arrays need to be validated on other than length so nothing needs to
+ // be done here.
+}
+
+void VectorField::SetSizeField(const SizeField* size_field) {
+ if (size_field->GetFieldType() == CountField::kFieldType && !size_modifier_.empty()) {
+ ERROR(this, size_field) << "Can not use count field to describe array with a size modifier."
+ << " Use size instead";
+ }
+
+ size_field_ = size_field;
+}
+
+const std::string& VectorField::GetSizeModifier() const {
+ return size_modifier_;
+}
+
+bool VectorField::IsContainerField() const {
+ return true;
+}
+
+const PacketField* VectorField::GetElementField() const {
+ return element_field_;
+}
diff --git a/gd/packet/parser/fields/vector_field.h b/gd/packet/parser/fields/vector_field.h
new file mode 100644
index 0000000..b2ae95d
--- /dev/null
+++ b/gd/packet/parser/fields/vector_field.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "fields/packet_field.h"
+#include "fields/size_field.h"
+#include "parse_location.h"
+#include "type_def.h"
+
+class VectorField : public PacketField {
+ public:
+ VectorField(std::string name, int element_size, std::string size_modifier, ParseLocation loc);
+
+ VectorField(std::string name, TypeDef* type_def, std::string size_modifier, ParseLocation loc);
+
+ static const std::string kFieldType;
+
+ virtual const std::string& GetFieldType() const override;
+
+ virtual Size GetSize() const override;
+
+ virtual Size GetBuilderSize() const override;
+
+ virtual Size GetStructSize() const override;
+
+ virtual std::string GetDataType() const override;
+
+ virtual void GenExtractor(std::ostream& s, int num_leading_bits, bool for_struct) const override;
+
+ virtual std::string GetGetterFunctionName() const override;
+
+ virtual void GenGetter(std::ostream& s, Size start_offset, Size end_offset) const override;
+
+ virtual std::string GetBuilderParameterType() const override;
+
+ virtual bool BuilderParameterMustBeMoved() const override;
+
+ virtual bool GenBuilderMember(std::ostream& s) const override;
+
+ virtual bool HasParameterValidator() const override;
+
+ virtual void GenParameterValidator(std::ostream& s) const override;
+
+ virtual void GenInserter(std::ostream& s) const override;
+
+ virtual void GenValidator(std::ostream&) const override;
+
+ void SetSizeField(const SizeField* size_field);
+
+ const std::string& GetSizeModifier() const;
+
+ virtual bool IsContainerField() const override;
+
+ virtual const PacketField* GetElementField() const override;
+
+ const std::string name_;
+
+ const PacketField* element_field_{nullptr};
+
+ const Size element_size_{};
+
+ // Size is always in bytes, unless it is a count.
+ const SizeField* size_field_{nullptr};
+
+ // Size modifier is only used when size_field_ is of type SIZE and is not used with COUNT.
+ std::string size_modifier_{""};
+};
diff --git a/gd/packet/parser/language_l.ll b/gd/packet/parser/language_l.ll
new file mode 100644
index 0000000..5814ec1
--- /dev/null
+++ b/gd/packet/parser/language_l.ll
@@ -0,0 +1,121 @@
+%{
+
+#include <string>
+#include <map>
+#include <iostream>
+
+#include "declarations.h"
+#include "language_y.h"
+
+using token = yy::parser::token;
+
+#define YY_USER_ACTION yylloc->step(); yylloc->columns(yyleng);
+
+%}
+
+%option debug
+
+%option yylineno
+%option noyywrap
+%option nounput
+%option noinput
+%option reentrant
+%option bison-bridge
+%option bison-locations
+
+identifier [a-zA-Z][_a-zA-Z0-9]*
+size_modifier [+*/-][ +*/\-0-9]*
+intvalue (0|[1-9][0-9]*)
+hexvalue 0[x|X][0-9a-fA-F]+
+string_literal \".*\"
+
+%x COMMENT_STATE
+
+%%
+ /* NOTE:
+ * Rule ordering is important in order to establist priority. Some
+ * rules are a superset of other rules and will cause the sub rules to
+ * never match. Ex. Keywords must always go before identifiers, otherwise
+ * all keywords will be treated as an identifier.
+ */
+
+ /* Block Comment */
+"/*" { BEGIN(COMMENT_STATE); }
+<COMMENT_STATE>"*/" { BEGIN(INITIAL); }
+<COMMENT_STATE>[\n]+ { yylloc->lines(yyleng); }
+<COMMENT_STATE>. { /* do nothing */ }
+
+ /* Line Comment */
+"//"[^\r\n]* { /* do nothing */ }
+
+ /* Begin reserved keyword definitions */
+ /* Fields */
+"_body_" { return(token::BODY); }
+"_payload_" { return(token::PAYLOAD); }
+"_size_" { return(token::SIZE); }
+"_count_" { return(token::COUNT); }
+"_fixed_" { return(token::FIXED); }
+"_reserved_" { return(token::RESERVED); }
+"_checksum_start_" { return(token::CHECKSUM_START); }
+"_padding_" { return(token::PADDING); }
+ /* Types */
+"checksum" { return(token::CHECKSUM); }
+"custom_field" { return(token::CUSTOM_FIELD); }
+"enum" { return(token::ENUM); }
+"group" { return(token::GROUP); }
+"packet" { return(token::PACKET); }
+"struct" { return(token::STRUCT); }
+"little_endian_packets" {
+ yylval->integer = 1;
+ return token::IS_LITTLE_ENDIAN;
+ }
+"big_endian_packets" {
+ yylval->integer = 0;
+ return token::IS_LITTLE_ENDIAN;
+ }
+
+ /* Begin identifier definitions */
+{string_literal} {
+ std::string with_quotes = std::string(yytext);
+ yylval->string = new std::string(with_quotes.begin() + 1, with_quotes.end() - 1);
+ return token::STRING;
+ }
+
+{size_modifier} {
+ yylval->string = new std::string(yytext);
+ return token::SIZE_MODIFIER;
+ }
+
+{identifier} {
+ yylval->string = new std::string(yytext);
+ return token::IDENTIFIER;
+ }
+
+{intvalue} {
+ yylval->integer = std::stoi(std::string(yytext), nullptr, 10);
+ return token::INTEGER;
+ }
+
+{hexvalue} {
+ yylval->integer = std::stoi(std::string(yytext), nullptr, 16);
+ return token::INTEGER;
+ }
+
+ /* Begin token definitions */
+":" { return(':'); }
+"{" { return('{'); }
+"}" { return('}'); }
+"[" { return('['); }
+"]" { return(']'); }
+"(" { return('('); }
+")" { return(')'); }
+"<" { return('<'); }
+">" { return('>'); }
+"=" { return('='); }
+"," { return(','); }
+
+(\n|\r\n)+ { yylloc->lines(yyleng); }
+[ \t\f\v]+ { /* Ignore all other whitespace */ }
+
+%%
+
diff --git a/gd/packet/parser/language_y.yy b/gd/packet/parser/language_y.yy
new file mode 100644
index 0000000..a36abef
--- /dev/null
+++ b/gd/packet/parser/language_y.yy
@@ -0,0 +1,725 @@
+%{
+ #include <iostream>
+ #include <vector>
+ #include <list>
+ #include <map>
+
+ #include "declarations.h"
+ #include "logging.h"
+ #include "language_y.h"
+ #include "field_list.h"
+ #include "fields/all_fields.h"
+
+ extern int yylex(yy::parser::semantic_type*, yy::parser::location_type*, void *);
+
+ ParseLocation toParseLocation(yy::parser::location_type loc) {
+ return ParseLocation(loc.begin.line);
+ }
+ #define LOC toParseLocation(yylloc)
+%}
+
+%parse-param { void* scanner }
+%parse-param { Declarations* decls }
+%lex-param { void* scanner }
+
+%pure-parser
+%glr-parser
+%skeleton "glr.cc"
+
+%expect-rr 0
+
+%debug
+%error-verbose
+%verbose
+
+%union {
+ int integer;
+ std::string* string;
+
+ EnumDef* enum_definition;
+ std::map<int, std::string>* enumeration_values;
+ std::pair<int, std::string>* enumeration_value;
+
+ PacketDef* packet_definition_value;
+ FieldList* packet_field_definitions;
+ PacketField* packet_field_type;
+
+ StructDef* struct_definition_value;
+
+ std::map<std::string, std::variant<int64_t, std::string>>* constraint_list_t;
+ std::pair<std::string, std::variant<int64_t, std::string>>* constraint_t;
+}
+
+%token <integer> INTEGER
+%token <integer> IS_LITTLE_ENDIAN
+%token <string> IDENTIFIER
+%token <string> SIZE_MODIFIER
+%token <string> STRING
+
+%token ENUM "enum"
+%token PACKET "packet"
+%token PAYLOAD "payload"
+%token BODY "body"
+%token STRUCT "struct"
+%token SIZE "size"
+%token COUNT "count"
+%token FIXED "fixed"
+%token RESERVED "reserved"
+%token GROUP "group"
+%token CUSTOM_FIELD "custom_field"
+%token CHECKSUM "checksum"
+%token CHECKSUM_START "checksum_start"
+%token PADDING "padding"
+
+%type<enum_definition> enum_definition
+%type<enumeration_values> enumeration_list
+%type<enumeration_value> enumeration
+
+%type<packet_definition_value> packet_definition;
+%type<packet_field_definitions> field_definition_list;
+%type<packet_field_type> field_definition;
+%type<packet_field_type> group_field_definition;
+%type<packet_field_type> type_def_field_definition;
+%type<packet_field_type> scalar_field_definition;
+%type<packet_field_type> checksum_start_field_definition;
+%type<packet_field_type> padding_field_definition;
+%type<packet_field_type> size_field_definition;
+%type<packet_field_type> payload_field_definition;
+%type<packet_field_type> body_field_definition;
+%type<packet_field_type> fixed_field_definition;
+%type<packet_field_type> reserved_field_definition;
+%type<packet_field_type> array_field_definition;
+
+%type<struct_definition_value> struct_definition;
+
+%type<constraint_list_t> constraint_list;
+%type<constraint_t> constraint;
+%destructor { std::cout << "DESTROYING STRING " << *$$ << "\n"; delete $$; } IDENTIFIER STRING SIZE_MODIFIER
+
+%%
+
+file
+ : IS_LITTLE_ENDIAN declarations
+ {
+ decls->is_little_endian = ($1 == 1);
+ if (decls->is_little_endian) {
+ DEBUG() << "LITTLE ENDIAN ";
+ } else {
+ DEBUG() << "BIG ENDIAN ";
+ }
+ }
+
+declarations
+ : /* empty */
+ | declarations declaration
+
+declaration
+ : enum_definition
+ {
+ DEBUG() << "FOUND ENUM\n\n";
+ decls->AddTypeDef($1->name_, $1);
+ }
+ | packet_definition
+ {
+ DEBUG() << "FOUND PACKET\n\n";
+ decls->AddPacketDef($1->name_, std::move(*$1));
+ delete $1;
+ }
+ | struct_definition
+ {
+ DEBUG() << "FOUND STRUCT\n\n";
+ decls->AddTypeDef($1->name_, $1);
+ }
+ | group_definition
+ {
+ // All actions are handled in group_definition
+ }
+ | checksum_definition
+ {
+ // All actions are handled in checksum_definition
+ }
+ | custom_field_definition
+ {
+ // All actions are handled in custom_field_definition
+ }
+
+enum_definition
+ : ENUM IDENTIFIER ':' INTEGER '{' enumeration_list ',' '}'
+ {
+ DEBUG() << "Enum Declared: name=" << *$2
+ << " size=" << $4 << "\n";
+
+ $$ = new EnumDef(std::move(*$2), $4);
+ for (const auto& e : *$6) {
+ $$->AddEntry(e.second, e.first);
+ }
+ delete $2;
+ delete $6;
+ }
+
+enumeration_list
+ : enumeration
+ {
+ DEBUG() << "Enumerator with comma\n";
+ $$ = new std::map<int, std::string>();
+ $$->insert(std::move(*$1));
+ delete $1;
+ }
+ | enumeration_list ',' enumeration
+ {
+ DEBUG() << "Enumerator with list\n";
+ $$ = $1;
+ $$->insert(std::move(*$3));
+ delete $3;
+ }
+
+enumeration
+ : IDENTIFIER '=' INTEGER
+ {
+ DEBUG() << "Enumerator: name=" << *$1
+ << " value=" << $3 << "\n";
+ $$ = new std::pair($3, std::move(*$1));
+ delete $1;
+ }
+
+group_definition
+ : GROUP IDENTIFIER '{' field_definition_list '}'
+ {
+ decls->AddGroupDef(*$2, $4);
+ delete $2;
+ }
+
+checksum_definition
+ : CHECKSUM IDENTIFIER ':' INTEGER STRING
+ {
+ DEBUG() << "Checksum field defined\n";
+ decls->AddTypeDef(*$2, new ChecksumDef(*$2, *$5, $4));
+ delete $2;
+ delete $5;
+ }
+
+custom_field_definition
+ : CUSTOM_FIELD IDENTIFIER ':' INTEGER STRING
+ {
+ decls->AddTypeDef(*$2, new CustomFieldDef(*$2, *$5, $4));
+ delete $2;
+ delete $5;
+ }
+ | CUSTOM_FIELD IDENTIFIER STRING
+ {
+ decls->AddTypeDef(*$2, new CustomFieldDef(*$2, *$3));
+ delete $2;
+ delete $3;
+ }
+
+struct_definition
+ : STRUCT IDENTIFIER '{' field_definition_list '}'
+ {
+ auto&& struct_name = *$2;
+ auto&& field_definition_list = *$4;
+
+ DEBUG() << "Struct " << struct_name << " with no parent";
+ DEBUG() << "STRUCT FIELD LIST SIZE: " << field_definition_list.size();
+ auto struct_definition = new StructDef(std::move(struct_name), std::move(field_definition_list));
+ struct_definition->AssignSizeFields();
+
+ $$ = struct_definition;
+ delete $2;
+ delete $4;
+ }
+ | STRUCT IDENTIFIER ':' IDENTIFIER '{' field_definition_list '}'
+ {
+ auto&& struct_name = *$2;
+ auto&& parent_struct_name = *$4;
+ auto&& field_definition_list = *$6;
+
+ DEBUG() << "Struct " << struct_name << " with parent " << parent_struct_name << "\n";
+ DEBUG() << "STRUCT FIELD LIST SIZE: " << field_definition_list.size() << "\n";
+
+ auto parent_struct = decls->GetTypeDef(parent_struct_name);
+ if (parent_struct == nullptr) {
+ ERRORLOC(LOC) << "Could not find struct " << parent_struct_name
+ << " used as parent for " << struct_name;
+ }
+
+ if (parent_struct->GetDefinitionType() != TypeDef::Type::STRUCT) {
+ ERRORLOC(LOC) << parent_struct_name << " is not a struct";
+ }
+ auto struct_definition = new StructDef(std::move(struct_name), std::move(field_definition_list), (StructDef*)parent_struct);
+ struct_definition->AssignSizeFields();
+
+ $$ = struct_definition;
+ delete $2;
+ delete $4;
+ delete $6;
+ }
+ | STRUCT IDENTIFIER ':' IDENTIFIER '(' constraint_list ')' '{' field_definition_list '}'
+ {
+ auto&& struct_name = *$2;
+ auto&& parent_struct_name = *$4;
+ auto&& constraints = *$6;
+ auto&& field_definition_list = *$9;
+
+ auto parent_struct = decls->GetTypeDef(parent_struct_name);
+ if (parent_struct == nullptr) {
+ ERRORLOC(LOC) << "Could not find struct " << parent_struct_name
+ << " used as parent for " << struct_name;
+ }
+
+ if (parent_struct->GetDefinitionType() != TypeDef::Type::STRUCT) {
+ ERRORLOC(LOC) << parent_struct_name << " is not a struct";
+ }
+
+ auto struct_definition = new StructDef(std::move(struct_name), std::move(field_definition_list), (StructDef*)parent_struct);
+ struct_definition->AssignSizeFields();
+
+ for (const auto& constraint : constraints) {
+ const auto& constraint_name = constraint.first;
+ const auto& constraint_value = constraint.second;
+ DEBUG() << "Parent constraint on " << constraint_name;
+ struct_definition->AddParentConstraint(constraint_name, constraint_value);
+ }
+
+ $$ = struct_definition;
+
+ delete $2;
+ delete $4;
+ delete $6;
+ delete $9;
+ }
+
+packet_definition
+ : PACKET IDENTIFIER '{' field_definition_list '}' /* Packet with no parent */
+ {
+ auto&& packet_name = *$2;
+ auto&& field_definition_list = *$4;
+
+ DEBUG() << "Packet " << packet_name << " with no parent";
+ DEBUG() << "PACKET FIELD LIST SIZE: " << field_definition_list.size();
+ auto packet_definition = new PacketDef(std::move(packet_name), std::move(field_definition_list));
+ packet_definition->AssignSizeFields();
+
+ $$ = packet_definition;
+ delete $2;
+ delete $4;
+ }
+ | PACKET IDENTIFIER ':' IDENTIFIER '{' field_definition_list '}'
+ {
+ auto&& packet_name = *$2;
+ auto&& parent_packet_name = *$4;
+ auto&& field_definition_list = *$6;
+
+ DEBUG() << "Packet " << packet_name << " with parent " << parent_packet_name << "\n";
+ DEBUG() << "PACKET FIELD LIST SIZE: " << field_definition_list.size() << "\n";
+
+ auto parent_packet = decls->GetPacketDef(parent_packet_name);
+ if (parent_packet == nullptr) {
+ ERRORLOC(LOC) << "Could not find packet " << parent_packet_name
+ << " used as parent for " << packet_name;
+ }
+
+ auto packet_definition = new PacketDef(std::move(packet_name), std::move(field_definition_list), parent_packet);
+ packet_definition->AssignSizeFields();
+
+ $$ = packet_definition;
+ delete $2;
+ delete $4;
+ delete $6;
+ }
+ | PACKET IDENTIFIER ':' IDENTIFIER '(' constraint_list ')' '{' field_definition_list '}'
+ {
+ auto&& packet_name = *$2;
+ auto&& parent_packet_name = *$4;
+ auto&& constraints = *$6;
+ auto&& field_definition_list = *$9;
+
+ DEBUG() << "Packet " << packet_name << " with parent " << parent_packet_name << "\n";
+ DEBUG() << "PACKET FIELD LIST SIZE: " << field_definition_list.size() << "\n";
+ DEBUG() << "CONSTRAINT LIST SIZE: " << constraints.size() << "\n";
+
+ auto parent_packet = decls->GetPacketDef(parent_packet_name);
+ if (parent_packet == nullptr) {
+ ERRORLOC(LOC) << "Could not find packet " << parent_packet_name
+ << " used as parent for " << packet_name;
+ }
+
+ auto packet_definition = new PacketDef(std::move(packet_name), std::move(field_definition_list), parent_packet);
+ packet_definition->AssignSizeFields();
+
+ for (const auto& constraint : constraints) {
+ const auto& constraint_name = constraint.first;
+ const auto& constraint_value = constraint.second;
+ DEBUG() << "Parent constraint on " << constraint_name;
+ packet_definition->AddParentConstraint(constraint_name, constraint_value);
+ }
+
+ $$ = packet_definition;
+
+ delete $2;
+ delete $4;
+ delete $6;
+ delete $9;
+ }
+
+field_definition_list
+ : /* empty */
+ {
+ DEBUG() << "Empty Field definition\n";
+ $$ = new FieldList();
+ }
+ | field_definition
+ {
+ DEBUG() << "Field definition\n";
+ $$ = new FieldList();
+
+ if ($1->GetFieldType() == GroupField::kFieldType) {
+ auto group_fields = static_cast<GroupField*>($1)->GetFields();
+ FieldList reversed_fields(group_fields->rbegin(), group_fields->rend());
+ for (auto& field : reversed_fields) {
+ $$->PrependField(field);
+ }
+ delete $1;
+ break;
+ }
+
+ $$->PrependField($1);
+ }
+ | field_definition ',' field_definition_list
+ {
+ DEBUG() << "Field definition with list\n";
+ $$ = $3;
+
+ if ($1->GetFieldType() == GroupField::kFieldType) {
+ auto group_fields = static_cast<GroupField*>($1)->GetFields();
+ FieldList reversed_fields(group_fields->rbegin(), group_fields->rend());
+ for (auto& field : reversed_fields) {
+ $$->PrependField(field);
+ }
+ delete $1;
+ break;
+ }
+
+ $$->PrependField($1);
+ }
+
+field_definition
+ : group_field_definition
+ {
+ DEBUG() << "Group Field";
+ $$ = $1;
+ }
+ | type_def_field_definition
+ {
+ DEBUG() << "Field with a pre-defined type\n";
+ $$ = $1;
+ }
+ | scalar_field_definition
+ {
+ DEBUG() << "Scalar field\n";
+ $$ = $1;
+ }
+ | checksum_start_field_definition
+ {
+ DEBUG() << "Checksum start field\n";
+ $$ = $1;
+ }
+ | padding_field_definition
+ {
+ DEBUG() << "Padding field\n";
+ $$ = $1;
+ }
+ | size_field_definition
+ {
+ DEBUG() << "Size field\n";
+ $$ = $1;
+ }
+ | body_field_definition
+ {
+ DEBUG() << "Body field\n";
+ $$ = $1;
+ }
+ | payload_field_definition
+ {
+ DEBUG() << "Payload field\n";
+ $$ = $1;
+ }
+ | fixed_field_definition
+ {
+ DEBUG() << "Fixed field\n";
+ $$ = $1;
+ }
+ | reserved_field_definition
+ {
+ DEBUG() << "Reserved field\n";
+ $$ = $1;
+ }
+ | array_field_definition
+ {
+ DEBUG() << "ARRAY field\n";
+ $$ = $1;
+ }
+
+group_field_definition
+ : IDENTIFIER
+ {
+ auto group = decls->GetGroupDef(*$1);
+ if (group == nullptr) {
+ ERRORLOC(LOC) << "Could not find group with name " << *$1;
+ }
+
+ std::list<PacketField*>* expanded_fields;
+ expanded_fields = new std::list<PacketField*>(group->begin(), group->end());
+ $$ = new GroupField(LOC, expanded_fields);
+ delete $1;
+ }
+ | IDENTIFIER '{' constraint_list '}'
+ {
+ DEBUG() << "Group with fixed field(s) " << *$1 << "\n";
+ auto group = decls->GetGroupDef(*$1);
+ if (group == nullptr) {
+ ERRORLOC(LOC) << "Could not find group with name " << *$1;
+ }
+
+ std::list<PacketField*>* expanded_fields = new std::list<PacketField*>();
+ for (const auto field : *group) {
+ const auto constraint = $3->find(field->GetName());
+ if (constraint != $3->end()) {
+ if (field->GetFieldType() == ScalarField::kFieldType) {
+ DEBUG() << "Fixing group scalar value\n";
+ expanded_fields->push_back(new FixedScalarField(field->GetSize().bits(), std::get<int64_t>(constraint->second), LOC));
+ } else if (field->GetFieldType() == EnumField::kFieldType) {
+ DEBUG() << "Fixing group enum value\n";
+
+ auto type_def = decls->GetTypeDef(field->GetDataType());
+ EnumDef* enum_def = (type_def->GetDefinitionType() == TypeDef::Type::ENUM ? (EnumDef*)type_def : nullptr);
+ if (enum_def == nullptr) {
+ ERRORLOC(LOC) << "No enum found of type " << field->GetDataType();
+ }
+ if (!enum_def->HasEntry(std::get<std::string>(constraint->second))) {
+ ERRORLOC(LOC) << "Enum " << field->GetDataType() << " has no enumeration " << std::get<std::string>(constraint->second);
+ }
+
+ expanded_fields->push_back(new FixedEnumField(enum_def, std::get<std::string>(constraint->second), LOC));
+ } else {
+ ERRORLOC(LOC) << "Unimplemented constraint of type " << field->GetFieldType();
+ }
+ $3->erase(constraint);
+ } else {
+ expanded_fields->push_back(field);
+ }
+ }
+ if ($3->size() > 0) {
+ ERRORLOC(LOC) << "Could not find member " << $3->begin()->first << " in group " << *$1;
+ }
+
+ $$ = new GroupField(LOC, expanded_fields);
+ delete $1;
+ delete $3;
+ }
+
+constraint_list
+ : constraint ',' constraint_list
+ {
+ DEBUG() << "Group field value list\n";
+ $3->insert(*$1);
+ $$ = $3;
+ delete($1);
+ }
+ | constraint
+ {
+ DEBUG() << "Group field value\n";
+ $$ = new std::map<std::string, std::variant<int64_t, std::string>>();
+ $$->insert(*$1);
+ delete($1);
+ }
+
+constraint
+ : IDENTIFIER '=' INTEGER
+ {
+ DEBUG() << "Group with a fixed integer value=" << $1 << " value=" << $3 << "\n";
+
+ $$ = new std::pair(*$1, std::variant<int64_t,std::string>($3));
+ delete $1;
+ }
+ | IDENTIFIER '=' IDENTIFIER
+ {
+ DEBUG() << "Group with a fixed enum field value=" << *$3 << " enum=" << *$1;
+
+ $$ = new std::pair(*$1, std::variant<int64_t,std::string>(*$3));
+ delete $1;
+ delete $3;
+ }
+
+type_def_field_definition
+ : IDENTIFIER ':' IDENTIFIER
+ {
+ DEBUG() << "Predefined type field " << *$1 << " : " << *$3 << "\n";
+ if (auto type_def = decls->GetTypeDef(*$3)) {
+ $$ = type_def->GetNewField(*$1, LOC);
+ } else {
+ ERRORLOC(LOC) << "No type with this name\n";
+ }
+ delete $1;
+ delete $3;
+ }
+
+scalar_field_definition
+ : IDENTIFIER ':' INTEGER
+ {
+ DEBUG() << "Scalar field " << *$1 << " : " << $3 << "\n";
+ $$ = new ScalarField(*$1, $3, LOC);
+ delete $1;
+ }
+
+body_field_definition
+ : BODY
+ {
+ DEBUG() << "Body field\n";
+ $$ = new BodyField(LOC);
+ }
+
+payload_field_definition
+ : PAYLOAD ':' '[' SIZE_MODIFIER ']'
+ {
+ DEBUG() << "Payload field with modifier " << *$4 << "\n";
+ $$ = new PayloadField(*$4, LOC);
+ delete $4;
+ }
+ | PAYLOAD
+ {
+ DEBUG() << "Payload field\n";
+ $$ = new PayloadField("", LOC);
+ }
+
+checksum_start_field_definition
+ : CHECKSUM_START '(' IDENTIFIER ')'
+ {
+ DEBUG() << "ChecksumStart field defined\n";
+ $$ = new ChecksumStartField(*$3, LOC);
+ delete $3;
+ }
+
+padding_field_definition
+ : PADDING '[' INTEGER ']'
+ {
+ DEBUG() << "Padding field defined\n";
+ $$ = new PaddingField($3, LOC);
+ }
+
+size_field_definition
+ : SIZE '(' IDENTIFIER ')' ':' INTEGER
+ {
+ DEBUG() << "Size field defined\n";
+ $$ = new SizeField(*$3, $6, LOC);
+ delete $3;
+ }
+ | SIZE '(' PAYLOAD ')' ':' INTEGER
+ {
+ DEBUG() << "Size for payload defined\n";
+ $$ = new SizeField("payload", $6, LOC);
+ }
+ | COUNT '(' IDENTIFIER ')' ':' INTEGER
+ {
+ DEBUG() << "Count field defined\n";
+ $$ = new CountField(*$3, $6, LOC);
+ delete $3;
+ }
+
+fixed_field_definition
+ : FIXED '=' INTEGER ':' INTEGER
+ {
+ DEBUG() << "Fixed field defined value=" << $3 << " size=" << $5 << "\n";
+ $$ = new FixedScalarField($5, $3, LOC);
+ }
+ | FIXED '=' IDENTIFIER ':' IDENTIFIER
+ {
+ DEBUG() << "Fixed enum field defined value=" << *$3 << " enum=" << *$5;
+ auto type_def = decls->GetTypeDef(*$5);
+ if (type_def != nullptr) {
+ EnumDef* enum_def = (type_def->GetDefinitionType() == TypeDef::Type::ENUM ? (EnumDef*)type_def : nullptr);
+ if (!enum_def->HasEntry(*$3)) {
+ ERRORLOC(LOC) << "Previously defined enum " << enum_def->GetTypeName() << " has no entry for " << *$3;
+ }
+
+ $$ = new FixedEnumField(enum_def, *$3, LOC);
+ } else {
+ ERRORLOC(LOC) << "No enum found with name " << *$5;
+ }
+
+ delete $3;
+ delete $5;
+ }
+
+reserved_field_definition
+ : RESERVED ':' INTEGER
+ {
+ DEBUG() << "Reserved field of size=" << $3 << "\n";
+ $$ = new ReservedField($3, LOC);
+ }
+
+array_field_definition
+ : IDENTIFIER ':' INTEGER '[' ']'
+ {
+ DEBUG() << "Vector field defined name=" << *$1 << " element_size=" << $3;
+ $$ = new VectorField(*$1, $3, "", LOC);
+ delete $1;
+ }
+ | IDENTIFIER ':' INTEGER '[' SIZE_MODIFIER ']'
+ {
+ DEBUG() << "Vector field defined name=" << *$1 << " element_size=" << $3
+ << " size_modifier=" << *$5;
+ $$ = new VectorField(*$1, $3, *$5, LOC);
+ delete $1;
+ delete $5;
+ }
+ | IDENTIFIER ':' INTEGER '[' INTEGER ']'
+ {
+ DEBUG() << "Array field defined name=" << *$1 << " element_size=" << $3
+ << " fixed_size=" << $5;
+ $$ = new ArrayField(*$1, $3, $5, LOC);
+ delete $1;
+ }
+ | IDENTIFIER ':' IDENTIFIER '[' ']'
+ {
+ DEBUG() << "Vector field defined name=" << *$1 << " type=" << *$3;
+ if (auto type_def = decls->GetTypeDef(*$3)) {
+ $$ = new VectorField(*$1, type_def, "", LOC);
+ } else {
+ ERRORLOC(LOC) << "Can't find type used in array field.";
+ }
+ delete $1;
+ delete $3;
+ }
+ | IDENTIFIER ':' IDENTIFIER '[' SIZE_MODIFIER ']'
+ {
+ DEBUG() << "Vector field defined name=" << *$1 << " type=" << *$3
+ << " size_modifier=" << *$5;
+ if (auto type_def = decls->GetTypeDef(*$3)) {
+ $$ = new VectorField(*$1, type_def, *$5, LOC);
+ } else {
+ ERRORLOC(LOC) << "Can't find type used in array field.";
+ }
+ delete $1;
+ delete $3;
+ delete $5;
+ }
+ | IDENTIFIER ':' IDENTIFIER '[' INTEGER ']'
+ {
+ DEBUG() << "Array field defined name=" << *$1 << " type=" << *$3
+ << " fixed_size=" << $5;
+ if (auto type_def = decls->GetTypeDef(*$3)) {
+ $$ = new ArrayField(*$1, type_def, $5, LOC);
+ } else {
+ ERRORLOC(LOC) << "Can't find type used in array field.";
+ }
+ delete $1;
+ delete $3;
+ }
+
+%%
+
+
+void yy::parser::error(const yy::parser::location_type& loc, const std::string& error) {
+ ERROR() << error << " at location " << loc << "\n";
+ abort();
+}
diff --git a/gd/packet/parser/logging.h b/gd/packet/parser/logging.h
new file mode 100644
index 0000000..a2939ef
--- /dev/null
+++ b/gd/packet/parser/logging.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <initializer_list>
+#include <iostream>
+#include <sstream>
+#include <vector>
+
+#include "parse_location.h"
+
+class Loggable {
+ public:
+ virtual ~Loggable() = default;
+ virtual std::string GetDebugName() const = 0;
+ virtual ParseLocation GetLocation() const = 0;
+};
+
+class LogMessage {
+ public:
+ LogMessage(ParseLocation loc, std::initializer_list<const Loggable*> tokens)
+ : debug_(false), loc_(loc), tokens_(tokens) {
+ Init();
+ }
+
+ LogMessage(bool debug, std::initializer_list<const Loggable*> tokens) : debug_(debug), tokens_(tokens) {
+ Init();
+ }
+
+ void Init() {
+ if (loc_.GetLine() != -1) {
+ stream_ << "\033[1mLine " << loc_.GetLine() << ": ";
+ }
+
+ if (!debug_) {
+ stream_ << "\033[1;31m";
+ stream_ << "ERROR: ";
+ stream_ << "\033[0m";
+ } else {
+ stream_ << "\033[1;m";
+ stream_ << "DEBUG: ";
+ stream_ << "\033[0m";
+ }
+ }
+
+ ~LogMessage() {
+ if (debug_ && suppress_debug_) return;
+
+ std::cerr << stream_.str() << "\n";
+ for (const auto& token : tokens_) {
+ // Bold line number
+ std::cerr << "\033[1m";
+ std::cerr << " Line " << token->GetLocation().GetLine() << ": ";
+ std::cerr << "\033[0m";
+ std::cerr << token->GetDebugName() << "\n";
+ }
+
+ if (!debug_) {
+ abort();
+ }
+ }
+
+ std::ostream& stream() {
+ return stream_;
+ }
+
+ private:
+ std::ostringstream stream_;
+ bool debug_;
+ bool suppress_debug_{true};
+ ParseLocation loc_;
+ std::vector<const Loggable*> tokens_;
+};
+
+// Error Log stream. Aborts the program after the message is printed.
+// The arguments to the macro is a list of Loggable objects that are printed when the error is printed.
+#define ERROR(...) LogMessage(false, {__VA_ARGS__}).stream()
+
+// ParseLocation error log, the first argument is a location.
+#define ERRORLOC(_1, ...) LogMessage(_1, {__VA_ARGS__}).stream()
+
+#define DEBUG(...) LogMessage(true, {__VA_ARGS__}).stream()
diff --git a/gd/packet/parser/main.cc b/gd/packet/parser/main.cc
new file mode 100644
index 0000000..757523d
--- /dev/null
+++ b/gd/packet/parser/main.cc
@@ -0,0 +1,439 @@
+/*
+ * Copyright 2019 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 <unistd.h>
+#include <cerrno>
+#include <cstdio>
+#include <filesystem>
+#include <fstream>
+#include <iostream>
+#include <queue>
+#include <regex>
+#include <sstream>
+#include <vector>
+
+#include "declarations.h"
+#include "struct_parser_generator.h"
+
+#include "language_y.h"
+
+void yylex_init(void**);
+void yylex_destroy(void*);
+void yyset_debug(int, void*);
+void yyset_in(FILE*, void*);
+
+namespace {
+
+void parse_namespace(const std::string& root_namespace, const std::filesystem::path& input_file_relative_path,
+ std::vector<std::string>* token) {
+ std::filesystem::path gen_namespace = root_namespace / input_file_relative_path;
+ std::string gen_namespace_str = gen_namespace;
+ std::regex path_tokenizer("/");
+ auto it = std::sregex_token_iterator(gen_namespace_str.cbegin(), gen_namespace_str.cend(), path_tokenizer, -1);
+ std::sregex_token_iterator it_end = {};
+ for (; it != it_end; ++it) {
+ token->push_back(it->str());
+ }
+}
+
+void generate_namespace_open(const std::vector<std::string>& token, std::ostream& output) {
+ for (const auto& ns : token) {
+ output << "namespace " << ns << " {" << std::endl;
+ }
+}
+
+void generate_namespace_close(const std::vector<std::string>& token, std::ostream& output) {
+ for (auto it = token.rbegin(); it != token.rend(); ++it) {
+ output << "} //namespace " << *it << std::endl;
+ }
+}
+
+bool parse_declarations_one_file(const std::filesystem::path& input_file, Declarations* declarations) {
+ void* scanner;
+ yylex_init(&scanner);
+
+ FILE* in_file = fopen(input_file.string().c_str(), "r");
+ if (in_file == nullptr) {
+ std::cerr << "can't open " << input_file << ": " << strerror(errno) << std::endl;
+ return false;
+ }
+
+ yyset_in(in_file, scanner);
+
+ int ret = yy::parser(scanner, declarations).parse();
+ if (ret != 0) {
+ std::cerr << "yylex parsing failed: returned " << ret << std::endl;
+ return false;
+ }
+
+ yylex_destroy(scanner);
+
+ fclose(in_file);
+
+ // Set endianess before returning
+ for (auto& s : declarations->type_defs_queue_) {
+ if (s.second->GetDefinitionType() == TypeDef::Type::STRUCT) {
+ auto* struct_def = dynamic_cast<StructDef*>(s.second);
+ struct_def->SetEndianness(declarations->is_little_endian);
+ }
+ }
+
+ for (auto& packet_def : declarations->packet_defs_queue_) {
+ packet_def.second.SetEndianness(declarations->is_little_endian);
+ }
+
+ return true;
+}
+
+bool generate_cpp_headers_one_file(const Declarations& decls, const std::filesystem::path& input_file,
+ const std::filesystem::path& include_dir, const std::filesystem::path& out_dir,
+ const std::string& root_namespace) {
+ auto gen_relative_path = input_file.lexically_relative(include_dir).parent_path();
+
+ auto input_filename = input_file.filename().string().substr(0, input_file.filename().string().find(".pdl"));
+ auto gen_path = out_dir / gen_relative_path;
+
+ std::filesystem::create_directories(gen_path);
+
+ auto gen_file = gen_path / (input_filename + ".h");
+
+ std::ofstream out_file;
+ out_file.open(gen_file);
+ if (!out_file.is_open()) {
+ std::cerr << "can't open " << gen_file << std::endl;
+ return false;
+ }
+
+ out_file << "\n\n";
+ out_file << "#pragma once\n";
+ out_file << "\n\n";
+ out_file << "#include <stdint.h>\n";
+ out_file << "#include <string>\n";
+ out_file << "#include <functional>\n";
+ out_file << "\n\n";
+ out_file << "#include \"os/log.h\"\n";
+ out_file << "#include \"packet/base_packet_builder.h\"\n";
+ out_file << "#include \"packet/bit_inserter.h\"\n";
+ out_file << "#include \"packet/iterator.h\"\n";
+ out_file << "#include \"packet/packet_builder.h\"\n";
+ out_file << "#include \"packet/packet_struct.h\"\n";
+ out_file << "#include \"packet/packet_view.h\"\n";
+ out_file << "#include \"packet/parser/checksum_type_checker.h\"\n";
+ out_file << "#include \"packet/parser/custom_type_checker.h\"\n";
+ out_file << "\n\n";
+
+ for (const auto& c : decls.type_defs_queue_) {
+ if (c.second->GetDefinitionType() == TypeDef::Type::CUSTOM ||
+ c.second->GetDefinitionType() == TypeDef::Type::CHECKSUM) {
+ ((CustomFieldDef*)c.second)->GenInclude(out_file);
+ }
+ }
+ out_file << "\n\n";
+
+ std::vector<std::string> namespace_list;
+ parse_namespace(root_namespace, gen_relative_path, &namespace_list);
+ generate_namespace_open(namespace_list, out_file);
+ out_file << "\n\n";
+
+ for (const auto& c : decls.type_defs_queue_) {
+ if (c.second->GetDefinitionType() == TypeDef::Type::CUSTOM ||
+ c.second->GetDefinitionType() == TypeDef::Type::CHECKSUM) {
+ ((CustomFieldDef*)c.second)->GenUsing(out_file);
+ }
+ }
+ out_file << "\n\n";
+
+ out_file << "using ::bluetooth::packet::BasePacketBuilder;";
+ out_file << "using ::bluetooth::packet::BitInserter;";
+ out_file << "using ::bluetooth::packet::CustomTypeChecker;";
+ out_file << "using ::bluetooth::packet::Iterator;";
+ out_file << "using ::bluetooth::packet::kLittleEndian;";
+ out_file << "using ::bluetooth::packet::PacketBuilder;";
+ out_file << "using ::bluetooth::packet::PacketStruct;";
+ out_file << "using ::bluetooth::packet::PacketView;";
+ out_file << "using ::bluetooth::packet::parser::ChecksumTypeChecker;";
+ out_file << "\n\n";
+
+ for (const auto& e : decls.type_defs_queue_) {
+ if (e.second->GetDefinitionType() == TypeDef::Type::ENUM) {
+ const auto* enum_def = dynamic_cast<const EnumDef*>(e.second);
+ EnumGen gen(*enum_def);
+ gen.GenDefinition(out_file);
+ out_file << "\n\n";
+ }
+ }
+ for (const auto& e : decls.type_defs_queue_) {
+ if (e.second->GetDefinitionType() == TypeDef::Type::ENUM) {
+ const auto* enum_def = dynamic_cast<const EnumDef*>(e.second);
+ EnumGen gen(*enum_def);
+ gen.GenLogging(out_file);
+ out_file << "\n\n";
+ }
+ }
+ for (const auto& ch : decls.type_defs_queue_) {
+ if (ch.second->GetDefinitionType() == TypeDef::Type::CHECKSUM) {
+ const auto* checksum_def = dynamic_cast<const ChecksumDef*>(ch.second);
+ checksum_def->GenChecksumCheck(out_file);
+ }
+ }
+ out_file << "\n/* Done ChecksumChecks */\n";
+
+ for (const auto& c : decls.type_defs_queue_) {
+ if (c.second->GetDefinitionType() == TypeDef::Type::CUSTOM && c.second->size_ == -1 /* Variable Size */) {
+ const auto* custom_field_def = dynamic_cast<const CustomFieldDef*>(c.second);
+ custom_field_def->GenCustomFieldCheck(out_file, decls.is_little_endian);
+ }
+ }
+ out_file << "\n";
+
+ for (auto& s : decls.type_defs_queue_) {
+ if (s.second->GetDefinitionType() == TypeDef::Type::STRUCT) {
+ const auto* struct_def = dynamic_cast<const StructDef*>(s.second);
+ struct_def->GenDefinition(out_file);
+ out_file << "\n";
+ }
+ }
+
+ {
+ StructParserGenerator spg(decls);
+ spg.Generate(out_file);
+ out_file << "\n\n";
+ }
+
+ for (const auto& packet_def : decls.packet_defs_queue_) {
+ packet_def.second.GenParserDefinition(out_file);
+ out_file << "\n\n";
+ }
+
+ for (const auto& packet_def : decls.packet_defs_queue_) {
+ packet_def.second.GenBuilderDefinition(out_file);
+ out_file << "\n\n";
+ }
+
+ generate_namespace_close(namespace_list, out_file);
+
+ out_file.close();
+
+ return true;
+}
+
+// Get the out_file shard at a symbol_count
+std::ofstream& get_out_file(size_t symbol_count, size_t symbol_total, std::vector<std::ofstream>* out_files) {
+ auto symbols_per_shard = symbol_total / out_files->size();
+ auto file_index = std::min(symbol_count / symbols_per_shard, out_files->size() - 1);
+ return out_files->at(file_index);
+}
+
+bool generate_pybind11_sources_one_file(const Declarations& decls, const std::filesystem::path& input_file,
+ const std::filesystem::path& include_dir, const std::filesystem::path& out_dir,
+ const std::string& root_namespace, size_t num_shards) {
+ auto gen_relative_path = input_file.lexically_relative(include_dir).parent_path();
+
+ auto input_filename = input_file.filename().string().substr(0, input_file.filename().string().find(".pdl"));
+ auto gen_path = out_dir / gen_relative_path;
+
+ std::filesystem::create_directories(gen_path);
+
+ auto gen_relative_header = gen_relative_path / (input_filename + ".h");
+
+ std::vector<std::string> namespace_list;
+ parse_namespace(root_namespace, gen_relative_path, &namespace_list);
+
+ std::vector<std::ofstream> out_file_shards(num_shards);
+ for (size_t i = 0; i < out_file_shards.size(); i++) {
+ auto filename = gen_path / (input_filename + "_python3_shard_" + std::to_string(i) + ".cc");
+ auto& out_file = out_file_shards[i];
+ out_file.open(filename);
+ if (!out_file.is_open()) {
+ std::cerr << "can't open " << filename << std::endl;
+ return false;
+ }
+ out_file << "#include <pybind11/pybind11.h>\n";
+ out_file << "#include <pybind11/stl.h>\n";
+ out_file << "\n\n";
+ out_file << "#include " << gen_relative_header << "\n";
+ out_file << "\n\n";
+
+ generate_namespace_open(namespace_list, out_file);
+ out_file << "\n\n";
+
+ for (const auto& c : decls.type_defs_queue_) {
+ if (c.second->GetDefinitionType() == TypeDef::Type::CUSTOM ||
+ c.second->GetDefinitionType() == TypeDef::Type::CHECKSUM) {
+ const auto* custom_def = dynamic_cast<const CustomFieldDef*>(c.second);
+ custom_def->GenUsing(out_file);
+ }
+ }
+ out_file << "\n\n";
+
+ out_file << "using ::bluetooth::packet::BasePacketBuilder;";
+ out_file << "using ::bluetooth::packet::BitInserter;";
+ out_file << "using ::bluetooth::packet::CustomTypeChecker;";
+ out_file << "using ::bluetooth::packet::Iterator;";
+ out_file << "using ::bluetooth::packet::kLittleEndian;";
+ out_file << "using ::bluetooth::packet::PacketBuilder;";
+ out_file << "using ::bluetooth::packet::BaseStruct;";
+ out_file << "using ::bluetooth::packet::PacketStruct;";
+ out_file << "using ::bluetooth::packet::PacketView;";
+ out_file << "using ::bluetooth::packet::parser::ChecksumTypeChecker;";
+ out_file << "\n\n";
+
+ out_file << "namespace py = pybind11;\n\n";
+
+ out_file << "void define_" << input_filename << "_submodule_shard_" << std::to_string(i) << "(py::module& m) {\n\n";
+ }
+ size_t symbol_total = 0;
+ // Only count types that will be generated
+ for (const auto& e : decls.type_defs_queue_) {
+ if (e.second->GetDefinitionType() == TypeDef::Type::ENUM) {
+ symbol_total++;
+ } else if (e.second->GetDefinitionType() == TypeDef::Type::STRUCT) {
+ symbol_total++;
+ }
+ }
+ // View and builder are counted separately
+ symbol_total += decls.packet_defs_queue_.size() * 2;
+ size_t symbol_count = 0;
+
+ for (const auto& e : decls.type_defs_queue_) {
+ if (e.second->GetDefinitionType() == TypeDef::Type::ENUM) {
+ const auto* enum_def = dynamic_cast<const EnumDef*>(e.second);
+ EnumGen gen(*enum_def);
+ auto& out_file = get_out_file(symbol_count, symbol_total, &out_file_shards);
+ gen.GenDefinitionPybind11(out_file);
+ out_file << "\n\n";
+ symbol_count++;
+ }
+ }
+
+ for (const auto& s : decls.type_defs_queue_) {
+ if (s.second->GetDefinitionType() == TypeDef::Type::STRUCT) {
+ const auto* struct_def = dynamic_cast<const StructDef*>(s.second);
+ auto& out_file = get_out_file(symbol_count, symbol_total, &out_file_shards);
+ struct_def->GenDefinitionPybind11(out_file);
+ out_file << "\n";
+ symbol_count++;
+ }
+ }
+
+ for (const auto& packet_def : decls.packet_defs_queue_) {
+ auto& out_file = get_out_file(symbol_count, symbol_total, &out_file_shards);
+ packet_def.second.GenParserDefinitionPybind11(out_file);
+ out_file << "\n\n";
+ symbol_count++;
+ }
+
+ for (const auto& p : decls.packet_defs_queue_) {
+ auto& out_file = get_out_file(symbol_count, symbol_total, &out_file_shards);
+ p.second.GenBuilderDefinitionPybind11(out_file);
+ out_file << "\n\n";
+ symbol_count++;
+ }
+
+ for (auto& out_file : out_file_shards) {
+ out_file << "}\n\n";
+ generate_namespace_close(namespace_list, out_file);
+ }
+
+ auto gen_file_main = gen_path / (input_filename + "_python3.cc");
+ std::ofstream out_file_main;
+ out_file_main.open(gen_file_main);
+ if (!out_file_main.is_open()) {
+ std::cerr << "can't open " << gen_file_main << std::endl;
+ return false;
+ }
+ out_file_main << "#include <pybind11/pybind11.h>\n";
+ generate_namespace_open(namespace_list, out_file_main);
+
+ out_file_main << "namespace py = pybind11;\n\n";
+
+ for (size_t i = 0; i < out_file_shards.size(); i++) {
+ out_file_main << "void define_" << input_filename << "_submodule_shard_" << std::to_string(i)
+ << "(py::module& m);\n";
+ }
+
+ out_file_main << "void define_" << input_filename << "_submodule(py::module& parent) {\n\n";
+ out_file_main << "py::module m = parent.def_submodule(\"" << input_filename << "\", \"A submodule of "
+ << input_filename << "\");\n\n";
+ for (size_t i = 0; i < out_file_shards.size(); i++) {
+ out_file_main << "define_" << input_filename << "_submodule_shard_" << std::to_string(i) << "(m);\n";
+ }
+ out_file_main << "}\n\n";
+
+ generate_namespace_close(namespace_list, out_file_main);
+
+ return true;
+}
+
+} // namespace
+
+// TODO(b/141583809): stop leaks
+extern "C" const char* __asan_default_options() {
+ return "detect_leaks=0";
+}
+
+int main(int argc, const char** argv) {
+ std::filesystem::path out_dir;
+ std::filesystem::path include_dir;
+ std::string root_namespace = "bluetooth";
+ // Number of shards per output pybind11 cc file
+ size_t num_shards = 1;
+ std::queue<std::filesystem::path> input_files;
+ const std::string arg_out = "--out=";
+ const std::string arg_include = "--include=";
+ const std::string arg_namespace = "--root_namespace=";
+ const std::string arg_num_shards = "--num_shards=";
+
+ for (int i = 1; i < argc; i++) {
+ std::string arg = argv[i];
+ if (arg.find(arg_out) == 0) {
+ out_dir = std::filesystem::current_path() / std::filesystem::path(arg.substr(arg_out.size()));
+ } else if (arg.find(arg_include) == 0) {
+ include_dir = std::filesystem::current_path() / std::filesystem::path(arg.substr(arg_include.size()));
+ } else if (arg.find(arg_namespace) == 0) {
+ root_namespace = arg.substr(arg_namespace.size());
+ } else if (arg.find(arg_num_shards) == 0) {
+ num_shards = std::stoul(arg.substr(arg_num_shards.size()));
+ } else {
+ input_files.emplace(std::filesystem::current_path() / std::filesystem::path(arg));
+ }
+ }
+ if (out_dir == std::filesystem::path() || include_dir == std::filesystem::path() || num_shards == 0) {
+ std::cerr << "Usage: bt-packetgen --out=OUT --include=INCLUDE --root_namespace=NAMESPACE --num_shards=NUM_SHARDS "
+ << "input_files..." << std::endl;
+ return 1;
+ }
+
+ while (!input_files.empty()) {
+ Declarations declarations;
+ if (!parse_declarations_one_file(input_files.front(), &declarations)) {
+ std::cerr << "Cannot parse " << input_files.front() << " correctly" << std::endl;
+ return 2;
+ }
+ if (!generate_cpp_headers_one_file(declarations, input_files.front(), include_dir, out_dir, root_namespace)) {
+ std::cerr << "Didn't generate cpp headers for " << input_files.front() << std::endl;
+ return 3;
+ }
+ if (!generate_pybind11_sources_one_file(declarations, input_files.front(), include_dir, out_dir, root_namespace,
+ num_shards)) {
+ std::cerr << "Didn't generate pybind11 sources for " << input_files.front() << std::endl;
+ return 4;
+ }
+ input_files.pop();
+ }
+
+ return 0;
+}
diff --git a/gd/packet/parser/packet_def.cc b/gd/packet/parser/packet_def.cc
new file mode 100644
index 0000000..2fd4df2
--- /dev/null
+++ b/gd/packet/parser/packet_def.cc
@@ -0,0 +1,688 @@
+/*
+ * Copyright 2019 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 "packet_def.h"
+
+#include <list>
+#include <set>
+
+#include "fields/all_fields.h"
+#include "util.h"
+
+PacketDef::PacketDef(std::string name, FieldList fields) : ParentDef(name, fields, nullptr) {}
+PacketDef::PacketDef(std::string name, FieldList fields, PacketDef* parent) : ParentDef(name, fields, parent) {}
+
+PacketField* PacketDef::GetNewField(const std::string&, ParseLocation) const {
+ return nullptr; // Packets can't be fields
+}
+
+void PacketDef::GenParserDefinition(std::ostream& s) const {
+ s << "class " << name_ << "View";
+ if (parent_ != nullptr) {
+ s << " : public " << parent_->name_ << "View {";
+ } else {
+ s << " : public PacketView<" << (is_little_endian_ ? "" : "!") << "kLittleEndian> {";
+ }
+ s << " public:";
+
+ // Specialize function
+ if (parent_ != nullptr) {
+ s << "static " << name_ << "View Create(" << parent_->name_ << "View parent)";
+ s << "{ return " << name_ << "View(parent); }";
+ } else {
+ s << "static " << name_ << "View Create(PacketView<" << (is_little_endian_ ? "" : "!") << "kLittleEndian> packet) ";
+ s << "{ return " << name_ << "View(packet); }";
+ }
+
+ std::set<std::string> fixed_types = {
+ FixedScalarField::kFieldType,
+ FixedEnumField::kFieldType,
+ };
+
+ // Print all of the public fields which are all the fields minus the fixed fields.
+ const auto& public_fields = fields_.GetFieldsWithoutTypes(fixed_types);
+ bool has_fixed_fields = public_fields.size() != fields_.size();
+ for (const auto& field : public_fields) {
+ GenParserFieldGetter(s, field);
+ s << "\n";
+ }
+ GenValidator(s);
+ s << "\n";
+
+ s << " protected:\n";
+ // Constructor from a View
+ if (parent_ != nullptr) {
+ s << name_ << "View(" << parent_->name_ << "View parent)";
+ s << " : " << parent_->name_ << "View(parent) { was_validated_ = false; }";
+ } else {
+ s << name_ << "View(PacketView<" << (is_little_endian_ ? "" : "!") << "kLittleEndian> packet) ";
+ s << " : PacketView<" << (is_little_endian_ ? "" : "!") << "kLittleEndian>(packet) { was_validated_ = false;}";
+ }
+
+ // Print the private fields which are the fixed fields.
+ if (has_fixed_fields) {
+ const auto& private_fields = fields_.GetFieldsWithTypes(fixed_types);
+ s << " private:\n";
+ for (const auto& field : private_fields) {
+ GenParserFieldGetter(s, field);
+ s << "\n";
+ }
+ }
+ s << "};\n";
+}
+
+void PacketDef::GenParserDefinitionPybind11(std::ostream& s) const {
+ s << "py::class_<" << name_ << "View";
+ if (parent_ != nullptr) {
+ s << ", " << parent_->name_ << "View";
+ } else {
+ s << ", PacketView<" << (is_little_endian_ ? "" : "!") << "kLittleEndian>";
+ }
+ s << ">(m, \"" << name_ << "View\")";
+ if (parent_ != nullptr) {
+ s << ".def(py::init([](" << parent_->name_ << "View parent) {";
+ } else {
+ s << ".def(py::init([](PacketView<" << (is_little_endian_ ? "" : "!") << "kLittleEndian> parent) {";
+ }
+ s << "auto view =" << name_ << "View::Create(std::move(parent));";
+ s << "if (!view.IsValid()) { throw std::invalid_argument(\"Bad packet view\"); }";
+ s << "return view; }))";
+
+ s << ".def(py::init(&" << name_ << "View::Create))";
+ std::set<std::string> protected_field_types = {
+ FixedScalarField::kFieldType,
+ FixedEnumField::kFieldType,
+ SizeField::kFieldType,
+ CountField::kFieldType,
+ };
+ const auto& public_fields = fields_.GetFieldsWithoutTypes(protected_field_types);
+ for (const auto& field : public_fields) {
+ auto getter_func_name = field->GetGetterFunctionName();
+ if (getter_func_name.empty()) {
+ continue;
+ }
+ s << ".def(\"" << getter_func_name << "\", &" << name_ << "View::" << getter_func_name << ")";
+ }
+ s << ".def(\"IsValid\", &" << name_ << "View::IsValid)";
+ s << ";\n";
+}
+
+void PacketDef::GenParserFieldGetter(std::ostream& s, const PacketField* field) const {
+ // Start field offset
+ auto start_field_offset = GetOffsetForField(field->GetName(), false);
+ auto end_field_offset = GetOffsetForField(field->GetName(), true);
+
+ if (start_field_offset.empty() && end_field_offset.empty()) {
+ ERROR(field) << "Field location for " << field->GetName() << " is ambiguous, "
+ << "no method exists to determine field location from begin() or end().\n";
+ }
+
+ field->GenGetter(s, start_field_offset, end_field_offset);
+}
+
+TypeDef::Type PacketDef::GetDefinitionType() const {
+ return TypeDef::Type::PACKET;
+}
+
+void PacketDef::GenValidator(std::ostream& s) const {
+ // Get the static offset for all of our fields.
+ int bits_size = 0;
+ for (const auto& field : fields_) {
+ if (field->GetFieldType() != PaddingField::kFieldType) {
+ bits_size += field->GetSize().bits();
+ }
+ }
+
+ // Write the function declaration.
+ s << "virtual bool IsValid() " << (parent_ != nullptr ? " override" : "") << " {";
+ s << "if (was_validated_) { return true; } ";
+ s << "else { was_validated_ = true; was_validated_ = IsValid_(); return was_validated_; }";
+ s << "}";
+
+ s << "protected:";
+ s << "virtual bool IsValid_() const {";
+
+ // Offset by the parents known size. We know that any dynamic fields can
+ // already be called since the parent must have already been validated by
+ // this point.
+ auto parent_size = Size(0);
+ if (parent_ != nullptr) {
+ parent_size = parent_->GetSize(true);
+ }
+
+ s << "auto it = begin() + (" << parent_size << ") / 8;";
+
+ // Check if you can extract the static fields.
+ // At this point you know you can use the size getters without crashing
+ // as long as they follow the instruction that size fields cant come before
+ // their corrisponding variable length field.
+ s << "it += " << ((bits_size + 7) / 8) << " /* Total size of the fixed fields */;";
+ s << "if (it > end()) return false;";
+
+ // For any variable length fields, use their size check.
+ for (const auto& field : fields_) {
+ if (field->GetFieldType() == ChecksumStartField::kFieldType) {
+ auto offset = GetOffsetForField(field->GetName(), false);
+ if (!offset.empty()) {
+ s << "size_t sum_index = (" << offset << ") / 8;";
+ } else {
+ offset = GetOffsetForField(field->GetName(), true);
+ if (offset.empty()) {
+ ERROR(field) << "Checksum Start Field offset can not be determined.";
+ }
+ s << "size_t sum_index = size() - (" << offset << ") / 8;";
+ }
+
+ const auto& field_name = ((ChecksumStartField*)field)->GetStartedFieldName();
+ const auto& started_field = fields_.GetField(field_name);
+ if (started_field == nullptr) {
+ ERROR(field) << __func__ << ": Can't find checksum field named " << field_name << "(" << field->GetName()
+ << ")";
+ }
+ auto end_offset = GetOffsetForField(started_field->GetName(), false);
+ if (!end_offset.empty()) {
+ s << "size_t end_sum_index = (" << end_offset << ") / 8;";
+ } else {
+ end_offset = GetOffsetForField(started_field->GetName(), true);
+ if (end_offset.empty()) {
+ ERROR(started_field) << "Checksum Field end_offset can not be determined.";
+ }
+ s << "size_t end_sum_index = size() - (" << started_field->GetSize() << " - " << end_offset << ") / 8;";
+ }
+ if (is_little_endian_) {
+ s << "auto checksum_view = GetLittleEndianSubview(sum_index, end_sum_index);";
+ } else {
+ s << "auto checksum_view = GetBigEndianSubview(sum_index, end_sum_index);";
+ }
+ s << started_field->GetDataType() << " checksum;";
+ s << "checksum.Initialize();";
+ s << "for (uint8_t byte : checksum_view) { ";
+ s << "checksum.AddByte(byte);}";
+ s << "if (checksum.GetChecksum() != (begin() + end_sum_index).extract<"
+ << util::GetTypeForSize(started_field->GetSize().bits()) << ">()) { return false; }";
+
+ continue;
+ }
+
+ auto field_size = field->GetSize();
+ // Fixed size fields have already been handled.
+ if (!field_size.has_dynamic()) {
+ continue;
+ }
+
+ // Custom fields with dynamic size must have the offset for the field passed in as well
+ // as the end iterator so that they may ensure that they don't try to read past the end.
+ // Custom fields with fixed sizes will be handled in the static offset checking.
+ if (field->GetFieldType() == CustomField::kFieldType) {
+ // Check if we can determine offset from begin(), otherwise error because by this point,
+ // the size of the custom field is unknown and can't be subtracted from end() to get the
+ // offset.
+ auto offset = GetOffsetForField(field->GetName(), false);
+ if (offset.empty()) {
+ ERROR(field) << "Custom Field offset can not be determined from begin().";
+ }
+
+ if (offset.bits() % 8 != 0) {
+ ERROR(field) << "Custom fields must be byte aligned.";
+ }
+
+ // Custom fields are special as their size field takes an argument.
+ const auto& custom_size_var = field->GetName() + "_size";
+ s << "const auto& " << custom_size_var << " = " << field_size.dynamic_string();
+ s << "(begin() + (" << offset << ") / 8);";
+
+ s << "if (!" << custom_size_var << ".has_value()) { return false; }";
+ s << "it += *" << custom_size_var << ";";
+ s << "if (it > end()) return false;";
+ continue;
+ } else {
+ s << "it += (" << field_size.dynamic_string() << ") / 8;";
+ s << "if (it > end()) return false;";
+ }
+ }
+
+ // Validate constraints after validating the size
+ if (parent_constraints_.size() > 0 && parent_ == nullptr) {
+ ERROR() << "Can't have a constraint on a NULL parent";
+ }
+
+ for (const auto& constraint : parent_constraints_) {
+ s << "if (Get" << util::UnderscoreToCamelCase(constraint.first) << "() != ";
+ const auto& field = parent_->GetParamList().GetField(constraint.first);
+ if (field->GetFieldType() == ScalarField::kFieldType) {
+ s << std::get<int64_t>(constraint.second);
+ } else {
+ s << std::get<std::string>(constraint.second);
+ }
+ s << ") return false;";
+ }
+
+ // Validate the packets fields last
+ for (const auto& field : fields_) {
+ field->GenValidator(s);
+ s << "\n";
+ }
+
+ s << "return true;";
+ s << "}\n";
+ if (parent_ == nullptr) {
+ s << "bool was_validated_{false};\n";
+ }
+}
+
+void PacketDef::GenBuilderDefinition(std::ostream& s) const {
+ s << "class " << name_ << "Builder";
+ if (parent_ != nullptr) {
+ s << " : public " << parent_->name_ << "Builder";
+ } else {
+ if (is_little_endian_) {
+ s << " : public PacketBuilder<kLittleEndian>";
+ } else {
+ s << " : public PacketBuilder<!kLittleEndian>";
+ }
+ }
+ s << " {";
+ s << " public:";
+ s << " virtual ~" << name_ << "Builder()" << (parent_ != nullptr ? " override" : "") << " = default;";
+
+ if (!fields_.HasBody()) {
+ GenBuilderCreate(s);
+ s << "\n";
+ }
+
+ GenSerialize(s);
+ s << "\n";
+
+ GenSize(s);
+ s << "\n";
+
+ s << " protected:\n";
+ GenBuilderConstructor(s);
+ s << "\n";
+
+ GenBuilderParameterChecker(s);
+ s << "\n";
+
+ GenMembers(s);
+ s << "};\n";
+
+ GenTestDefine(s);
+ s << "\n";
+
+ GenFuzzTestDefine(s);
+ s << "\n";
+}
+
+void PacketDef::GenBuilderDefinitionPybind11(std::ostream& s) const {
+ s << "py::class_<" << name_ << "Builder";
+ if (parent_ != nullptr) {
+ s << ", " << parent_->name_ << "Builder";
+ } else {
+ if (is_little_endian_) {
+ s << ", PacketBuilder<kLittleEndian>";
+ } else {
+ s << ", PacketBuilder<!kLittleEndian>";
+ }
+ }
+ s << ">(m, \"" << name_ << "Builder\")";
+ if (!fields_.HasBody()) {
+ GenBuilderCreatePybind11(s);
+ }
+ s << ".def(\"Serialize\", [](" << name_ << "Builder& builder){";
+ s << "std::vector<uint8_t> bytes;";
+ s << "BitInserter bi(bytes);";
+ s << "builder.Serialize(bi);";
+ s << "return bytes;})";
+ s << ";\n";
+}
+
+void PacketDef::GenTestDefine(std::ostream& s) const {
+ s << "#ifdef PACKET_TESTING\n";
+ s << "#define DEFINE_AND_INSTANTIATE_" << name_ << "ReflectionTest(...)";
+ s << "class " << name_ << "ReflectionTest : public testing::TestWithParam<std::vector<uint8_t>> { ";
+ s << "public: ";
+ s << "void CompareBytes(std::vector<uint8_t> captured_packet) {";
+ s << "auto vec = std::make_shared<std::vector<uint8_t>>(captured_packet.begin(), captured_packet.end());";
+ s << name_ << "View view = " << name_ << "View::Create(";
+ auto ancestor_ptr = parent_;
+ size_t parent_parens = 0;
+ while (ancestor_ptr != nullptr) {
+ s << ancestor_ptr->name_ << "View::Create(";
+ parent_parens++;
+ ancestor_ptr = ancestor_ptr->parent_;
+ }
+ s << "vec";
+ for (size_t i = 0; i < parent_parens; i++) {
+ s << ")";
+ }
+ s << ");";
+ s << "if (!view.IsValid()) { LOG_INFO(\"Invalid Packet Bytes (size = %zu)\", view.size());";
+ s << "for (size_t i = 0; i < view.size(); i++) { LOG_DEBUG(\"%5zd:%02X\", i, *(view.begin() + i)); }}";
+ s << "ASSERT_TRUE(view.IsValid());";
+ s << "auto packet = " << name_ << "Builder::Create(";
+ FieldList params = GetParamList().GetFieldsWithoutTypes({
+ BodyField::kFieldType,
+ });
+ for (int i = 0; i < params.size(); i++) {
+ params[i]->GenBuilderParameterFromView(s);
+ if (i != params.size() - 1) {
+ s << ", ";
+ }
+ }
+ s << ");";
+ s << "std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();";
+ s << "packet_bytes->reserve(packet->size());";
+ s << "BitInserter it(*packet_bytes);";
+ s << "packet->Serialize(it);";
+ s << "ASSERT_EQ(*packet_bytes, *vec);";
+ s << "}";
+ s << "};";
+ s << "TEST_P(" << name_ << "ReflectionTest, generatedReflectionTest) {";
+ s << "CompareBytes(GetParam());";
+ s << "}";
+ s << "INSTANTIATE_TEST_SUITE_P(" << name_ << "_reflection, ";
+ s << name_ << "ReflectionTest, testing::Values(__VA_ARGS__))";
+ s << "\n#endif";
+}
+
+void PacketDef::GenFuzzTestDefine(std::ostream& s) const {
+ s << "#ifdef PACKET_FUZZ_TESTING\n";
+ s << "#define DEFINE_AND_REGISTER_" << name_ << "ReflectionFuzzTest(REGISTRY) ";
+ s << "void Run" << name_ << "ReflectionFuzzTest(const uint8_t* data, size_t size) {";
+ s << "auto vec = std::make_shared<std::vector<uint8_t>>(data, data + size);";
+ s << name_ << "View view = " << name_ << "View::Create(";
+ auto ancestor_ptr = parent_;
+ size_t parent_parens = 0;
+ while (ancestor_ptr != nullptr) {
+ s << ancestor_ptr->name_ << "View::Create(";
+ parent_parens++;
+ ancestor_ptr = ancestor_ptr->parent_;
+ }
+ s << "vec";
+ for (size_t i = 0; i < parent_parens; i++) {
+ s << ")";
+ }
+ s << ");";
+ s << "if (!view.IsValid()) { return; }";
+ s << "auto packet = " << name_ << "Builder::Create(";
+ FieldList params = GetParamList().GetFieldsWithoutTypes({
+ BodyField::kFieldType,
+ });
+ for (int i = 0; i < params.size(); i++) {
+ params[i]->GenBuilderParameterFromView(s);
+ if (i != params.size() - 1) {
+ s << ", ";
+ }
+ }
+ s << ");";
+ s << "std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();";
+ s << "packet_bytes->reserve(packet->size());";
+ s << "BitInserter it(*packet_bytes);";
+ s << "packet->Serialize(it);";
+ s << "}";
+ s << " class " << name_ << "ReflectionFuzzTestRegistrant {";
+ s << "public: ";
+ s << "explicit " << name_
+ << "ReflectionFuzzTestRegistrant(std::vector<void(*)(const uint8_t*, size_t)>& fuzz_test_registry) {";
+ s << "fuzz_test_registry.push_back(Run" << name_ << "ReflectionFuzzTest);";
+ s << "}}; ";
+ s << name_ << "ReflectionFuzzTestRegistrant " << name_ << "_reflection_fuzz_test_registrant(REGISTRY);";
+ s << "\n#endif";
+}
+
+FieldList PacketDef::GetParametersToValidate() const {
+ FieldList params_to_validate;
+ for (const auto& field : GetParamList()) {
+ if (field->HasParameterValidator()) {
+ params_to_validate.AppendField(field);
+ }
+ }
+ return params_to_validate;
+}
+
+void PacketDef::GenBuilderCreate(std::ostream& s) const {
+ s << "static std::unique_ptr<" << name_ << "Builder> Create(";
+
+ auto params = GetParamList();
+ for (int i = 0; i < params.size(); i++) {
+ params[i]->GenBuilderParameter(s);
+ if (i != params.size() - 1) {
+ s << ", ";
+ }
+ }
+ s << ") {";
+
+ // Call the constructor
+ s << "auto builder = std::unique_ptr<" << name_ << "Builder>(new " << name_ << "Builder(";
+
+ params = params.GetFieldsWithoutTypes({
+ PayloadField::kFieldType,
+ BodyField::kFieldType,
+ });
+ // Add the parameters.
+ for (int i = 0; i < params.size(); i++) {
+ if (params[i]->BuilderParameterMustBeMoved()) {
+ s << "std::move(" << params[i]->GetName() << ")";
+ } else {
+ s << params[i]->GetName();
+ }
+ if (i != params.size() - 1) {
+ s << ", ";
+ }
+ }
+
+ s << "));";
+ if (fields_.HasPayload()) {
+ s << "builder->payload_ = std::move(payload);";
+ }
+ s << "return builder;";
+ s << "}\n";
+}
+
+void PacketDef::GenBuilderCreatePybind11(std::ostream& s) const {
+ s << ".def(py::init([](";
+ auto params = GetParamList();
+ std::vector<std::string> constructor_args;
+ std::vector<std::string> keep_alive_args;
+ int i = 1;
+ for (const auto& param : params) {
+ i++;
+ std::stringstream ss;
+ auto param_type = param->GetBuilderParameterType();
+ if (param_type.empty()) {
+ continue;
+ }
+ // Use shared_ptr instead of unique_ptr for the Python interface
+ if (param->BuilderParameterMustBeMoved()) {
+ param_type = util::StringFindAndReplaceAll(param_type, "unique_ptr", "shared_ptr");
+ keep_alive_args.push_back(std::to_string(i));
+ }
+ ss << param_type << " " << param->GetName();
+ constructor_args.push_back(ss.str());
+ }
+ s << util::StringJoin(",", constructor_args) << "){";
+
+ // Deal with move only args
+ for (const auto& param : params) {
+ std::stringstream ss;
+ auto param_type = param->GetBuilderParameterType();
+ if (param_type.empty()) {
+ continue;
+ }
+ if (!param->BuilderParameterMustBeMoved()) {
+ continue;
+ }
+ auto move_only_param_name = param->GetName() + "_move_only";
+ s << param_type << " " << move_only_param_name << ";";
+ if (param->IsContainerField()) {
+ // Assume single layer container
+ s << "for (size_t i = 0; i < " << param->GetName() << ".size(); i++) {";
+ if (param->GetFieldType() == VectorField::kFieldType) {
+ s << move_only_param_name << ".emplace_back(" << param->GetName() << "[i].get());";
+ } else if (param->GetFieldType() == ArrayField::kFieldType) {
+ s << move_only_param_name << "[i].reset(" << param->GetName() << "[i].get());";
+ } else {
+ ERROR() << param << " is not supported by Pybind11";
+ }
+ s << "}";
+ } else {
+ // Release shared_ptr to unique_ptr and leave the Python copy as nullptr and to be garbage collected by Python
+ s << move_only_param_name << ".reset(" << param->GetName() << ".get());";
+ }
+ }
+ s << "return " << name_ << "Builder::Create(";
+ std::vector<std::string> builder_vars;
+ for (const auto& param : params) {
+ std::stringstream ss;
+ auto param_type = param->GetBuilderParameterType();
+ if (param_type.empty()) {
+ continue;
+ }
+ auto param_name = param->GetName();
+ if (param->BuilderParameterMustBeMoved()) {
+ ss << "std::move(" << param_name << "_move_only)";
+ } else {
+ ss << param_name;
+ }
+ builder_vars.push_back(ss.str());
+ }
+ s << util::StringJoin(",", builder_vars) << ");}";
+ if (keep_alive_args.empty()) {
+ s << "))";
+ } else {
+ s << "), py::keep_alive<1," << util::StringJoin(",", keep_alive_args) << ">())";
+ }
+}
+
+void PacketDef::GenBuilderParameterChecker(std::ostream& s) const {
+ FieldList params_to_validate = GetParametersToValidate();
+
+ // Skip writing this function if there is nothing to validate.
+ if (params_to_validate.size() == 0) {
+ return;
+ }
+
+ // Generate function arguments.
+ s << "void CheckParameterValues(";
+ for (int i = 0; i < params_to_validate.size(); i++) {
+ params_to_validate[i]->GenBuilderParameter(s);
+ if (i != params_to_validate.size() - 1) {
+ s << ", ";
+ }
+ }
+ s << ") {";
+
+ // Check the parameters.
+ for (const auto& field : params_to_validate) {
+ field->GenParameterValidator(s);
+ }
+ s << "}\n";
+}
+
+void PacketDef::GenBuilderConstructor(std::ostream& s) const {
+ s << name_ << "Builder(";
+
+ // Generate the constructor parameters.
+ auto params = GetParamList().GetFieldsWithoutTypes({
+ PayloadField::kFieldType,
+ BodyField::kFieldType,
+ });
+ for (int i = 0; i < params.size(); i++) {
+ params[i]->GenBuilderParameter(s);
+ if (i != params.size() - 1) {
+ s << ", ";
+ }
+ }
+ if (params.size() > 0 || parent_constraints_.size() > 0) {
+ s << ") :";
+ } else {
+ s << ")";
+ }
+
+ // Get the list of parent params to call the parent constructor with.
+ FieldList parent_params;
+ if (parent_ != nullptr) {
+ // Pass parameters to the parent constructor
+ s << parent_->name_ << "Builder(";
+ parent_params = parent_->GetParamList().GetFieldsWithoutTypes({
+ PayloadField::kFieldType,
+ BodyField::kFieldType,
+ });
+
+ // Go through all the fields and replace constrained fields with fixed values
+ // when calling the parent constructor.
+ for (int i = 0; i < parent_params.size(); i++) {
+ const auto& field = parent_params[i];
+ const auto& constraint = parent_constraints_.find(field->GetName());
+ if (constraint != parent_constraints_.end()) {
+ if (field->GetFieldType() == ScalarField::kFieldType) {
+ s << std::get<int64_t>(constraint->second);
+ } else if (field->GetFieldType() == EnumField::kFieldType) {
+ s << std::get<std::string>(constraint->second);
+ } else {
+ ERROR(field) << "Constraints on non enum/scalar fields should be impossible.";
+ }
+
+ s << "/* " << field->GetName() << "_ */";
+ } else {
+ s << field->GetName();
+ }
+
+ if (i != parent_params.size() - 1) {
+ s << ", ";
+ }
+ }
+ s << ") ";
+ }
+
+ // Build a list of parameters that excludes all parent parameters.
+ FieldList saved_params;
+ for (const auto& field : params) {
+ if (parent_params.GetField(field->GetName()) == nullptr) {
+ saved_params.AppendField(field);
+ }
+ }
+ if (parent_ != nullptr && saved_params.size() > 0) {
+ s << ",";
+ }
+ for (int i = 0; i < saved_params.size(); i++) {
+ const auto& saved_param_name = saved_params[i]->GetName();
+ if (saved_params[i]->BuilderParameterMustBeMoved()) {
+ s << saved_param_name << "_(std::move(" << saved_param_name << "))";
+ } else {
+ s << saved_param_name << "_(" << saved_param_name << ")";
+ }
+ if (i != saved_params.size() - 1) {
+ s << ",";
+ }
+ }
+ s << " {";
+
+ FieldList params_to_validate = GetParametersToValidate();
+
+ if (params_to_validate.size() > 0) {
+ s << "CheckParameterValues(";
+ for (int i = 0; i < params_to_validate.size(); i++) {
+ s << params_to_validate[i]->GetName() << "_";
+ if (i != params_to_validate.size() - 1) {
+ s << ", ";
+ }
+ }
+ s << ");";
+ }
+
+ s << "}\n";
+}
diff --git a/gd/packet/parser/packet_def.h b/gd/packet/parser/packet_def.h
new file mode 100644
index 0000000..e8acdc3
--- /dev/null
+++ b/gd/packet/parser/packet_def.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <map>
+#include <variant>
+
+#include "enum_def.h"
+#include "field_list.h"
+#include "fields/packet_field.h"
+#include "parent_def.h"
+
+class PacketDef : public ParentDef {
+ public:
+ PacketDef(std::string name, FieldList fields);
+ PacketDef(std::string name, FieldList fields, PacketDef* parent);
+
+ PacketField* GetNewField(const std::string& name, ParseLocation loc) const;
+
+ void GenParserDefinition(std::ostream& s) const;
+
+ void GenParserDefinitionPybind11(std::ostream& s) const;
+
+ void GenParserFieldGetter(std::ostream& s, const PacketField* field) const;
+
+ void GenValidator(std::ostream& s) const;
+
+ TypeDef::Type GetDefinitionType() const;
+
+ void GenBuilderDefinition(std::ostream& s) const;
+
+ void GenBuilderDefinitionPybind11(std::ostream& s) const;
+
+ void GenTestDefine(std::ostream& s) const;
+
+ void GenFuzzTestDefine(std::ostream& s) const;
+
+ FieldList GetParametersToValidate() const;
+
+ void GenBuilderCreate(std::ostream& s) const;
+
+ void GenBuilderCreatePybind11(std::ostream& s) const;
+
+ void GenBuilderParameterChecker(std::ostream& s) const;
+
+ void GenBuilderConstructor(std::ostream& s) const;
+};
diff --git a/gd/packet/parser/parent_def.cc b/gd/packet/parser/parent_def.cc
new file mode 100644
index 0000000..1557bf6
--- /dev/null
+++ b/gd/packet/parser/parent_def.cc
@@ -0,0 +1,461 @@
+/*
+ * Copyright 2019 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 "parent_def.h"
+
+#include "fields/all_fields.h"
+#include "util.h"
+
+ParentDef::ParentDef(std::string name, FieldList fields) : ParentDef(name, fields, nullptr) {}
+ParentDef::ParentDef(std::string name, FieldList fields, ParentDef* parent)
+ : TypeDef(name), fields_(fields), parent_(parent) {}
+
+void ParentDef::AddParentConstraint(std::string field_name, std::variant<int64_t, std::string> value) {
+ // NOTE: This could end up being very slow if there are a lot of constraints.
+ const auto& parent_params = parent_->GetParamList();
+ const auto& constrained_field = parent_params.GetField(field_name);
+ if (constrained_field == nullptr) {
+ ERROR() << "Attempting to constrain field " << field_name << " in parent " << parent_->name_
+ << ", but no such field exists.";
+ }
+
+ if (constrained_field->GetFieldType() == ScalarField::kFieldType) {
+ if (!std::holds_alternative<int64_t>(value)) {
+ ERROR(constrained_field) << "Attempting to constrain a scalar field to an enum value in " << parent_->name_;
+ }
+ } else if (constrained_field->GetFieldType() == EnumField::kFieldType) {
+ if (!std::holds_alternative<std::string>(value)) {
+ ERROR(constrained_field) << "Attempting to constrain an enum field to a scalar value in " << parent_->name_;
+ }
+ const auto& enum_def = static_cast<EnumField*>(constrained_field)->GetEnumDef();
+ if (!enum_def.HasEntry(std::get<std::string>(value))) {
+ ERROR(constrained_field) << "No matching enumeration \"" << std::get<std::string>(value)
+ << "\" for constraint on enum in parent " << parent_->name_ << ".";
+ }
+
+ // For enums, we have to qualify the value using the enum type name.
+ value = enum_def.GetTypeName() + "::" + std::get<std::string>(value);
+ } else {
+ ERROR(constrained_field) << "Field in parent " << parent_->name_ << " is not viable for constraining.";
+ }
+
+ parent_constraints_.insert(std::pair(field_name, value));
+}
+
+// Assign all size fields to their corresponding variable length fields.
+// Will crash if
+// - there aren't any fields that don't match up to a field.
+// - the size field points to a fixed size field.
+// - if the size field comes after the variable length field.
+void ParentDef::AssignSizeFields() {
+ for (const auto& field : fields_) {
+ DEBUG() << "field name: " << field->GetName();
+
+ if (field->GetFieldType() != SizeField::kFieldType && field->GetFieldType() != CountField::kFieldType) {
+ continue;
+ }
+
+ const SizeField* size_field = static_cast<SizeField*>(field);
+ // Check to see if a corresponding field can be found.
+ const auto& var_len_field = fields_.GetField(size_field->GetSizedFieldName());
+ if (var_len_field == nullptr) {
+ ERROR(field) << "Could not find corresponding field for size/count field.";
+ }
+
+ // Do the ordering check to ensure the size field comes before the
+ // variable length field.
+ for (auto it = fields_.begin(); *it != size_field; it++) {
+ DEBUG() << "field name: " << (*it)->GetName();
+ if (*it == var_len_field) {
+ ERROR(var_len_field, size_field) << "Size/count field must come before the variable length field it describes.";
+ }
+ }
+
+ if (var_len_field->GetFieldType() == PayloadField::kFieldType) {
+ const auto& payload_field = static_cast<PayloadField*>(var_len_field);
+ payload_field->SetSizeField(size_field);
+ continue;
+ }
+
+ if (var_len_field->GetFieldType() == VectorField::kFieldType) {
+ const auto& vector_field = static_cast<VectorField*>(var_len_field);
+ vector_field->SetSizeField(size_field);
+ continue;
+ }
+
+ // If we've reached this point then the field wasn't a variable length field.
+ // Check to see if the field is a variable length field
+ ERROR(field, size_field) << "Can not use size/count in reference to a fixed size field.\n";
+ }
+}
+
+void ParentDef::SetEndianness(bool is_little_endian) {
+ is_little_endian_ = is_little_endian;
+}
+
+// Get the size. You scan specify without_payload in order to exclude payload fields as children will be overriding it.
+Size ParentDef::GetSize(bool without_payload) const {
+ auto size = Size(0);
+
+ for (const auto& field : fields_) {
+ if (without_payload &&
+ (field->GetFieldType() == PayloadField::kFieldType || field->GetFieldType() == BodyField::kFieldType)) {
+ continue;
+ }
+
+ // The offset to the field must be passed in as an argument for dynamically sized custom fields.
+ if (field->GetFieldType() == CustomField::kFieldType && field->GetSize().has_dynamic()) {
+ std::stringstream custom_field_size;
+
+ // Custom fields are special as their size field takes an argument.
+ custom_field_size << field->GetSize().dynamic_string() << "(begin()";
+
+ // Check if we can determine offset from begin(), otherwise error because by this point,
+ // the size of the custom field is unknown and can't be subtracted from end() to get the
+ // offset.
+ auto offset = GetOffsetForField(field->GetName(), false);
+ if (offset.empty()) {
+ ERROR(field) << "Custom Field offset can not be determined from begin().";
+ }
+
+ if (offset.bits() % 8 != 0) {
+ ERROR(field) << "Custom fields must be byte aligned.";
+ }
+ if (offset.has_bits()) custom_field_size << " + " << offset.bits() / 8;
+ if (offset.has_dynamic()) custom_field_size << " + " << offset.dynamic_string();
+ custom_field_size << ")";
+
+ size += custom_field_size.str();
+ continue;
+ }
+
+ size += field->GetSize();
+ }
+
+ if (parent_ != nullptr) {
+ size += parent_->GetSize(true);
+ }
+
+ return size;
+}
+
+// Get the offset until the field is reached, if there is no field
+// returns an empty Size. from_end requests the offset to the field
+// starting from the end() iterator. If there is a field with an unknown
+// size along the traversal, then an empty size is returned.
+Size ParentDef::GetOffsetForField(std::string field_name, bool from_end) const {
+ // Check first if the field exists.
+ if (fields_.GetField(field_name) == nullptr) {
+ ERROR() << "Can't find a field offset for nonexistent field named: " << field_name << " in " << name_;
+ }
+
+ // We have to use a generic lambda to conditionally change iteration direction
+ // due to iterator and reverse_iterator being different types.
+ auto size_lambda = [&](auto from, auto to) -> Size {
+ auto size = Size(0);
+ for (auto it = from; it != to; it++) {
+ // We've reached the field, end the loop.
+ if ((*it)->GetName() == field_name) break;
+ const auto& field = *it;
+ // If there is a field with an unknown size before the field, return an empty Size.
+ if (field->GetSize().empty()) {
+ return Size();
+ }
+ if (field->GetFieldType() != PaddingField::kFieldType || !from_end) {
+ size += field->GetSize();
+ }
+ }
+ return size;
+ };
+
+ // Change iteration direction based on from_end.
+ auto size = Size();
+ if (from_end)
+ size = size_lambda(fields_.rbegin(), fields_.rend());
+ else
+ size = size_lambda(fields_.begin(), fields_.end());
+ if (size.empty()) return size;
+
+ // We need the offset until a payload or body field.
+ if (parent_ != nullptr) {
+ if (parent_->fields_.HasPayload()) {
+ auto parent_payload_offset = parent_->GetOffsetForField("payload", from_end);
+ if (parent_payload_offset.empty()) {
+ ERROR() << "Empty offset for payload in " << parent_->name_ << " finding the offset for field: " << field_name;
+ }
+ size += parent_payload_offset;
+ } else {
+ auto parent_body_offset = parent_->GetOffsetForField("body", from_end);
+ if (parent_body_offset.empty()) {
+ ERROR() << "Empty offset for body in " << parent_->name_ << " finding the offset for field: " << field_name;
+ }
+ size += parent_body_offset;
+ }
+ }
+
+ return size;
+}
+
+FieldList ParentDef::GetParamList() const {
+ FieldList params;
+
+ std::set<std::string> param_types = {
+ ScalarField::kFieldType,
+ EnumField::kFieldType,
+ ArrayField::kFieldType,
+ VectorField::kFieldType,
+ CustomField::kFieldType,
+ StructField::kFieldType,
+ VariableLengthStructField::kFieldType,
+ PayloadField::kFieldType,
+ };
+
+ if (parent_ != nullptr) {
+ auto parent_params = parent_->GetParamList().GetFieldsWithTypes(param_types);
+
+ // Do not include constrained fields in the params
+ for (const auto& field : parent_params) {
+ if (parent_constraints_.find(field->GetName()) == parent_constraints_.end()) {
+ params.AppendField(field);
+ }
+ }
+ }
+ // Add our parameters.
+ return params.Merge(fields_.GetFieldsWithTypes(param_types));
+}
+
+void ParentDef::GenMembers(std::ostream& s) const {
+ // Add the parameter list.
+ for (int i = 0; i < fields_.size(); i++) {
+ if (fields_[i]->GenBuilderMember(s)) {
+ s << "_;";
+ }
+ }
+}
+
+void ParentDef::GenSize(std::ostream& s) const {
+ auto header_fields = fields_.GetFieldsBeforePayloadOrBody();
+ auto footer_fields = fields_.GetFieldsAfterPayloadOrBody();
+
+ s << "protected:";
+ s << "size_t BitsOfHeader() const {";
+ s << "return 0";
+
+ if (parent_ != nullptr) {
+ if (parent_->GetDefinitionType() == Type::PACKET) {
+ s << " + " << parent_->name_ << "Builder::BitsOfHeader() ";
+ } else {
+ s << " + " << parent_->name_ << "::BitsOfHeader() ";
+ }
+ }
+
+ for (const auto& field : header_fields) {
+ s << " + " << field->GetBuilderSize();
+ }
+ s << ";";
+
+ s << "}\n\n";
+
+ s << "size_t BitsOfFooter() const {";
+ s << "return 0";
+ for (const auto& field : footer_fields) {
+ s << " + " << field->GetBuilderSize();
+ }
+
+ if (parent_ != nullptr) {
+ if (parent_->GetDefinitionType() == Type::PACKET) {
+ s << " + " << parent_->name_ << "Builder::BitsOfFooter() ";
+ } else {
+ s << " + " << parent_->name_ << "::BitsOfFooter() ";
+ }
+ }
+ s << ";";
+ s << "}\n\n";
+
+ if (fields_.HasPayload()) {
+ s << "size_t GetPayloadSize() const {";
+ s << "if (payload_ != nullptr) {return payload_->size();}";
+ s << "else { return size() - (BitsOfHeader() + BitsOfFooter()) / 8;}";
+ s << ";}\n\n";
+ }
+
+ Size padded_size;
+ for (const auto& field : header_fields) {
+ if (field->GetFieldType() == PaddingField::kFieldType) {
+ if (!padded_size.empty()) {
+ ERROR() << "Only one padding field is allowed. Second field: " << field->GetName();
+ }
+ padded_size = field->GetSize();
+ }
+ }
+
+ s << "public:";
+ s << "virtual size_t size() const override {";
+ if (!padded_size.empty()) {
+ s << "return " << padded_size.bytes() << ";}";
+ s << "size_t unpadded_size() const {";
+ }
+ s << "return (BitsOfHeader() / 8)";
+ if (fields_.HasPayload()) {
+ s << "+ payload_->size()";
+ }
+ s << " + (BitsOfFooter() / 8);";
+ s << "}\n";
+}
+
+void ParentDef::GenSerialize(std::ostream& s) const {
+ auto header_fields = fields_.GetFieldsBeforePayloadOrBody();
+ auto footer_fields = fields_.GetFieldsAfterPayloadOrBody();
+
+ s << "protected:";
+ s << "void SerializeHeader(BitInserter&";
+ if (parent_ != nullptr || header_fields.size() != 0) {
+ s << " i ";
+ }
+ s << ") const {";
+
+ if (parent_ != nullptr) {
+ if (parent_->GetDefinitionType() == Type::PACKET) {
+ s << parent_->name_ << "Builder::SerializeHeader(i);";
+ } else {
+ s << parent_->name_ << "::SerializeHeader(i);";
+ }
+ }
+
+ for (const auto& field : header_fields) {
+ if (field->GetFieldType() == SizeField::kFieldType) {
+ const auto& field_name = ((SizeField*)field)->GetSizedFieldName();
+ const auto& sized_field = fields_.GetField(field_name);
+ if (sized_field == nullptr) {
+ ERROR(field) << __func__ << ": Can't find sized field named " << field_name;
+ }
+ if (sized_field->GetFieldType() == PayloadField::kFieldType) {
+ s << "size_t payload_bytes = GetPayloadSize();";
+ std::string modifier = ((PayloadField*)sized_field)->size_modifier_;
+ if (modifier != "") {
+ s << "static_assert((" << modifier << ")%8 == 0, \"Modifiers must be byte-aligned\");";
+ s << "payload_bytes = payload_bytes + (" << modifier << ") / 8;";
+ }
+ s << "ASSERT(payload_bytes < (static_cast<size_t>(1) << " << field->GetSize().bits() << "));";
+ s << "insert(static_cast<" << field->GetDataType() << ">(payload_bytes), i," << field->GetSize().bits() << ");";
+ } else {
+ if (sized_field->GetFieldType() != VectorField::kFieldType) {
+ ERROR(field) << __func__ << ": Unhandled sized field type for " << field_name;
+ }
+ const auto& vector_name = field_name + "_";
+ const VectorField* vector = (VectorField*)sized_field;
+ s << "size_t " << vector_name + "bytes = 0;";
+ if (vector->element_size_.empty() || vector->element_size_.has_dynamic()) {
+ s << "for (auto elem : " << vector_name << ") {";
+ s << vector_name + "bytes += elem.size(); }";
+ } else {
+ s << vector_name + "bytes = ";
+ s << vector_name << ".size() * ((" << vector->element_size_ << ") / 8);";
+ }
+ std::string modifier = vector->GetSizeModifier();
+ if (modifier != "") {
+ s << "static_assert((" << modifier << ")%8 == 0, \"Modifiers must be byte-aligned\");";
+ s << vector_name << "bytes = ";
+ s << vector_name << "bytes + (" << modifier << ") / 8;";
+ }
+ s << "ASSERT(" << vector_name + "bytes < (1 << " << field->GetSize().bits() << "));";
+ s << "insert(" << vector_name << "bytes, i, ";
+ s << field->GetSize().bits() << ");";
+ }
+ } else if (field->GetFieldType() == ChecksumStartField::kFieldType) {
+ const auto& field_name = ((ChecksumStartField*)field)->GetStartedFieldName();
+ const auto& started_field = fields_.GetField(field_name);
+ if (started_field == nullptr) {
+ ERROR(field) << __func__ << ": Can't find checksum field named " << field_name << "(" << field->GetName()
+ << ")";
+ }
+ s << "auto shared_checksum_ptr = std::make_shared<" << started_field->GetDataType() << ">();";
+ s << "shared_checksum_ptr->Initialize();";
+ s << "i.RegisterObserver(packet::ByteObserver(";
+ s << "[shared_checksum_ptr](uint8_t byte){ shared_checksum_ptr->AddByte(byte);},";
+ s << "[shared_checksum_ptr](){ return static_cast<uint64_t>(shared_checksum_ptr->GetChecksum());}));";
+ } else if (field->GetFieldType() == PaddingField::kFieldType) {
+ s << "ASSERT(unpadded_size() <= " << field->GetSize().bytes() << ");";
+ s << "size_t padding_bytes = ";
+ s << field->GetSize().bytes() << " - unpadded_size();";
+ s << "for (size_t padding = 0; padding < padding_bytes; padding++) {i.insert_byte(0);}";
+ } else if (field->GetFieldType() == CountField::kFieldType) {
+ const auto& vector_name = ((SizeField*)field)->GetSizedFieldName() + "_";
+ s << "insert(" << vector_name << ".size(), i, " << field->GetSize().bits() << ");";
+ } else {
+ field->GenInserter(s);
+ }
+ }
+ s << "}\n\n";
+
+ s << "void SerializeFooter(BitInserter&";
+ if (parent_ != nullptr || footer_fields.size() != 0) {
+ s << " i ";
+ }
+ s << ") const {";
+
+ for (const auto& field : footer_fields) {
+ field->GenInserter(s);
+ }
+ if (parent_ != nullptr) {
+ if (parent_->GetDefinitionType() == Type::PACKET) {
+ s << parent_->name_ << "Builder::SerializeFooter(i);";
+ } else {
+ s << parent_->name_ << "::SerializeFooter(i);";
+ }
+ }
+ s << "}\n\n";
+
+ s << "public:";
+ s << "virtual void Serialize(BitInserter& i) const override {";
+ s << "SerializeHeader(i);";
+ if (fields_.HasPayload()) {
+ s << "payload_->Serialize(i);";
+ }
+ s << "SerializeFooter(i);";
+
+ s << "}\n";
+}
+
+void ParentDef::GenInstanceOf(std::ostream& s) const {
+ if (parent_ != nullptr && parent_constraints_.size() > 0) {
+ s << "static bool IsInstance(const " << parent_->name_ << "& parent) {";
+ // Get the list of parent params.
+ FieldList parent_params = parent_->GetParamList().GetFieldsWithoutTypes({
+ PayloadField::kFieldType,
+ BodyField::kFieldType,
+ });
+
+ // Check if constrained parent fields are set to their correct values.
+ for (int i = 0; i < parent_params.size(); i++) {
+ const auto& field = parent_params[i];
+ const auto& constraint = parent_constraints_.find(field->GetName());
+ if (constraint != parent_constraints_.end()) {
+ s << "if (parent." << field->GetName() << "_ != ";
+ if (field->GetFieldType() == ScalarField::kFieldType) {
+ s << std::get<int64_t>(constraint->second) << ")";
+ s << "{ return false;}";
+ } else if (field->GetFieldType() == EnumField::kFieldType) {
+ s << std::get<std::string>(constraint->second) << ")";
+ s << "{ return false;}";
+ } else {
+ ERROR(field) << "Constraints on non enum/scalar fields should be impossible.";
+ }
+ }
+ }
+ s << "return true;}";
+ }
+}
diff --git a/gd/packet/parser/parent_def.h b/gd/packet/parser/parent_def.h
new file mode 100644
index 0000000..a293a26
--- /dev/null
+++ b/gd/packet/parser/parent_def.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <map>
+#include <variant>
+
+#include "enum_def.h"
+#include "field_list.h"
+#include "fields/all_fields.h"
+#include "fields/packet_field.h"
+#include "parse_location.h"
+#include "type_def.h"
+
+class ParentDef : public TypeDef {
+ public:
+ ParentDef(std::string name, FieldList fields);
+ ParentDef(std::string name, FieldList fields, ParentDef* parent);
+
+ void AddParentConstraint(std::string field_name, std::variant<int64_t, std::string> value);
+
+ // Assign all size fields to their corresponding variable length fields.
+ // Will crash if
+ // - there aren't any fields that don't match up to a field.
+ // - the size field points to a fixed size field.
+ // - if the size field comes after the variable length field.
+ void AssignSizeFields();
+
+ void SetEndianness(bool is_little_endian);
+
+ // Get the size. You scan specify without_payload to exclude payload and body fields as children override them.
+ Size GetSize(bool without_payload = false) const;
+
+ // Get the offset until the field is reached, if there is no field
+ // returns an empty Size. from_end requests the offset to the field
+ // starting from the end() iterator. If there is a field with an unknown
+ // size along the traversal, then an empty size is returned.
+ Size GetOffsetForField(std::string field_name, bool from_end = false) const;
+
+ FieldList GetParamList() const;
+
+ void GenMembers(std::ostream& s) const;
+
+ void GenSize(std::ostream& s) const;
+
+ void GenSerialize(std::ostream& s) const;
+
+ void GenInstanceOf(std::ostream& s) const;
+
+ FieldList fields_;
+
+ ParentDef* parent_{nullptr};
+
+ std::map<std::string, std::variant<int64_t, std::string>> parent_constraints_;
+ bool is_little_endian_;
+};
diff --git a/gd/packet/parser/parse_location.h b/gd/packet/parser/parse_location.h
new file mode 100644
index 0000000..80bdc72
--- /dev/null
+++ b/gd/packet/parser/parse_location.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+class ParseLocation {
+ public:
+ ParseLocation() : line_(-1) {}
+
+ ParseLocation(int line) : line_(line) {}
+
+ int GetLine() {
+ return line_;
+ }
+
+ private:
+ int line_;
+};
diff --git a/gd/packet/parser/size.h b/gd/packet/parser/size.h
new file mode 100644
index 0000000..e73bff0
--- /dev/null
+++ b/gd/packet/parser/size.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <iterator>
+#include <sstream>
+#include <string>
+#include <vector>
+
+class Size {
+ public:
+ Size() {}
+
+ Size(int bits) {
+ is_valid_ = true;
+ bits_ = bits;
+ }
+
+ Size(std::string dynamic) {
+ is_valid_ = true;
+ dynamic_.push_back(dynamic);
+ }
+
+ Size(int bits, std::string dynamic) {
+ is_valid_ = true;
+ bits_ = bits;
+ dynamic_.push_back(dynamic);
+ }
+
+ Size(const Size& size) {
+ is_valid_ = size.is_valid_;
+ bits_ = size.bits_;
+ dynamic_ = size.dynamic_;
+ }
+
+ std::string dynamic_string() const {
+ if (dynamic_.empty()) return "0";
+
+ std::stringstream result;
+ // Print everything but the last element then append it manually to avoid
+ // the trailing "+" operator.
+ std::copy(dynamic_.begin(), dynamic_.end() - 1, std::ostream_iterator<std::string>(result, " + "));
+ result << dynamic_.back();
+ return result.str();
+ }
+
+ std::vector<std::string> dynamic_string_list() {
+ return dynamic_;
+ }
+
+ bool empty() const {
+ return !is_valid_;
+ }
+
+ bool has_bits() const {
+ return bits_ != 0;
+ }
+
+ bool has_dynamic() const {
+ return !dynamic_.empty();
+ }
+
+ int bits() const {
+ return bits_;
+ }
+
+ int bytes() const {
+ return bits_ / 8;
+ }
+
+ Size operator+(int rhs) {
+ return Size(bits_ + rhs);
+ }
+
+ Size operator+(std::string rhs) {
+ auto ret = Size();
+ ret.is_valid_ = true;
+ ret.dynamic_.insert(ret.dynamic_.end(), dynamic_.begin(), dynamic_.end());
+ ret.dynamic_.push_back(rhs);
+ return ret;
+ }
+
+ Size operator+(const Size& rhs) {
+ auto ret = Size(bits_ + rhs.bits_);
+ ret.is_valid_ = is_valid_ && rhs.is_valid_;
+ ret.dynamic_.insert(ret.dynamic_.end(), dynamic_.begin(), dynamic_.end());
+ ret.dynamic_.insert(ret.dynamic_.end(), rhs.dynamic_.begin(), rhs.dynamic_.end());
+ return ret;
+ }
+
+ Size& operator+=(int rhs) {
+ is_valid_ = true;
+ bits_ += rhs;
+ return *this;
+ }
+
+ Size& operator+=(std::string rhs) {
+ is_valid_ = true;
+ dynamic_.push_back(rhs);
+ return *this;
+ }
+
+ Size& operator+=(const Size& rhs) {
+ is_valid_ = is_valid_ && rhs.is_valid_;
+ bits_ += rhs.bits_;
+ dynamic_.insert(dynamic_.end(), rhs.dynamic_.begin(), rhs.dynamic_.end());
+ return *this;
+ }
+
+ std::string ToString() const {
+ std::stringstream str;
+ str << "/* Bits: */ " << bits_ << " + /* Dynamic: */ " << dynamic_string();
+ if (!is_valid_) {
+ str << " (invalid) ";
+ }
+ return str.str();
+ }
+
+ friend std::ostream& operator<<(std::ostream& os, const Size& rhs) {
+ return os << rhs.ToString();
+ }
+
+ private:
+ bool is_valid_ = false;
+ int bits_ = 0;
+ std::vector<std::string> dynamic_;
+};
diff --git a/gd/packet/parser/struct_def.cc b/gd/packet/parser/struct_def.cc
new file mode 100644
index 0000000..bdeb780
--- /dev/null
+++ b/gd/packet/parser/struct_def.cc
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2019 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 "struct_def.h"
+
+#include "fields/all_fields.h"
+#include "util.h"
+
+StructDef::StructDef(std::string name, FieldList fields) : StructDef(name, fields, nullptr) {}
+StructDef::StructDef(std::string name, FieldList fields, StructDef* parent)
+ : ParentDef(name, fields, parent), total_size_(GetSize(true)) {}
+
+PacketField* StructDef::GetNewField(const std::string& name, ParseLocation loc) const {
+ if (fields_.HasBody()) {
+ return new VariableLengthStructField(name, name_, loc);
+ } else {
+ return new StructField(name, name_, total_size_, loc);
+ }
+}
+
+TypeDef::Type StructDef::GetDefinitionType() const {
+ return TypeDef::Type::STRUCT;
+}
+
+void StructDef::GenSpecialize(std::ostream& s) const {
+ if (parent_ == nullptr) {
+ return;
+ }
+ s << "static " << name_ << "* Specialize(" << parent_->name_ << "* parent) {";
+ s << "ASSERT(" << name_ << "::IsInstance(*parent));";
+ s << "return static_cast<" << name_ << "*>(parent);";
+ s << "}";
+}
+
+void StructDef::GenParse(std::ostream& s) const {
+ std::string iterator = (is_little_endian_ ? "Iterator<kLittleEndian>" : "Iterator<!kLittleEndian>");
+
+ if (fields_.HasBody()) {
+ s << "static std::optional<" << iterator << ">";
+ } else {
+ s << "static " << iterator;
+ }
+
+ s << " Parse(" << name_ << "* to_fill, " << iterator << " struct_begin_it ";
+
+ if (parent_ != nullptr) {
+ s << ", bool fill_parent = true) {";
+ } else {
+ s << ") {";
+ }
+ s << "auto to_bound = struct_begin_it;";
+
+ if (parent_ != nullptr) {
+ s << "if (fill_parent) {";
+ std::string parent_param = (parent_->parent_ == nullptr ? "" : ", true");
+ if (parent_->fields_.HasBody()) {
+ s << "auto parent_optional_it = " << parent_->name_ << "::Parse(to_fill, to_bound" << parent_param << ");";
+ if (fields_.HasBody()) {
+ s << "if (!parent_optional_it) { return {}; }";
+ } else {
+ s << "ASSERT(parent_optional_it);";
+ }
+ } else {
+ s << parent_->name_ << "::Parse(to_fill, to_bound" << parent_param << ");";
+ }
+ s << "}";
+ }
+
+ if (!fields_.HasBody()) {
+ s << "size_t end_index = struct_begin_it.NumBytesRemaining();";
+ if (parent_ != nullptr) {
+ s << "if (end_index < " << GetSize().bytes() << " - to_fill->" << parent_->name_ << "::size())";
+ } else {
+ s << "if (end_index < " << GetSize().bytes() << ")";
+ }
+ s << "{ return struct_begin_it.Subrange(0,0);}";
+ }
+
+ for (const auto& field : fields_) {
+ if (field->GetFieldType() != ReservedField::kFieldType && field->GetFieldType() != BodyField::kFieldType &&
+ field->GetFieldType() != FixedScalarField::kFieldType && field->GetFieldType() != SizeField::kFieldType &&
+ field->GetFieldType() != ChecksumStartField::kFieldType && field->GetFieldType() != ChecksumField::kFieldType &&
+ field->GetFieldType() != CountField::kFieldType) {
+ s << "{";
+ s << "if (to_bound.NumBytesRemaining() < " << field->GetSize().bytes() << ")";
+ if (!fields_.HasBody()) {
+ s << "{ return to_bound.Subrange(to_bound.NumBytesRemaining(),0);}";
+ } else {
+ s << "{ return {};}";
+ }
+ int num_leading_bits =
+ field->GenBounds(s, GetStructOffsetForField(field->GetName()), Size(), field->GetStructSize());
+ s << "auto " << field->GetName() << "_ptr = &to_fill->" << field->GetName() << "_;";
+ field->GenExtractor(s, num_leading_bits, true);
+ s << "}";
+ }
+ if (field->GetFieldType() == CountField::kFieldType || field->GetFieldType() == SizeField::kFieldType) {
+ s << field->GetDataType() << " " << field->GetName() << "_extracted;";
+ s << "{";
+ s << "if (to_bound.NumBytesRemaining() < " << field->GetSize().bytes() << ")";
+ if (!fields_.HasBody()) {
+ s << "{ return to_bound.Subrange(to_bound.NumBytesRemaining(),0);}";
+ } else {
+ s << "{ return {};}";
+ }
+ int num_leading_bits =
+ field->GenBounds(s, GetStructOffsetForField(field->GetName()), Size(), field->GetStructSize());
+ s << "auto " << field->GetName() << "_ptr = &" << field->GetName() << "_extracted;";
+ field->GenExtractor(s, num_leading_bits, true);
+ s << "}";
+ }
+ }
+ s << "return struct_begin_it + to_fill->" << name_ << "::size();";
+ s << "}";
+}
+
+void StructDef::GenParseFunctionPrototype(std::ostream& s) const {
+ s << "std::unique_ptr<" << name_ << "> Parse" << name_ << "(";
+ if (is_little_endian_) {
+ s << "Iterator<kLittleEndian>";
+ } else {
+ s << "Iterator<!kLittleEndian>";
+ }
+ s << "it);";
+}
+
+void StructDef::GenDefinition(std::ostream& s) const {
+ s << "class " << name_;
+ if (parent_ != nullptr) {
+ s << " : public " << parent_->name_;
+ } else {
+ if (is_little_endian_) {
+ s << " : public PacketStruct<kLittleEndian>";
+ } else {
+ s << " : public PacketStruct<!kLittleEndian>";
+ }
+ }
+ s << " {";
+ s << " public:";
+
+ GenConstructor(s);
+
+ s << " public:\n";
+ s << " virtual ~" << name_ << "() override = default;\n";
+
+ GenSerialize(s);
+ s << "\n";
+
+ GenParse(s);
+ s << "\n";
+
+ GenSize(s);
+ s << "\n";
+
+ GenInstanceOf(s);
+ s << "\n";
+
+ GenSpecialize(s);
+ s << "\n";
+
+ GenMembers(s);
+ s << "};\n";
+
+ if (fields_.HasBody()) {
+ GenParseFunctionPrototype(s);
+ }
+ s << "\n";
+}
+
+void StructDef::GenDefinitionPybind11(std::ostream& s) const {
+ s << "py::class_<" << name_;
+ if (parent_ != nullptr) {
+ s << ", " << parent_->name_;
+ } else {
+ if (is_little_endian_) {
+ s << ", PacketStruct<kLittleEndian>";
+ } else {
+ s << ", PacketStruct<!kLittleEndian>";
+ }
+ }
+ s << ">(m, \"" << name_ << "\")";
+ s << ".def(py::init<>())";
+ s << ".def(\"Serialize\", &" << GetTypeName() << "::Serialize)";
+ s << ".def(\"Parse\", &" << name_ << "::Parse)";
+ s << ";\n";
+}
+
+void StructDef::GenConstructor(std::ostream& s) const {
+ if (parent_ != nullptr) {
+ s << name_ << "(const " << parent_->name_ << "& parent) : " << parent_->name_ << "(parent) {}";
+ s << name_ << "() : " << parent_->name_ << "() {";
+ } else {
+ s << name_ << "() {";
+ }
+
+ // Get the list of parent params.
+ FieldList parent_params;
+ if (parent_ != nullptr) {
+ parent_params = parent_->GetParamList().GetFieldsWithoutTypes({
+ PayloadField::kFieldType,
+ BodyField::kFieldType,
+ });
+
+ // Set constrained parent fields to their correct values.
+ for (int i = 0; i < parent_params.size(); i++) {
+ const auto& field = parent_params[i];
+ const auto& constraint = parent_constraints_.find(field->GetName());
+ if (constraint != parent_constraints_.end()) {
+ s << parent_->name_ << "::" << field->GetName() << "_ = ";
+ if (field->GetFieldType() == ScalarField::kFieldType) {
+ s << std::get<int64_t>(constraint->second) << ";";
+ } else if (field->GetFieldType() == EnumField::kFieldType) {
+ s << std::get<std::string>(constraint->second) << ";";
+ } else {
+ ERROR(field) << "Constraints on non enum/scalar fields should be impossible.";
+ }
+ }
+ }
+ }
+
+ s << "}\n";
+}
+
+Size StructDef::GetStructOffsetForField(std::string field_name) const {
+ auto size = Size(0);
+ for (auto it = fields_.begin(); it != fields_.end(); it++) {
+ // We've reached the field, end the loop.
+ if ((*it)->GetName() == field_name) break;
+ const auto& field = *it;
+ // When we need to parse this field, all previous fields should already be parsed.
+ if (field->GetStructSize().empty()) {
+ ERROR() << "Empty size for field " << (*it)->GetName() << " finding the offset for field: " << field_name;
+ }
+ size += field->GetStructSize();
+ }
+
+ // We need the offset until a body field.
+ if (parent_ != nullptr) {
+ auto parent_body_offset = static_cast<StructDef*>(parent_)->GetStructOffsetForField("body");
+ if (parent_body_offset.empty()) {
+ ERROR() << "Empty offset for body in " << parent_->name_ << " finding the offset for field: " << field_name;
+ }
+ size += parent_body_offset;
+ }
+
+ return size;
+}
diff --git a/gd/packet/parser/struct_def.h b/gd/packet/parser/struct_def.h
new file mode 100644
index 0000000..74c1b04
--- /dev/null
+++ b/gd/packet/parser/struct_def.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <map>
+#include <variant>
+
+#include "field_list.h"
+#include "fields/packet_field.h"
+#include "parent_def.h"
+#include "parse_location.h"
+#include "type_def.h"
+
+class StructDef : public ParentDef {
+ public:
+ StructDef(std::string name, FieldList fields);
+ StructDef(std::string name, FieldList fields, StructDef* parent);
+
+ PacketField* GetNewField(const std::string& name, ParseLocation loc) const;
+
+ TypeDef::Type GetDefinitionType() const;
+
+ void GenSpecialize(std::ostream& s) const;
+
+ void GenParse(std::ostream& s) const;
+
+ void GenParseFunctionPrototype(std::ostream& s) const;
+
+ void GenDefinition(std::ostream& s) const;
+
+ void GenDefinitionPybind11(std::ostream& s) const;
+
+ void GenConstructor(std::ostream& s) const;
+
+ Size GetStructOffsetForField(std::string field_name) const;
+
+ private:
+ Size total_size_;
+};
diff --git a/gd/packet/parser/struct_parser_generator.cc b/gd/packet/parser/struct_parser_generator.cc
new file mode 100644
index 0000000..352219e
--- /dev/null
+++ b/gd/packet/parser/struct_parser_generator.cc
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2019 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 "struct_parser_generator.h"
+
+StructParserGenerator::StructParserGenerator(const Declarations& decls) {
+ is_little_endian = decls.is_little_endian;
+ for (const auto& s : decls.type_defs_queue_) {
+ if (s.second->GetDefinitionType() == TypeDef::Type::STRUCT) {
+ const auto* struct_def = dynamic_cast<const StructDef*>(s.second);
+ variable_struct_fields_.emplace_back(struct_def);
+ }
+ }
+ for (const auto& node : variable_struct_fields_) {
+ if (node.struct_def_->parent_ != nullptr) {
+ for (auto& parent : variable_struct_fields_) {
+ if (node.struct_def_->parent_->name_ == parent.struct_def_->name_) {
+ parent.children_.push_back(&node);
+ }
+ }
+ }
+ }
+}
+
+void StructParserGenerator::explore_children(const TreeNode& node, std::ostream& s) const {
+ auto field = node.packet_field_;
+ if (!node.children_.empty()) {
+ s << "bool " << field->GetName() << "_child_found = false; /* Greedy match */";
+ }
+ for (const auto& child : node.children_) {
+ s << "if (!" << field->GetName() << "_child_found && ";
+ s << child->struct_def_->name_ << "::IsInstance(*" << field->GetName() << "_value.get())) {";
+ s << field->GetName() << "_child_found = true;";
+ s << "std::unique_ptr<" << child->struct_def_->name_ << "> " << child->packet_field_->GetName() << "_value;";
+ s << child->packet_field_->GetName() << "_value.reset(new ";
+ s << child->struct_def_->name_ << "(*" << field->GetName() << "_value));";
+ if (child->struct_def_->fields_.HasBody()) {
+ s << "auto optional_it = ";
+ s << child->struct_def_->name_ << "::Parse( " << child->packet_field_->GetName() << "_value.get(), ";
+ s << "to_bound, false);";
+ s << "if (optional_it) {";
+ s << "} else { return " << field->GetName() << "_value;}";
+ } else {
+ s << child->struct_def_->name_ << "::Parse( " << child->packet_field_->GetName() << "_value.get(), ";
+ s << "to_bound, false);";
+ }
+ explore_children(*child, s);
+ s << field->GetName() << "_value = std::move(" << child->packet_field_->GetName() << "_value);";
+
+ s << " }";
+ }
+}
+
+void StructParserGenerator::Generate(std::ostream& s) const {
+ for (const auto& node : variable_struct_fields_) {
+ if (node.children_.empty()) {
+ continue;
+ }
+ auto field = node.packet_field_;
+ s << "inline std::unique_ptr<" << node.struct_def_->name_ << "> Parse" << node.struct_def_->name_;
+ if (is_little_endian) {
+ s << "(Iterator<kLittleEndian> to_bound) {";
+ } else {
+ s << "(Iterator<!kLittleEndian> to_bound) {";
+ }
+ s << field->GetDataType() << " " << field->GetName() << "_value = ";
+ s << "std::make_unique<" << node.struct_def_->name_ << ">();";
+
+ s << "auto " << field->GetName() << "_it = to_bound;";
+ s << "auto optional_it = ";
+ s << node.struct_def_->name_ << "::Parse( " << field->GetName() << "_value.get(), ";
+ s << field->GetName() << "_it";
+ if (node.struct_def_->parent_ != nullptr) {
+ s << ", true);";
+ } else {
+ s << ");";
+ }
+ s << "if (optional_it) {";
+ s << field->GetName() << "_it = *optional_it;";
+ s << "} else { return nullptr; }";
+
+ explore_children(node, s);
+ s << "return " << field->GetName() << "_value; }";
+ }
+}
diff --git a/gd/packet/parser/struct_parser_generator.h b/gd/packet/parser/struct_parser_generator.h
new file mode 100644
index 0000000..0315460
--- /dev/null
+++ b/gd/packet/parser/struct_parser_generator.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <iostream>
+
+#include "declarations.h"
+#include "fields/packet_field.h"
+#include "parse_location.h"
+
+class StructParserGenerator {
+ public:
+ explicit StructParserGenerator(const Declarations& declarations);
+
+ void Generate(std::ostream& s) const;
+
+ private:
+ class TreeNode {
+ public:
+ explicit TreeNode(const StructDef* s)
+ : struct_def_(s), packet_field_(s->GetNewField(s->name_ + "_parse", ParseLocation())) {}
+ const StructDef* struct_def_;
+ const PacketField* packet_field_;
+ std::list<const TreeNode*> children_;
+ };
+ std::list<TreeNode> variable_struct_fields_;
+ bool is_little_endian;
+
+ void explore_children(const TreeNode& node, std::ostream& s) const;
+};
diff --git a/gd/packet/parser/test/Android.bp b/gd/packet/parser/test/Android.bp
new file mode 100644
index 0000000..65b2f3e
--- /dev/null
+++ b/gd/packet/parser/test/Android.bp
@@ -0,0 +1,24 @@
+genrule {
+ name: "BluetoothPacketParserTestPacketPdlGen_h",
+ tools: [
+ "bluetooth_packetgen",
+ ],
+ cmd: "$(location bluetooth_packetgen) --include=system/bt/gd --out=$(genDir) $(in)",
+ srcs: [
+ "test_packets.pdl",
+ "big_endian_test_packets.pdl",
+ ],
+ out: [
+ "packet/parser/test/test_packets.h",
+ "packet/parser/test/big_endian_test_packets.h",
+ ],
+}
+
+filegroup {
+ name: "BluetoothPacketParserTestPacketTestSources",
+ srcs: [
+ "generated_packet_test.cc",
+ "six_bytes.cc",
+ "variable.cc",
+ ],
+}
diff --git a/gd/packet/parser/test/big_endian_test_packets.pdl b/gd/packet/parser/test/big_endian_test_packets.pdl
new file mode 100644
index 0000000..5647ea6
--- /dev/null
+++ b/gd/packet/parser/test/big_endian_test_packets.pdl
@@ -0,0 +1,266 @@
+big_endian_packets
+
+custom_field SixBytes : 48 "packet/parser/test/"
+custom_field Variable "packet/parser/test/"
+
+packet ParentBe {
+ _fixed_ = 0x12 : 8,
+ _size_(_payload_) : 8,
+ _payload_,
+ footer : 8,
+}
+
+packet ChildBe : ParentBe {
+ field_name : 16,
+}
+
+enum FourBitsBe : 4 {
+ ONE = 1,
+ TWO = 2,
+ THREE = 3,
+ FIVE = 5,
+ TEN = 10,
+ LAZY_ME = 15,
+}
+
+packet ParentTwoBe {
+ _reserved_ : 4,
+ four_bits : FourBitsBe,
+ _payload_,
+}
+
+packet ChildTwoThreeBe : ParentTwoBe (four_bits = THREE) {
+ more_bits : FourBitsBe,
+ _reserved_ : 4,
+ sixteen_bits : 16
+}
+
+packet ChildTwoTwoBe : ParentTwoBe (four_bits = TWO) {
+ more_bits : FourBitsBe,
+ _reserved_ : 4,
+}
+
+packet ChildTwoTwoThreeBe :ChildTwoTwoBe (more_bits = THREE) {
+}
+
+enum TwoBitsBe : 2 {
+ ZERO = 0,
+ ONE = 1,
+ TWO = 2,
+ THREE = 3,
+}
+
+packet MiddleFourBitsBe {
+ low_two : TwoBitsBe,
+ next_four : FourBitsBe,
+ straddle : FourBitsBe,
+ four_more : FourBitsBe,
+ high_two : TwoBitsBe,
+}
+
+packet ParentWithSixBytesBe {
+ two_bytes : 16,
+ six_bytes : SixBytes,
+ _payload_,
+}
+
+packet ChildWithSixBytesBe : ParentWithSixBytesBe (two_bytes = 0x1234) {
+ child_six_bytes : SixBytes,
+}
+
+checksum SimpleSum : 16 "packet/parser/test/"
+
+packet ParentWithSumBe {
+ two_bytes : 16,
+ _checksum_start_(example_checksum),
+ sum_bytes : 16,
+ _payload_,
+ example_checksum : SimpleSum,
+}
+
+packet ChildWithSumBe : ParentWithSumBe {
+ more_bytes : 32,
+ another_byte : 8,
+}
+
+packet ChildWithNestedSumBe : ParentWithSumBe {
+ _checksum_start_(nested_checksum),
+ more_bytes : 32,
+ nested_checksum : SimpleSum,
+}
+
+packet ParentSizeModifierBe {
+ _size_(_payload_) : 8,
+ _payload_ : [+2*8], // Include two_bytes in the size
+ two_bytes : 16,
+}
+
+packet ChildSizeModifierBe : ParentSizeModifierBe (two_bytes = 0x1211) {
+ more_bytes : 32,
+}
+
+enum ForArraysBe : 16 {
+ ONE = 0x0001,
+ TWO = 0x0002,
+ ONE_TWO = 0x0201,
+ TWO_THREE = 0x0302,
+ FFFF = 0xffff,
+}
+
+packet FixedArrayEnumBe {
+ enum_array : ForArraysBe[5],
+}
+
+packet SizedArrayEnumBe {
+ _size_(enum_array) : 16,
+ enum_array : ForArraysBe[],
+}
+
+packet CountArrayEnumBe {
+ _count_(enum_array) : 8,
+ enum_array : ForArraysBe[],
+}
+
+packet SizedArrayCustomBe {
+ _size_(six_bytes_array) : 8,
+ an_extra_byte : 8,
+ six_bytes_array : SixBytes[+1*8],
+}
+
+packet FixedArrayCustomBe {
+ six_bytes_array : SixBytes[5],
+}
+
+packet CountArrayCustomBe {
+ _count_(six_bytes_array) : 8,
+ six_bytes_array : SixBytes[],
+}
+
+packet PacketWithFixedArraysOfBytesBe {
+ fixed_256bit_in_bytes : 8[32],
+ fixed_256bit_in_words : 32[8],
+}
+
+packet OneVariableBe {
+ one : Variable,
+}
+
+packet SizedArrayVariableBe {
+ _size_(variable_array) : 8,
+ variable_array : Variable[],
+}
+
+packet FixedArrayVariableBe {
+ variable_array : Variable[5],
+}
+
+packet CountArrayVariableBe {
+ _count_(variable_array) : 8,
+ variable_array : Variable[],
+}
+
+struct TwoRelatedNumbersBe {
+ id : 8,
+ count : 16,
+}
+
+packet OneStructBe {
+ one : TwoRelatedNumbersBe,
+}
+
+packet TwoStructsBe {
+ one : TwoRelatedNumbersBe,
+ two : TwoRelatedNumbersBe,
+}
+
+packet ArrayOfStructBe {
+ _count_(array) : 8,
+ array : TwoRelatedNumbersBe[],
+}
+
+struct StructWithFixedTypesBe {
+ four_bits : FourBitsBe,
+ _reserved_ : 4,
+ _checksum_start_(example_checksum),
+ _fixed_ = 0xf3 : 8,
+ id : 8,
+ array : 8[3],
+ example_checksum : SimpleSum,
+ six_bytes : SixBytes,
+}
+
+packet OneFixedTypesStructBe {
+ one : StructWithFixedTypesBe,
+}
+
+packet ArrayOfStructAndAnotherBe {
+ _count_(array) : 8,
+ array : TwoRelatedNumbersBe[],
+ another : TwoRelatedNumbersBe,
+}
+
+group BitFieldGroupBe {
+ seven_bits : 7,
+ straddle : 4,
+ five_bits : 5,
+}
+
+packet BitFieldGroupPacketBe {
+ BitFieldGroupBe,
+}
+
+packet BitFieldGroupAfterPayloadPacketBe {
+ _payload_,
+ BitFieldGroupBe,
+}
+
+packet BitFieldGroupAfterUnsizedArrayPacketBe : BitFieldGroupAfterPayloadPacketBe {
+ array : 8[],
+}
+
+struct BitFieldBe {
+ seven_bits : 7,
+ straddle : 4,
+ five_bits : 5,
+}
+
+packet BitFieldPacketBe {
+ bit_field : BitFieldBe,
+}
+
+packet BitFieldAfterPayloadPacketBe {
+ _payload_,
+ bit_field : BitFieldBe,
+}
+
+packet BitFieldAfterUnsizedArrayPacketBe : BitFieldAfterPayloadPacketBe {
+ array : 8[],
+}
+
+packet BitFieldArrayPacketBe {
+ _size_(array): 8,
+ array : BitFieldBe[],
+}
+
+struct VersionlessStructBe {
+ one_number : 8,
+}
+
+packet OneVersionlessStructPacketBe {
+ versionless : VersionlessStructBe,
+ _payload_,
+}
+
+packet OneVersionedStructPacketBe : OneVersionlessStructPacketBe {
+ version : 8,
+ _payload_,
+}
+
+packet OneVersionOneStructPacketBe : OneVersionedStructPacketBe (version = 0x01) {
+ just_one_number : 8,
+}
+
+packet OneVersionTwoStructPacketBe : OneVersionedStructPacketBe (version = 0x02) {
+ one_number : 8,
+ another_number : 8,
+}
diff --git a/gd/packet/parser/test/generated_packet_test.cc b/gd/packet/parser/test/generated_packet_test.cc
new file mode 100644
index 0000000..f8454a2
--- /dev/null
+++ b/gd/packet/parser/test/generated_packet_test.cc
@@ -0,0 +1,1882 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#define PACKET_TESTING
+#include "packet/parser/test/big_endian_test_packets.h"
+#include "packet/parser/test/test_packets.h"
+
+#include <gtest/gtest.h>
+#include <forward_list>
+#include <memory>
+
+#include "os/log.h"
+#include "packet/bit_inserter.h"
+#include "packet/parser/test/six_bytes.h"
+#include "packet/raw_builder.h"
+
+using ::bluetooth::packet::BitInserter;
+using ::bluetooth::packet::kLittleEndian;
+using ::bluetooth::packet::RawBuilder;
+using ::bluetooth::packet::parser::test::SixBytes;
+using std::vector;
+
+namespace {
+vector<uint8_t> child_two_two_three = {
+ 0x20 /* Reserved : 4, FourBits::TWO */,
+ 0x03 /* FourBits::THREE, Reserved : 4 */,
+};
+vector<uint8_t> child = {
+ 0x12 /* fixed */, 0x02 /* Size of the payload */, 0xa1 /* First byte of the payload */, 0xa2, 0xb1 /* footer */,
+};
+vector<uint8_t> child_with_six_bytes = {
+ 0x34 /* TwoBytes */,
+ 0x12,
+ 0xa1 /* First byte of the six_bytes */,
+ 0xa2,
+ 0xa3,
+ 0xa4,
+ 0xa5,
+ 0xa6,
+ 0xb1 /* Second six_bytes*/,
+ 0xb2,
+ 0xb3,
+ 0xb4,
+ 0xb5,
+ 0xb6,
+};
+
+} // namespace
+
+namespace bluetooth {
+namespace packet {
+namespace parser {
+using namespace test;
+
+TEST(GeneratedPacketTest, testChildTwoTwoThree) {
+ auto packet = ChildTwoTwoThreeBuilder::Create();
+
+ ASSERT_EQ(child_two_two_three.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(packet_bytes->size(), child_two_two_three.size());
+ for (size_t i = 0; i < child_two_two_three.size(); i++) {
+ ASSERT_EQ(packet_bytes->at(i), child_two_two_three[i]);
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ ParentView wrong_view = ParentView::Create(packet_bytes_view);
+ ASSERT_FALSE(wrong_view.IsValid());
+
+ ParentTwoView parent_view = ParentTwoView::Create(packet_bytes_view);
+ ASSERT_TRUE(parent_view.IsValid());
+ ASSERT_EQ(FourBits::TWO, parent_view.GetFourBits());
+
+ ChildTwoTwoView child_view = ChildTwoTwoView::Create(parent_view);
+ ASSERT_TRUE(child_view.IsValid());
+ ASSERT_EQ(FourBits::THREE, child_view.GetMoreBits());
+
+ ChildTwoTwoThreeView grandchild_view = ChildTwoTwoThreeView::Create(child_view);
+ ASSERT_TRUE(grandchild_view.IsValid());
+}
+
+TEST(GeneratedPacketTest, testChild) {
+ uint16_t field_name = 0xa2a1;
+ uint8_t footer = 0xb1;
+ auto packet = ChildBuilder::Create(field_name, footer);
+
+ ASSERT_EQ(child.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(packet_bytes->size(), child.size());
+ for (size_t i = 0; i < child.size(); i++) {
+ ASSERT_EQ(packet_bytes->at(i), child[i]);
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ ParentView parent_view = ParentView::Create(packet_bytes_view);
+ ASSERT_TRUE(parent_view.IsValid());
+ auto payload = parent_view.GetPayload();
+
+ ASSERT_EQ(child[1 /* skip fixed field */], payload.size());
+ for (size_t i = 0; i < payload.size(); i++) {
+ ASSERT_EQ(child[i + 2 /* fixed & size */], payload[i]);
+ }
+
+ ChildView child_view = ChildView::Create(parent_view);
+ ASSERT_TRUE(child_view.IsValid());
+
+ ASSERT_EQ(field_name, child_view.GetFieldName());
+}
+
+TEST(GeneratedPacketTest, testValidateWayTooSmall) {
+ std::vector<uint8_t> too_small_bytes = {0x34};
+ auto too_small = std::make_shared<std::vector<uint8_t>>(too_small_bytes.begin(), too_small_bytes.end());
+
+ ParentWithSixBytesView invalid_parent = ParentWithSixBytesView::Create(too_small);
+ ASSERT_FALSE(invalid_parent.IsValid());
+ ChildWithSixBytesView invalid = ChildWithSixBytesView::Create(ParentWithSixBytesView::Create(too_small));
+ ASSERT_FALSE(invalid.IsValid());
+}
+
+TEST(GeneratedPacketTest, testValidateTooSmall) {
+ std::vector<uint8_t> too_small_bytes = {0x34, 0x12, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x11};
+ auto too_small = std::make_shared<std::vector<uint8_t>>(too_small_bytes.begin(), too_small_bytes.end());
+
+ ParentWithSixBytesView valid_parent = ParentWithSixBytesView::Create(too_small);
+ ASSERT_TRUE(valid_parent.IsValid());
+ ChildWithSixBytesView invalid = ChildWithSixBytesView::Create(ParentWithSixBytesView::Create(too_small));
+ ASSERT_FALSE(invalid.IsValid());
+}
+
+TEST(GeneratedPacketTest, testValidateJustRight) {
+ std::vector<uint8_t> just_right_bytes = {0x34, 0x12, 0x01, 0x02, 0x03, 0x04, 0x05,
+ 0x06, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16};
+ auto just_right = std::make_shared<std::vector<uint8_t>>(just_right_bytes.begin(), just_right_bytes.end());
+
+ ChildWithSixBytesView valid = ChildWithSixBytesView::Create(ParentWithSixBytesView::Create(just_right));
+ ASSERT_TRUE(valid.IsValid());
+}
+
+TEST(GeneratedPacketTest, testValidateTooBig) {
+ std::vector<uint8_t> too_big_bytes = {0x34, 0x12, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x20};
+ auto too_big = std::make_shared<std::vector<uint8_t>>(too_big_bytes.begin(), too_big_bytes.end());
+
+ ChildWithSixBytesView lenient = ChildWithSixBytesView::Create(ParentWithSixBytesView::Create(too_big));
+ ASSERT_TRUE(lenient.IsValid());
+}
+
+TEST(GeneratedPacketTest, testValidateDeath) {
+ auto packet = ChildTwoTwoThreeBuilder::Create();
+
+ ASSERT_EQ(child_two_two_three.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(packet_bytes->size(), child_two_two_three.size());
+ for (size_t i = 0; i < child_two_two_three.size(); i++) {
+ ASSERT_EQ(packet_bytes->at(i), child_two_two_three[i]);
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ ParentView wrong_view = ParentView::Create(packet_bytes_view);
+ ASSERT_DEATH(wrong_view.GetPayload(), "validated");
+}
+
+TEST(GeneratedPacketTest, testValidatedParentDeath) {
+ uint16_t field_name = 0xa2a1;
+ uint8_t footer = 0xb1;
+ auto packet = ChildBuilder::Create(field_name, footer);
+
+ ASSERT_EQ(child.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(packet_bytes->size(), child.size());
+ for (size_t i = 0; i < child.size(); i++) {
+ ASSERT_EQ(packet_bytes->at(i), child[i]);
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ ParentView parent_view = ParentView::Create(packet_bytes_view);
+ ASSERT_TRUE(parent_view.IsValid());
+ auto payload = parent_view.GetPayload();
+
+ ASSERT_EQ(child[1 /* skip fixed field */], payload.size());
+ for (size_t i = 0; i < payload.size(); i++) {
+ ASSERT_EQ(child[i + 2 /* fixed & size */], payload[i]);
+ }
+
+ ChildView child_view = ChildView::Create(parent_view);
+ ASSERT_DEATH(child_view.GetFieldName(), "validated");
+}
+
+vector<uint8_t> middle_four_bits = {
+ 0x95, // low_two = ONE, next_four = FIVE, straddle = TEN
+ 0x8a, // straddle = TEN, four_more = TWO, high_two = TWO
+};
+
+TEST(GeneratedPacketTest, testMiddleFourBitsPacket) {
+ TwoBits low_two = TwoBits::ONE;
+ FourBits next_four = FourBits::FIVE;
+ FourBits straddle = FourBits::TEN;
+ FourBits four_more = FourBits::TWO;
+ TwoBits high_two = TwoBits::TWO;
+
+ auto packet = MiddleFourBitsBuilder::Create(low_two, next_four, straddle, four_more, high_two);
+
+ ASSERT_EQ(middle_four_bits.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(packet_bytes->size(), middle_four_bits.size());
+ for (size_t i = 0; i < middle_four_bits.size(); i++) {
+ ASSERT_EQ(packet_bytes->at(i), middle_four_bits[i]);
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ MiddleFourBitsView view = MiddleFourBitsView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ ASSERT_EQ(low_two, view.GetLowTwo());
+ ASSERT_EQ(next_four, view.GetNextFour());
+ ASSERT_EQ(straddle, view.GetStraddle());
+ ASSERT_EQ(four_more, view.GetFourMore());
+ ASSERT_EQ(high_two, view.GetHighTwo());
+}
+
+TEST(GeneratedPacketTest, testChildWithSixBytes) {
+ SixBytes six_bytes_a{{0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6}};
+ SixBytes six_bytes_b{{0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6}};
+ auto packet = ChildWithSixBytesBuilder::Create(six_bytes_a, six_bytes_b);
+
+ ASSERT_EQ(child_with_six_bytes.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(packet_bytes->size(), child_with_six_bytes.size());
+ for (size_t i = 0; i < child_with_six_bytes.size(); i++) {
+ ASSERT_EQ(packet_bytes->at(i), child_with_six_bytes[i]);
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ ParentWithSixBytesView parent_view = ParentWithSixBytesView::Create(packet_bytes_view);
+ ASSERT_TRUE(parent_view.IsValid());
+ ASSERT_EQ(six_bytes_a, parent_view.GetSixBytes());
+
+ ChildWithSixBytesView child_view = ChildWithSixBytesView::Create(parent_view);
+ ASSERT_TRUE(child_view.IsValid());
+
+ ASSERT_EQ(six_bytes_a, child_view.GetSixBytes());
+ ASSERT_EQ(six_bytes_a, ((ParentWithSixBytesView)child_view).GetSixBytes());
+ ASSERT_EQ(six_bytes_b, child_view.GetChildSixBytes());
+}
+
+namespace {
+vector<uint8_t> parent_with_sum = {
+ 0x11 /* TwoBytes */, 0x12, 0x21 /* Sum Bytes */, 0x22, 0x43 /* Sum, excluding TwoBytes */, 0x00,
+};
+
+} // namespace
+
+TEST(GeneratedPacketTest, testParentWithSum) {
+ uint16_t two_bytes = 0x1211;
+ uint16_t sum_bytes = 0x2221;
+ auto packet = ParentWithSumBuilder::Create(two_bytes, sum_bytes, std::make_unique<packet::RawBuilder>());
+
+ ASSERT_EQ(parent_with_sum.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(packet_bytes->size(), parent_with_sum.size());
+ for (size_t i = 0; i < parent_with_sum.size(); i++) {
+ ASSERT_EQ(packet_bytes->at(i), parent_with_sum[i]);
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ ParentWithSumView parent_view = ParentWithSumView::Create(packet_bytes_view);
+ ASSERT_TRUE(parent_view.IsValid());
+ ASSERT_EQ(two_bytes, parent_view.GetTwoBytes());
+
+ // Corrupt checksum
+ packet_bytes->back()++;
+ PacketView<kLittleEndian> corrupted_bytes_view(packet_bytes);
+ ParentWithSumView corrupted_view = ParentWithSumView::Create(corrupted_bytes_view);
+ ASSERT_FALSE(corrupted_view.IsValid());
+}
+
+namespace {
+vector<uint8_t> child_with_nested_sum = {
+ 0x11 /* TwoBytes */,
+ 0x12,
+ 0x21 /* Sum Bytes */,
+ 0x22,
+ 0x31 /* More Bytes */,
+ 0x32,
+ 0x33,
+ 0x34,
+ 0xca /* Nested Sum */,
+ 0x00,
+ 0xd7 /* Sum, excluding TwoBytes */,
+ 0x01,
+};
+
+} // namespace
+
+TEST(GeneratedPacketTest, testChildWithNestedSum) {
+ uint16_t two_bytes = 0x1211;
+ uint16_t sum_bytes = 0x2221;
+ uint32_t more_bytes = 0x34333231;
+ auto packet = ChildWithNestedSumBuilder::Create(two_bytes, sum_bytes, more_bytes);
+
+ ASSERT_EQ(child_with_nested_sum.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(packet_bytes->size(), child_with_nested_sum.size());
+ for (size_t i = 0; i < child_with_nested_sum.size(); i++) {
+ ASSERT_EQ(packet_bytes->at(i), child_with_nested_sum[i]);
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ ParentWithSumView parent_view = ParentWithSumView::Create(packet_bytes_view);
+ ASSERT_TRUE(parent_view.IsValid());
+ ASSERT_EQ(two_bytes, parent_view.GetTwoBytes());
+
+ ChildWithNestedSumView child_view = ChildWithNestedSumView::Create(parent_view);
+ ASSERT_TRUE(child_view.IsValid());
+
+ ASSERT_EQ(more_bytes, child_view.GetMoreBytes());
+}
+
+namespace {
+vector<uint8_t> parent_size_modifier = {
+ 0x02 /* Size */,
+ 0x11 /* TwoBytes */,
+ 0x12,
+};
+
+} // namespace
+
+TEST(GeneratedPacketTest, testParentSizeModifier) {
+ uint16_t two_bytes = 0x1211;
+ auto packet = ParentSizeModifierBuilder::Create(std::make_unique<RawBuilder>(), two_bytes);
+
+ ASSERT_EQ(parent_size_modifier.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(parent_size_modifier.size(), packet_bytes->size());
+ for (size_t i = 0; i < parent_size_modifier.size(); i++) {
+ ASSERT_EQ(parent_size_modifier[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ ParentSizeModifierView parent_view = ParentSizeModifierView::Create(packet_bytes_view);
+ ASSERT_TRUE(parent_view.IsValid());
+ ASSERT_EQ(two_bytes, parent_view.GetTwoBytes());
+}
+
+namespace {
+vector<uint8_t> child_size_modifier = {
+ 0x06 /* PayloadSize (TwoBytes + MoreBytes)*/,
+ 0x31 /* MoreBytes */,
+ 0x32,
+ 0x33,
+ 0x34,
+ 0x11 /* TwoBytes = 0x1211 */,
+ 0x12,
+};
+
+} // namespace
+
+TEST(GeneratedPacketTest, testChildSizeModifier) {
+ uint16_t two_bytes = 0x1211;
+ uint32_t more_bytes = 0x34333231;
+ auto packet = ChildSizeModifierBuilder::Create(more_bytes);
+
+ ASSERT_EQ(child_size_modifier.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(child_size_modifier.size(), packet_bytes->size());
+ for (size_t i = 0; i < child_size_modifier.size(); i++) {
+ ASSERT_EQ(child_size_modifier[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ ParentSizeModifierView parent_view = ParentSizeModifierView::Create(packet_bytes_view);
+ ASSERT_TRUE(parent_view.IsValid());
+ ASSERT_EQ(two_bytes, parent_view.GetTwoBytes());
+
+ ChildSizeModifierView child_view = ChildSizeModifierView::Create(parent_view);
+ ASSERT_TRUE(child_view.IsValid());
+
+ ASSERT_EQ(more_bytes, child_view.GetMoreBytes());
+}
+
+namespace {
+vector<uint8_t> fixed_array_enum{
+ 0x01, // ONE
+ 0x00,
+ 0x02, // TWO
+ 0x00,
+ 0x01, // ONE_TWO
+ 0x02,
+ 0x02, // TWO_THREE
+ 0x03,
+ 0xff, // FFFF
+ 0xff,
+};
+}
+
+TEST(GeneratedPacketTest, testFixedArrayEnum) {
+ std::array<ForArrays, 5> fixed_array{
+ {ForArrays::ONE, ForArrays::TWO, ForArrays::ONE_TWO, ForArrays::TWO_THREE, ForArrays::FFFF}};
+ auto packet = FixedArrayEnumBuilder::Create(fixed_array);
+ ASSERT_EQ(fixed_array_enum.size(), packet->size());
+
+ // Verify that the packet is independent from the array.
+ std::array<ForArrays, 5> copy_array(fixed_array);
+ fixed_array[1] = ForArrays::ONE;
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(fixed_array_enum.size(), packet_bytes->size());
+ for (size_t i = 0; i < fixed_array_enum.size(); i++) {
+ ASSERT_EQ(fixed_array_enum[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = FixedArrayEnumView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetEnumArray();
+ ASSERT_EQ(copy_array.size(), array.size());
+ for (size_t i = 0; i < copy_array.size(); i++) {
+ ASSERT_EQ(array[i], copy_array[i]);
+ }
+}
+
+namespace {
+vector<uint8_t> sized_array_enum{
+ 0x0a, // _size_
+ 0x00,
+ 0x01, // ONE
+ 0x00,
+ 0x02, // TWO
+ 0x00,
+ 0x01, // ONE_TWO
+ 0x02,
+ 0x02, // TWO_THREE
+ 0x03,
+ 0xff, // FFFF
+ 0xff,
+};
+}
+
+TEST(GeneratedPacketTest, testSizedArrayEnum) {
+ std::vector<ForArrays> sized_array{
+ {ForArrays::ONE, ForArrays::TWO, ForArrays::ONE_TWO, ForArrays::TWO_THREE, ForArrays::FFFF}};
+ auto packet = SizedArrayEnumBuilder::Create(sized_array);
+ ASSERT_EQ(sized_array_enum.size(), packet->size());
+
+ // Copy the original vector and modify it to make sure the packet is independent.
+ std::vector<ForArrays> copy_array(sized_array);
+ sized_array[1] = ForArrays::ONE;
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(sized_array_enum.size(), packet_bytes->size());
+ for (size_t i = 0; i < sized_array_enum.size(); i++) {
+ ASSERT_EQ(sized_array_enum[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = SizedArrayEnumView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetEnumArray();
+ ASSERT_EQ(copy_array.size(), array.size());
+ for (size_t i = 0; i < copy_array.size(); i++) {
+ ASSERT_EQ(array[i], copy_array[i]);
+ }
+}
+
+namespace {
+vector<uint8_t> count_array_enum{
+ 0x03, // _count_
+ 0x01, // ONE
+ 0x00,
+ 0x02, // TWO_THREE
+ 0x03,
+ 0xff, // FFFF
+ 0xff,
+};
+}
+
+TEST(GeneratedPacketTest, testCountArrayEnum) {
+ std::vector<ForArrays> count_array{{ForArrays::ONE, ForArrays::TWO_THREE, ForArrays::FFFF}};
+ auto packet = CountArrayEnumBuilder::Create(count_array);
+ ASSERT_EQ(count_array_enum.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(count_array_enum.size(), packet_bytes->size());
+ for (size_t i = 0; i < count_array_enum.size(); i++) {
+ ASSERT_EQ(count_array_enum[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = CountArrayEnumView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetEnumArray();
+ ASSERT_EQ(count_array.size(), array.size());
+ for (size_t i = 0; i < count_array.size(); i++) {
+ ASSERT_EQ(array[i], count_array[i]);
+ }
+}
+
+TEST(GeneratedPacketTest, testFixedSizeByteArray) {
+ constexpr std::size_t byte_array_size = 32;
+ std::array<uint8_t, byte_array_size> byte_array;
+ for (uint8_t i = 0; i < byte_array_size; i++) byte_array[i] = i;
+
+ constexpr int word_array_size = 8;
+ std::array<uint32_t, word_array_size> word_array;
+ for (uint32_t i = 0; i < word_array_size; i++) word_array[i] = i;
+
+ auto packet = PacketWithFixedArraysOfBytesBuilder::Create(byte_array, word_array);
+ ASSERT_EQ(2 * (256 / 8), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(byte_array_size + word_array_size * sizeof(uint32_t), packet_bytes->size());
+
+ for (size_t i = 0; i < byte_array_size; i++) {
+ ASSERT_EQ(byte_array[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = PacketWithFixedArraysOfBytesView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetFixed256bitInBytes();
+ ASSERT_EQ(byte_array.size(), array.size());
+ for (size_t i = 0; i < array.size(); i++) {
+ ASSERT_EQ(array[i], byte_array[i]);
+ }
+
+ auto decoded_word_array = view.GetFixed256bitInWords();
+ ASSERT_EQ(word_array.size(), decoded_word_array.size());
+ for (size_t i = 0; i < decoded_word_array.size(); i++) {
+ ASSERT_EQ(word_array[i], decoded_word_array[i]);
+ }
+}
+
+vector<uint8_t> one_variable{
+ 0x03, 'o', 'n', 'e', // "one"
+};
+
+TEST(GeneratedPacketTest, testOneVariableField) {
+ Variable variable_one{"one"};
+
+ auto packet = OneVariableBuilder::Create(variable_one);
+ ASSERT_EQ(one_variable.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(one_variable.size(), packet_bytes->size());
+ for (size_t i = 0; i < one_variable.size(); i++) {
+ ASSERT_EQ(one_variable[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = OneVariableView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto one = view.GetOne();
+ ASSERT_EQ(one->data, variable_one.data);
+}
+
+vector<uint8_t> fou_variable{
+ 0x04, 'f', 'o', 'u', // too short
+};
+
+TEST(GeneratedPacketTest, testOneVariableFieldTooShort) {
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>(fou_variable);
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = OneVariableView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto one = view.GetOne();
+ ASSERT_EQ(one, nullptr);
+}
+
+vector<uint8_t> sized_array_variable{
+ 0x0e, // _size_
+ 0x03, 'o', 'n', 'e', // "one"
+ 0x03, 't', 'w', 'o', // "two"
+ 0x05, 't', 'h', 'r', 'e', 'e', // "three"
+};
+
+TEST(GeneratedPacketTest, testSizedArrayVariableLength) {
+ std::vector<Variable> sized_array;
+ sized_array.emplace_back("one");
+ sized_array.emplace_back("two");
+ sized_array.emplace_back("three");
+
+ auto packet = SizedArrayVariableBuilder::Create(sized_array);
+ ASSERT_EQ(sized_array_variable.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(sized_array_variable.size(), packet_bytes->size());
+ for (size_t i = 0; i < sized_array_variable.size(); i++) {
+ ASSERT_EQ(sized_array_variable[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = SizedArrayVariableView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetVariableArray();
+ ASSERT_EQ(sized_array.size(), array.size());
+ for (size_t i = 0; i < sized_array.size(); i++) {
+ ASSERT_EQ(array[i].data, sized_array[i].data);
+ }
+}
+
+vector<uint8_t> sized_array_variable_too_short{
+ 0x0e, // _size_
+ 0x03, 'o', 'n', 'e', // "one"
+ 0x03, 't', 'w', 'o', // "two"
+ 0x06, 't', 'h', 'r', 'e', 'e', // "three" needs another letter to be length 6
+};
+
+TEST(GeneratedPacketTest, testSizedArrayVariableLengthLastBad) {
+ std::vector<Variable> sized_array;
+ sized_array.emplace_back("one");
+ sized_array.emplace_back("two");
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+ std::make_shared<std::vector<uint8_t>>(sized_array_variable_too_short);
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = SizedArrayVariableView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetVariableArray();
+ ASSERT_EQ(sized_array.size(), array.size());
+ for (size_t i = 0; i < sized_array.size(); i++) {
+ ASSERT_EQ(array[i].data, sized_array[i].data);
+ }
+}
+
+vector<uint8_t> sized_array_variable_first_too_short{
+ 0x0e, // _size_
+ 0x02, 'o', 'n', 'e', // "on"
+ 0x03, 't', 'w', 'o', // "two"
+ 0x05, 't', 'h', 'r', 'e', 'e', // "three"
+};
+
+TEST(GeneratedPacketTest, testSizedArrayVariableLengthFirstBad) {
+ std::vector<Variable> sized_array;
+ sized_array.emplace_back("on");
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+ std::make_shared<std::vector<uint8_t>>(sized_array_variable_first_too_short);
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = SizedArrayVariableView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetVariableArray();
+ ASSERT_EQ(sized_array.size(), array.size());
+ for (size_t i = 0; i < sized_array.size(); i++) {
+ ASSERT_EQ(array[i].data, sized_array[i].data);
+ }
+}
+
+vector<uint8_t> fixed_array_variable{
+ 0x03, 'o', 'n', 'e', // "one"
+ 0x03, 't', 'w', 'o', // "two"
+ 0x05, 't', 'h', 'r', 'e', 'e', // "three"
+ 0x04, 'f', 'o', 'u', 'r', // "four"
+ 0x04, 'f', 'i', 'v', 'e', // "five"
+};
+
+TEST(GeneratedPacketTest, testFixedArrayVariableLength) {
+ std::array<Variable, 5> fixed_array{std::string("one"), std::string("two"), std::string("three"), std::string("four"),
+ std::string("five")};
+
+ auto packet = FixedArrayVariableBuilder::Create(fixed_array);
+ ASSERT_EQ(fixed_array_variable.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(fixed_array_variable.size(), packet_bytes->size());
+ for (size_t i = 0; i < fixed_array_variable.size(); i++) {
+ ASSERT_EQ(fixed_array_variable[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = FixedArrayVariableView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetVariableArray();
+ ASSERT_EQ(fixed_array.size(), array.size());
+ for (size_t i = 0; i < fixed_array.size(); i++) {
+ ASSERT_EQ(array[i].data, fixed_array[i].data);
+ }
+}
+
+vector<uint8_t> fixed_array_variable_too_short{
+ 0x03, 'o', 'n', 'e', // "one"
+ 0x03, 't', 'w', 'o', // "two"
+ 0x05, 't', 'h', 'r', 'e', 'e', // "three"
+ 0x04, 'f', 'o', 'u', 'r', // "four"
+ 0x05, 'f', 'i', 'v', 'e', // "five"
+};
+
+TEST(GeneratedPacketTest, testFixedArrayVariableLengthTooShort) {
+ std::array<Variable, 5> fixed_array{std::string("one"), std::string("two"), std::string("three"),
+ std::string("four")};
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+ std::make_shared<std::vector<uint8_t>>(fixed_array_variable_too_short);
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = FixedArrayVariableView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetVariableArray();
+ ASSERT_EQ(fixed_array.size(), array.size());
+ for (size_t i = 0; i < fixed_array.size(); i++) {
+ ASSERT_EQ(array[i].data, fixed_array[i].data);
+ }
+}
+
+vector<uint8_t> count_array_variable{
+ 0x04, // _count_
+ 0x03, 'o', 'n', 'e', // "one"
+ 0x03, 't', 'w', 'o', // "two"
+ 0x05, 't', 'h', 'r', 'e', 'e', // "three"
+ 0x04, 'f', 'o', 'u', 'r', // "four"
+};
+
+TEST(GeneratedPacketTest, testCountArrayVariableLength) {
+ std::vector<Variable> count_array;
+ count_array.emplace_back("one");
+ count_array.emplace_back("two");
+ count_array.emplace_back("three");
+ count_array.emplace_back("four");
+
+ auto packet = CountArrayVariableBuilder::Create(count_array);
+ ASSERT_EQ(count_array_variable.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(count_array_variable.size(), packet_bytes->size());
+ for (size_t i = 0; i < count_array_variable.size(); i++) {
+ ASSERT_EQ(count_array_variable[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = CountArrayVariableView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetVariableArray();
+ ASSERT_EQ(count_array.size(), array.size());
+ for (size_t i = 0; i < count_array.size(); i++) {
+ ASSERT_EQ(array[i].data, count_array[i].data);
+ }
+}
+
+vector<uint8_t> count_array_variable_extra{
+ 0x04, // _count_
+ 0x03, 'o', 'n', 'e', // "one"
+ 0x03, 't', 'w', 'o', // "two"
+ 0x05, 't', 'h', 'r', 'e', 'e', // "three"
+ 0x04, 'f', 'o', 'u', 'r', // "four"
+ 0x04, 'x', 't', 'r', 'a', // "xtra"
+};
+
+TEST(GeneratedPacketTest, testCountArrayVariableLengthExtraData) {
+ std::vector<Variable> count_array;
+ count_array.emplace_back("one");
+ count_array.emplace_back("two");
+ count_array.emplace_back("three");
+ count_array.emplace_back("four");
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+ std::make_shared<std::vector<uint8_t>>(count_array_variable_extra);
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = CountArrayVariableView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetVariableArray();
+ ASSERT_EQ(count_array.size(), array.size());
+ for (size_t i = 0; i < count_array.size(); i++) {
+ ASSERT_EQ(array[i].data, count_array[i].data);
+ }
+}
+
+vector<uint8_t> count_array_variable_too_few{
+ 0x04, // _count_
+ 0x03, 'o', 'n', 'e', // "one"
+ 0x03, 't', 'w', 'o', // "two"
+ 0x05, 't', 'h', 'r', 'e', 'e', // "three"
+};
+
+TEST(GeneratedPacketTest, testCountArrayVariableLengthMissingData) {
+ std::vector<Variable> count_array;
+ count_array.emplace_back("one");
+ count_array.emplace_back("two");
+ count_array.emplace_back("three");
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+ std::make_shared<std::vector<uint8_t>>(count_array_variable_too_few);
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = CountArrayVariableView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetVariableArray();
+ ASSERT_EQ(count_array.size(), array.size());
+ for (size_t i = 0; i < count_array.size(); i++) {
+ ASSERT_EQ(array[i].data, count_array[i].data);
+ }
+}
+
+vector<uint8_t> one_struct{
+ 0x01, 0x02, 0x03, // id = 0x01, count = 0x0302
+};
+
+TEST(GeneratedPacketTest, testOneStruct) {
+ TwoRelatedNumbers trn;
+ trn.id_ = 1;
+ trn.count_ = 0x0302;
+
+ auto packet = OneStructBuilder::Create(trn);
+ ASSERT_EQ(one_struct.size(), packet->size());
+
+ // Copy the original struct, then modify it to verify independence from the packet.
+ TwoRelatedNumbers copy_trn(trn);
+ trn.id_ = 2;
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(one_struct.size(), packet_bytes->size());
+ for (size_t i = 0; i < one_struct.size(); i++) {
+ ASSERT_EQ(one_struct[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = OneStructView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto one = view.GetOne();
+ ASSERT_EQ(one.id_, copy_trn.id_);
+ ASSERT_EQ(one.count_, copy_trn.count_);
+}
+
+vector<uint8_t> two_structs{
+ 0x01, 0x01, 0x02, // id, id * 0x0201
+ 0x02, 0x02, 0x04,
+};
+
+TEST(GeneratedPacketTest, testTwoStructs) {
+ std::vector<TwoRelatedNumbers> count_array;
+ for (uint8_t i = 1; i < 3; i++) {
+ TwoRelatedNumbers trn;
+ trn.id_ = i;
+ trn.count_ = 0x0201 * i;
+ count_array.push_back(trn);
+ }
+
+ auto packet = TwoStructsBuilder::Create(count_array[0], count_array[1]);
+ ASSERT_EQ(two_structs.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(two_structs.size(), packet_bytes->size());
+ for (size_t i = 0; i < two_structs.size(); i++) {
+ ASSERT_EQ(two_structs[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = TwoStructsView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto one = view.GetOne();
+ ASSERT_EQ(one.id_, count_array[0].id_);
+ ASSERT_EQ(one.count_, count_array[0].count_);
+ auto two = view.GetTwo();
+ ASSERT_EQ(two.id_, count_array[1].id_);
+ ASSERT_EQ(two.count_, count_array[1].count_);
+}
+
+vector<uint8_t> array_or_vector_of_struct{
+ 0x04, // _count_
+ 0x01, 0x01, 0x02, // id, id * 0x0201
+ 0x02, 0x02, 0x04, 0x03, 0x03, 0x06, 0x04, 0x04, 0x08,
+};
+
+TEST(GeneratedPacketTest, testVectorOfStruct) {
+ std::vector<TwoRelatedNumbers> count_array;
+ for (uint8_t i = 1; i < 5; i++) {
+ TwoRelatedNumbers trn;
+ trn.id_ = i;
+ trn.count_ = 0x0201 * i;
+ count_array.push_back(trn);
+ }
+
+ // Make a copy
+ std::vector<TwoRelatedNumbers> copy_array(count_array);
+
+ auto packet = VectorOfStructBuilder::Create(count_array);
+
+ // Change the original vector to make sure a copy was made.
+ count_array[0].id_ = count_array[0].id_ + 1;
+
+ ASSERT_EQ(array_or_vector_of_struct.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(array_or_vector_of_struct.size(), packet_bytes->size());
+ for (size_t i = 0; i < array_or_vector_of_struct.size(); i++) {
+ ASSERT_EQ(array_or_vector_of_struct[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = VectorOfStructView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetArray();
+ ASSERT_EQ(copy_array.size(), array.size());
+ for (size_t i = 0; i < copy_array.size(); i++) {
+ ASSERT_EQ(array[i].id_, copy_array[i].id_);
+ ASSERT_EQ(array[i].count_, copy_array[i].count_);
+ }
+}
+
+TEST(GeneratedPacketTest, testArrayOfStruct) {
+ std::array<TwoRelatedNumbers, 4> count_array;
+ for (uint8_t i = 1; i < 5; i++) {
+ TwoRelatedNumbers trn;
+ trn.id_ = i;
+ trn.count_ = 0x0201 * i;
+ count_array[i - 1] = trn;
+ }
+
+ // Make a copy
+ std::array<TwoRelatedNumbers, 4> copy_array(count_array);
+
+ auto packet = ArrayOfStructBuilder::Create(4, count_array);
+
+ // Change the original vector to make sure a copy was made.
+ count_array[0].id_ = count_array[0].id_ + 1;
+
+ ASSERT_EQ(array_or_vector_of_struct.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(array_or_vector_of_struct.size(), packet_bytes->size());
+ for (size_t i = 0; i < array_or_vector_of_struct.size(); i++) {
+ ASSERT_EQ(array_or_vector_of_struct[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = ArrayOfStructView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetArray();
+ ASSERT_EQ(copy_array.size(), array.size());
+ for (size_t i = 0; i < copy_array.size(); i++) {
+ ASSERT_EQ(array[i].id_, copy_array[i].id_);
+ ASSERT_EQ(array[i].count_, copy_array[i].count_);
+ }
+}
+
+vector<uint8_t> one_fixed_types_struct{
+ 0x05, // four_bits = FIVE, reserved
+ 0xf3, // _fixed_
+ 0x0d, // id = 0x0d
+ 0x01, 0x02, 0x03, // array = { 1, 2, 3}
+ 0x06, 0x01, // example_checksum
+ 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, // six_bytes
+};
+
+TEST(GeneratedPacketTest, testOneFixedTypesStruct) {
+ StructWithFixedTypes swf;
+ swf.four_bits_ = FourBits::FIVE;
+ swf.id_ = 0x0d;
+ swf.array_ = {{0x01, 0x02, 0x03}};
+ swf.six_bytes_ = SixBytes{{0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6}};
+
+ auto packet = OneFixedTypesStructBuilder::Create(swf);
+ ASSERT_EQ(one_fixed_types_struct.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(one_fixed_types_struct.size(), packet_bytes->size());
+ for (size_t i = 0; i < one_fixed_types_struct.size(); i++) {
+ ASSERT_EQ(one_fixed_types_struct[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = OneFixedTypesStructView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto one = view.GetOne();
+ ASSERT_EQ(one.four_bits_, swf.four_bits_);
+ ASSERT_EQ(one.id_, swf.id_);
+ ASSERT_EQ(one.array_, swf.array_);
+ ASSERT_EQ(one.six_bytes_, swf.six_bytes_);
+}
+
+vector<uint8_t> array_of_struct_and_another{
+ 0x03, // _count_
+ 0x01, 0x01, 0x02, // id, id * 0x0201
+ 0x02, 0x02, 0x04, // 2
+ 0x03, 0x03, 0x06, // 3
+ 0x04, 0x04, 0x08, // Another
+};
+
+TEST(GeneratedPacketTest, testArrayOfStructAndAnother) {
+ std::vector<TwoRelatedNumbers> count_array;
+ for (uint8_t i = 1; i < 4; i++) {
+ TwoRelatedNumbers trn;
+ trn.id_ = i;
+ trn.count_ = 0x0201 * i;
+ count_array.push_back(trn);
+ }
+ TwoRelatedNumbers another;
+ another.id_ = 4;
+ another.count_ = 0x0201 * 4;
+
+ auto packet = ArrayOfStructAndAnotherBuilder::Create(count_array, another);
+ ASSERT_EQ(array_or_vector_of_struct.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(array_of_struct_and_another.size(), packet_bytes->size());
+ for (size_t i = 0; i < array_of_struct_and_another.size(); i++) {
+ ASSERT_EQ(array_of_struct_and_another[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = ArrayOfStructAndAnotherView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetArray();
+ ASSERT_EQ(count_array.size(), array.size());
+ for (size_t i = 0; i < count_array.size(); i++) {
+ ASSERT_EQ(array[i].id_, count_array[i].id_);
+ ASSERT_EQ(array[i].count_, count_array[i].count_);
+ }
+ auto nother = view.GetAnother();
+ ASSERT_EQ(nother.id_, another.id_);
+ ASSERT_EQ(nother.count_, another.count_);
+}
+
+DEFINE_AND_INSTANTIATE_OneArrayOfStructAndAnotherStructReflectionTest(array_of_struct_and_another);
+
+TEST(GeneratedPacketTest, testOneArrayOfStructAndAnotherStruct) {
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+ std::make_shared<std::vector<uint8_t>>(array_of_struct_and_another);
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = OneArrayOfStructAndAnotherStructView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto one = view.GetOne();
+ ASSERT_EQ(one.array_.size(), 3);
+ ASSERT_EQ(one.another_.id_, 4);
+ ASSERT_EQ(one.another_.count_, 0x0804);
+}
+
+vector<uint8_t> sized_array_of_struct_and_another{
+ 0x09, // _size_
+ 0x01, 0x01, 0x02, // id, id * 0x0201
+ 0x02, 0x02, 0x04, // 2
+ 0x03, 0x03, 0x06, // 3
+ 0x04, 0x04, 0x08, // Another
+};
+
+DEFINE_AND_INSTANTIATE_OneSizedArrayOfStructAndAnotherStructReflectionTest(sized_array_of_struct_and_another);
+
+vector<uint8_t> bit_field_group_packet{
+ // seven_bits_ = 0x77, straddle_ = 0x5, five_bits_ = 0x15
+ 0xf7, // 0x77 | (0x5 & 0x1) << 7
+ 0xaa, // 0x15 << 3 | (0x5 >> 1)
+};
+
+TEST(GeneratedPacketTest, testBitFieldGroupPacket) {
+ uint8_t seven_bits = 0x77;
+ uint8_t straddle = 0x5;
+ uint8_t five_bits = 0x15;
+
+ auto packet = BitFieldGroupPacketBuilder::Create(seven_bits, straddle, five_bits);
+ ASSERT_EQ(bit_field_group_packet.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(bit_field_group_packet.size(), packet_bytes->size());
+ for (size_t i = 0; i < bit_field_group_packet.size(); i++) {
+ ASSERT_EQ(bit_field_group_packet[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = BitFieldGroupPacketView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ ASSERT_EQ(seven_bits, view.GetSevenBits());
+ ASSERT_EQ(straddle, view.GetStraddle());
+ ASSERT_EQ(five_bits, view.GetFiveBits());
+}
+
+vector<uint8_t> bit_field_packet{
+ // seven_bits_ = 0x77, straddle_ = 0x5, five_bits_ = 0x15
+ 0xf7, // 0x77 | (0x5 & 0x1) << 7
+ 0xaa, // 0x15 << 3 | (0x5 >> 1)
+};
+
+TEST(GeneratedPacketTest, testBitFieldPacket) {
+ BitField bit_field;
+ bit_field.seven_bits_ = 0x77;
+ bit_field.straddle_ = 0x5;
+ bit_field.five_bits_ = 0x15;
+
+ auto packet = BitFieldPacketBuilder::Create(bit_field);
+ ASSERT_EQ(bit_field_packet.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(bit_field_packet.size(), packet_bytes->size());
+ for (size_t i = 0; i < bit_field_packet.size(); i++) {
+ ASSERT_EQ(bit_field_packet[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = BitFieldPacketView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ BitField bf = view.GetBitField();
+ ASSERT_EQ(bf.seven_bits_, bit_field.seven_bits_);
+ ASSERT_EQ(bf.straddle_, bit_field.straddle_);
+ ASSERT_EQ(bf.five_bits_, bit_field.five_bits_);
+}
+
+vector<uint8_t> bit_field_group_after_unsized_array_packet{
+ 0x01, 0x02, 0x03, 0x04, // byte array
+ // seven_bits_ = 0x77, straddle_ = 0x5, five_bits_ = 0x15
+ 0xf7, // 0x77 | (0x5 & 0x1) << 7
+ 0xaa, // 0x15 << 3 | (0x5 >> 1)
+};
+
+TEST(GeneratedPacketTest, testBitFieldGroupAfterUnsizedArrayPacket) {
+ std::vector<uint8_t> count_array;
+ for (uint8_t i = 1; i < 5; i++) {
+ count_array.push_back(i);
+ }
+ uint8_t seven_bits = 0x77;
+ uint8_t straddle = 0x5;
+ uint8_t five_bits = 0x15;
+
+ auto packet = BitFieldGroupAfterUnsizedArrayPacketBuilder::Create(count_array, seven_bits, straddle, five_bits);
+ ASSERT_EQ(bit_field_group_after_unsized_array_packet.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(bit_field_group_after_unsized_array_packet.size(), packet_bytes->size());
+ for (size_t i = 0; i < bit_field_group_after_unsized_array_packet.size(); i++) {
+ ASSERT_EQ(bit_field_group_after_unsized_array_packet[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto payload_view = BitFieldGroupAfterPayloadPacketView::Create(packet_bytes_view);
+ ASSERT_TRUE(payload_view.IsValid());
+ EXPECT_EQ(seven_bits, payload_view.GetSevenBits());
+ EXPECT_EQ(straddle, payload_view.GetStraddle());
+ EXPECT_EQ(five_bits, payload_view.GetFiveBits());
+
+ auto view = BitFieldGroupAfterUnsizedArrayPacketView::Create(payload_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetArray();
+ ASSERT_EQ(count_array.size(), array.size());
+ for (size_t i = 0; i < count_array.size(); i++) {
+ ASSERT_EQ(array[i], count_array[i]);
+ }
+ ASSERT_EQ(seven_bits, view.GetSevenBits());
+ ASSERT_EQ(straddle, view.GetStraddle());
+ ASSERT_EQ(five_bits, view.GetFiveBits());
+}
+
+vector<uint8_t> bit_field_after_unsized_array_packet{
+ 0x01, 0x02, 0x03, 0x04, // byte array
+ // seven_bits_ = 0x77, straddle_ = 0x5, five_bits_ = 0x15
+ 0xf7, // 0x77 | (0x5 & 0x1) << 7
+ 0xaa, // 0x15 << 3 | (0x5 >> 1)
+};
+
+TEST(GeneratedPacketTest, testBitFieldAfterUnsizedArrayPacket) {
+ std::vector<uint8_t> count_array;
+ for (uint8_t i = 1; i < 5; i++) {
+ count_array.push_back(i);
+ }
+ BitField bit_field;
+ bit_field.seven_bits_ = 0x77;
+ bit_field.straddle_ = 0x5;
+ bit_field.five_bits_ = 0x15;
+
+ auto packet = BitFieldAfterUnsizedArrayPacketBuilder::Create(count_array, bit_field);
+ ASSERT_EQ(bit_field_after_unsized_array_packet.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(bit_field_after_unsized_array_packet.size(), packet_bytes->size());
+ for (size_t i = 0; i < bit_field_after_unsized_array_packet.size(); i++) {
+ ASSERT_EQ(bit_field_after_unsized_array_packet[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto payload_view = BitFieldAfterPayloadPacketView::Create(packet_bytes_view);
+ ASSERT_TRUE(payload_view.IsValid());
+ BitField parent_bf = payload_view.GetBitField();
+ ASSERT_EQ(parent_bf.seven_bits_, bit_field.seven_bits_);
+ ASSERT_EQ(parent_bf.straddle_, bit_field.straddle_);
+ ASSERT_EQ(parent_bf.five_bits_, bit_field.five_bits_);
+
+ auto view = BitFieldAfterUnsizedArrayPacketView::Create(payload_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetArray();
+ ASSERT_EQ(count_array.size(), array.size());
+ for (size_t i = 0; i < count_array.size(); i++) {
+ ASSERT_EQ(array[i], count_array[i]);
+ }
+ BitField bf = view.GetBitField();
+ ASSERT_EQ(bf.seven_bits_, bit_field.seven_bits_);
+ ASSERT_EQ(bf.straddle_, bit_field.straddle_);
+ ASSERT_EQ(bf.five_bits_, bit_field.five_bits_);
+}
+
+vector<uint8_t> bit_field_array_packet{
+ 0x06, // _size_(array)
+ // seven_bits_ = 0x77, straddle_ = 0x5, five_bits_ = 0x15
+ 0xf7, // 0x77 | (0x5 & 0x1) << 7
+ 0xaa, // 0x15 << 3 | (0x5 >> 1)
+
+ // seven_bits_ = 0x78, straddle_ = 0x6, five_bits_ = 0x16
+ 0x78, // 0x78 | (0x6 & 0x1) << 7
+ 0xb3, // 0x16 << 3 | (0x6 >> 1)
+
+ // seven_bits_ = 0x79, straddle_ = 0x7, five_bits_ = 0x17
+ 0xf9, // 0x79 | (0x7 & 0x1) << 7
+ 0xbb, // 0x17 << 3 | (0x7 >> 1)
+};
+
+TEST(GeneratedPacketTest, testBitFieldArrayPacket) {
+ std::vector<BitField> count_array;
+ for (size_t i = 0; i < 3; i++) {
+ BitField bf;
+ bf.seven_bits_ = 0x77 + i;
+ bf.straddle_ = 0x5 + i;
+ bf.five_bits_ = 0x15 + i;
+ count_array.push_back(bf);
+ }
+
+ auto packet = BitFieldArrayPacketBuilder::Create(count_array);
+ ASSERT_EQ(bit_field_array_packet.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(bit_field_array_packet.size(), packet_bytes->size());
+ for (size_t i = 0; i < bit_field_array_packet.size(); i++) {
+ ASSERT_EQ(bit_field_array_packet[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = BitFieldArrayPacketView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetArray();
+ ASSERT_EQ(count_array.size(), array.size());
+ for (size_t i = 0; i < count_array.size(); i++) {
+ ASSERT_EQ(array[i].seven_bits_, count_array[i].seven_bits_);
+ ASSERT_EQ(array[i].straddle_, count_array[i].straddle_);
+ ASSERT_EQ(array[i].five_bits_, count_array[i].five_bits_);
+ }
+}
+
+TEST(GeneratedPacketTest, testNewBitFieldArrayPacket) {
+ PacketView<kLittleEndian> packet_bytes_view(std::make_shared<std::vector<uint8_t>>(bit_field_array_packet));
+ auto view = BitFieldArrayPacketView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+
+ auto packet = BitFieldArrayPacketBuilder::Create(view.GetArray());
+ ASSERT_EQ(bit_field_array_packet.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(*packet_bytes, bit_field_array_packet);
+}
+
+std::vector<uint8_t> child_two_two_two_ = {0x20, 0x02};
+std::vector<uint8_t> child_two_two_three_ = {0x20, 0x03};
+std::vector<uint8_t> child_two_two_four_ = {0x20, 0x04};
+
+DEFINE_AND_INSTANTIATE_ParentTwoReflectionTest(child_two_two_two_, child_two_two_three_, child_two_two_four_);
+
+DEFINE_AND_INSTANTIATE_ChildTwoTwoReflectionTest(child_two_two_two_, child_two_two_three_, child_two_two_four_);
+
+DEFINE_AND_INSTANTIATE_ChildTwoTwoThreeReflectionTest(child_two_two_three_);
+
+std::vector<uint8_t> one_versionless_struct_packet = {0x01};
+std::vector<uint8_t> one_versioned_struct_packet = {0x02, 0x03 /* version */, 0x04, 0x05, 0x06};
+std::vector<uint8_t> one_version_one_struct_packet = {0x03, 0x01 /* version */, 0x02};
+std::vector<uint8_t> one_version_two_struct_packet = {0x03, 0x02 /* version */, 0x03, 0x04};
+DEFINE_AND_INSTANTIATE_OneVersionlessStructPacketReflectionTest(one_versionless_struct_packet,
+ one_versioned_struct_packet,
+ one_version_one_struct_packet,
+ one_version_two_struct_packet);
+DEFINE_AND_INSTANTIATE_OneVersionedStructPacketReflectionTest(one_versioned_struct_packet,
+ one_version_one_struct_packet,
+ one_version_two_struct_packet);
+DEFINE_AND_INSTANTIATE_OneVersionOneStructPacketReflectionTest(one_version_one_struct_packet);
+DEFINE_AND_INSTANTIATE_OneVersionTwoStructPacketReflectionTest(one_version_two_struct_packet);
+
+vector<uint8_t> one_struct_be{
+ 0x01, 0x02, 0x03, // id = 0x01, count = 0x0203
+};
+
+TEST(GeneratedPacketTest, testOneStructBe) {
+ TwoRelatedNumbersBe trn;
+ trn.id_ = 1;
+ trn.count_ = 0x0203;
+
+ auto packet = OneStructBeBuilder::Create(trn);
+ ASSERT_EQ(one_struct_be.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(one_struct_be.size(), packet_bytes->size());
+ for (size_t i = 0; i < one_struct_be.size(); i++) {
+ ASSERT_EQ(one_struct_be[i], packet_bytes->at(i));
+ }
+
+ PacketView<!kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = OneStructBeView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto one = view.GetOne();
+ ASSERT_EQ(one.id_, trn.id_);
+ ASSERT_EQ(one.count_, trn.count_);
+}
+
+vector<uint8_t> two_structs_be{
+ 0x01, 0x01, 0x02, // id, id * 0x0102
+ 0x02, 0x02, 0x04,
+};
+
+TEST(GeneratedPacketTest, testTwoStructsBe) {
+ std::vector<TwoRelatedNumbersBe> count_array;
+ for (uint8_t i = 1; i < 3; i++) {
+ TwoRelatedNumbersBe trn;
+ trn.id_ = i;
+ trn.count_ = 0x0102 * i;
+ count_array.push_back(trn);
+ }
+
+ auto packet = TwoStructsBeBuilder::Create(count_array[0], count_array[1]);
+ ASSERT_EQ(two_structs_be.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(two_structs_be.size(), packet_bytes->size());
+ for (size_t i = 0; i < two_structs_be.size(); i++) {
+ ASSERT_EQ(two_structs_be[i], packet_bytes->at(i));
+ }
+
+ PacketView<!kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = TwoStructsBeView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto one = view.GetOne();
+ ASSERT_EQ(one.id_, count_array[0].id_);
+ ASSERT_EQ(one.count_, count_array[0].count_);
+ auto two = view.GetTwo();
+ ASSERT_EQ(two.id_, count_array[1].id_);
+ ASSERT_EQ(two.count_, count_array[1].count_);
+}
+
+vector<uint8_t> array_of_struct_be{
+ 0x04, // _count_
+ 0x01, 0x01, 0x02, // id, id * 0x0102
+ 0x02, 0x02, 0x04, 0x03, 0x03, 0x06, 0x04, 0x04, 0x08,
+};
+
+TEST(GeneratedPacketTest, testArrayOfStructBe) {
+ std::vector<TwoRelatedNumbersBe> count_array;
+ for (uint8_t i = 1; i < 5; i++) {
+ TwoRelatedNumbersBe trn;
+ trn.id_ = i;
+ trn.count_ = 0x0102 * i;
+ count_array.push_back(trn);
+ }
+
+ auto packet = ArrayOfStructBeBuilder::Create(count_array);
+
+ ASSERT_EQ(array_of_struct_be.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(array_of_struct_be.size(), packet_bytes->size());
+ for (size_t i = 0; i < array_of_struct_be.size(); i++) {
+ ASSERT_EQ(array_of_struct_be[i], packet_bytes->at(i));
+ }
+
+ PacketView<!kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = ArrayOfStructBeView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto array = view.GetArray();
+ ASSERT_EQ(count_array.size(), array.size());
+ for (size_t i = 0; i < count_array.size(); i++) {
+ ASSERT_EQ(array[i].id_, count_array[i].id_);
+ ASSERT_EQ(array[i].count_, count_array[i].count_);
+ }
+}
+
+vector<uint8_t> one_four_byte_struct{
+ 0x04, // struct_type_ = FourByte
+ 0xd1, 0xd2, 0xd3, 0xd4, // four_bytes_
+};
+
+TEST(GeneratedPacketTest, testOneFourByteStruct) {
+ FourByteStruct four_byte_struct;
+ four_byte_struct.four_bytes_ = 0xd4d3d2d1;
+
+ auto packet = OneFourByteStructBuilder::Create(four_byte_struct);
+ ASSERT_EQ(one_four_byte_struct.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(one_four_byte_struct.size(), packet_bytes->size());
+ for (size_t i = 0; i < one_four_byte_struct.size(); i++) {
+ ASSERT_EQ(one_four_byte_struct[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = OneFourByteStructView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ ASSERT_EQ(StructType::FOUR_BYTE, view.GetOneStruct().struct_type_);
+ ASSERT_EQ(four_byte_struct.four_bytes_, view.GetOneStruct().four_bytes_);
+}
+
+vector<uint8_t> generic_struct_two{
+ 0x02, // struct_type_ = TwoByte
+ 0x01, 0x02, // two_bytes_
+};
+
+TEST(GeneratedPacketTest, testOneGenericStructTwo) {
+ TwoByteStruct two_byte_struct;
+ two_byte_struct.two_bytes_ = 0x0201;
+ std::unique_ptr<TwoByteStruct> two_byte_struct_ptr = std::make_unique<TwoByteStruct>(two_byte_struct);
+
+ auto packet = OneGenericStructBuilder::Create(std::move(two_byte_struct_ptr));
+ ASSERT_EQ(generic_struct_two.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(generic_struct_two.size(), packet_bytes->size());
+ for (size_t i = 0; i < generic_struct_two.size(); i++) {
+ ASSERT_EQ(generic_struct_two[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = OneGenericStructView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto base_struct = view.GetBaseStruct();
+ ASSERT_NE(nullptr, base_struct);
+ ASSERT_TRUE(TwoByteStruct::IsInstance(*base_struct));
+ TwoByteStruct* two_byte = static_cast<TwoByteStruct*>(base_struct.get());
+ ASSERT_NE(nullptr, two_byte);
+ ASSERT_TRUE(TwoByteStruct::IsInstance(*two_byte));
+ ASSERT_EQ(two_byte_struct.two_bytes_, 0x0201);
+ uint16_t val = two_byte->two_bytes_;
+ ASSERT_EQ(val, 0x0201);
+ ASSERT_EQ(two_byte_struct.two_bytes_, ((TwoByteStruct*)base_struct.get())->two_bytes_);
+}
+
+vector<uint8_t> generic_struct_four{
+ 0x04, // struct_type_ = FourByte
+ 0x01, 0x02, 0x03, 0x04, // four_bytes_
+};
+
+TEST(GeneratedPacketTest, testOneGenericStructFour) {
+ FourByteStruct four_byte_struct;
+ four_byte_struct.four_bytes_ = 0x04030201;
+ std::unique_ptr<FourByteStruct> four_byte_struct_p = std::make_unique<FourByteStruct>(four_byte_struct);
+ ASSERT_EQ(four_byte_struct.four_bytes_, four_byte_struct_p->four_bytes_);
+
+ auto packet = OneGenericStructBuilder::Create(std::move(four_byte_struct_p));
+ ASSERT_EQ(generic_struct_four.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(generic_struct_four.size(), packet_bytes->size());
+ for (size_t i = 0; i < generic_struct_four.size(); i++) {
+ ASSERT_EQ(generic_struct_four[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = OneGenericStructView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto base_struct = view.GetBaseStruct();
+ ASSERT_NE(nullptr, base_struct);
+ ASSERT_EQ(StructType::FOUR_BYTE, base_struct->struct_type_);
+ ASSERT_EQ(four_byte_struct.four_bytes_, ((FourByteStruct*)base_struct.get())->four_bytes_);
+}
+
+vector<uint8_t> one_struct_array{
+ 0x04, // struct_type_ = FourByte
+ 0xa1, 0xa2, 0xa3, 0xa4, // four_bytes_
+ 0x04, // struct_type_ = FourByte
+ 0xb2, 0xb2, 0xb3, 0xb4, // four_bytes_
+ 0x02, // struct_type_ = TwoByte
+ 0xc3, 0xc2, // two_bytes_
+ 0x04, // struct_type_ = TwoByte
+ 0xd4, 0xd2, 0xd3, 0xd4, // four_bytes_
+};
+
+TEST(GeneratedPacketTest, testOneGenericStructArray) {
+ std::vector<std::unique_ptr<UnusedParentStruct>> parent_vector;
+ std::unique_ptr<FourByteStruct> fbs;
+ std::unique_ptr<TwoByteStruct> tbs;
+ fbs = std::make_unique<FourByteStruct>();
+ fbs->four_bytes_ = 0xa4a3a2a1;
+ parent_vector.push_back(std::move(fbs));
+ fbs = std::make_unique<FourByteStruct>();
+ fbs->four_bytes_ = 0xb4b3b2b2;
+ parent_vector.push_back(std::move(fbs));
+ tbs = std::make_unique<TwoByteStruct>();
+ tbs->two_bytes_ = 0xc2c3;
+ parent_vector.push_back(std::move(tbs));
+ fbs = std::make_unique<FourByteStruct>();
+ fbs->four_bytes_ = 0xd4d3d2d4;
+ parent_vector.push_back(std::move(fbs));
+
+ std::vector<std::unique_ptr<UnusedParentStruct>> vector_copy;
+ for (auto& s : parent_vector) {
+ if (s->struct_type_ == StructType::TWO_BYTE) {
+ vector_copy.push_back(std::make_unique<TwoByteStruct>(*(TwoByteStruct*)s.get()));
+ }
+ if (s->struct_type_ == StructType::FOUR_BYTE) {
+ vector_copy.push_back(std::make_unique<FourByteStruct>(*(FourByteStruct*)s.get()));
+ }
+ }
+
+ auto packet = OneGenericStructArrayBuilder::Create(std::move(parent_vector));
+ ASSERT_EQ(one_struct_array.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(one_struct_array.size(), packet_bytes->size());
+ for (size_t i = 0; i < one_struct_array.size(); i++) {
+ ASSERT_EQ(one_struct_array[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = OneGenericStructArrayView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto an_array = view.GetAnArray();
+ ASSERT_EQ(vector_copy.size(), an_array.size());
+ for (size_t i = 0; i < vector_copy.size(); i++) {
+ ASSERT_NE(nullptr, an_array[i]);
+ ASSERT_EQ(vector_copy[i]->struct_type_, an_array[i]->struct_type_);
+ if (vector_copy[i]->struct_type_ == StructType::FOUR_BYTE) {
+ ASSERT_EQ(FourByteStruct::Specialize(vector_copy[i].get())->four_bytes_,
+ FourByteStruct::Specialize(an_array[i].get())->four_bytes_);
+ } else {
+ ASSERT_EQ(TwoByteStruct::Specialize(vector_copy[i].get())->two_bytes_,
+ TwoByteStruct::Specialize(an_array[i].get())->two_bytes_);
+ }
+ }
+}
+
+TEST(GeneratedPacketTest, testOneGenericStructFourArray) {
+ std::array<std::unique_ptr<UnusedParentStruct>, 4> parent_vector;
+ std::unique_ptr<FourByteStruct> fbs;
+ std::unique_ptr<TwoByteStruct> tbs;
+ fbs = std::make_unique<FourByteStruct>();
+ fbs->four_bytes_ = 0xa4a3a2a1;
+ parent_vector[0] = std::move(fbs);
+ fbs = std::make_unique<FourByteStruct>();
+ fbs->four_bytes_ = 0xb4b3b2b2;
+ parent_vector[1] = std::move(fbs);
+ tbs = std::make_unique<TwoByteStruct>();
+ tbs->two_bytes_ = 0xc2c3;
+ parent_vector[2] = std::move(tbs);
+ fbs = std::make_unique<FourByteStruct>();
+ fbs->four_bytes_ = 0xd4d3d2d4;
+ parent_vector[3] = std::move(fbs);
+
+ std::array<std::unique_ptr<UnusedParentStruct>, 4> vector_copy;
+ size_t i = 0;
+ for (auto& s : parent_vector) {
+ if (s->struct_type_ == StructType::TWO_BYTE) {
+ vector_copy[i] = std::make_unique<TwoByteStruct>(*(TwoByteStruct*)s.get());
+ }
+ if (s->struct_type_ == StructType::FOUR_BYTE) {
+ vector_copy[i] = std::make_unique<FourByteStruct>(*(FourByteStruct*)s.get());
+ }
+ i++;
+ }
+
+ auto packet = OneGenericStructFourArrayBuilder::Create(std::move(parent_vector));
+ ASSERT_EQ(one_struct_array.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(one_struct_array.size(), packet_bytes->size());
+ for (size_t i = 0; i < one_struct_array.size(); i++) {
+ ASSERT_EQ(one_struct_array[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = OneGenericStructFourArrayView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto an_array = view.GetAnArray();
+ ASSERT_EQ(vector_copy.size(), an_array.size());
+ for (size_t i = 0; i < vector_copy.size(); i++) {
+ ASSERT_NE(nullptr, an_array[i]);
+ ASSERT_EQ(vector_copy[i]->struct_type_, an_array[i]->struct_type_);
+ if (vector_copy[i]->struct_type_ == StructType::FOUR_BYTE) {
+ ASSERT_EQ(FourByteStruct::Specialize(vector_copy[i].get())->four_bytes_,
+ FourByteStruct::Specialize(an_array[i].get())->four_bytes_);
+ } else {
+ ASSERT_EQ(TwoByteStruct::Specialize(vector_copy[i].get())->two_bytes_,
+ TwoByteStruct::Specialize(an_array[i].get())->two_bytes_);
+ }
+ }
+}
+
+vector<uint8_t> one_struct_array_after_fixed{
+ 0x01, 0x02, // two_bytes = 0x0201
+ 0x04, // struct_type_ = FourByte
+ 0xa1, 0xa2, 0xa3, 0xa4, // four_bytes_
+ 0x04, // struct_type_ = FourByte
+ 0xb2, 0xb2, 0xb3, 0xb4, // four_bytes_
+ 0x02, // struct_type_ = TwoByte
+ 0xc3, 0xc2, // two_bytes_
+ 0x04, // struct_type_ = TwoByte
+ 0xd4, 0xd2, 0xd3, 0xd4, // four_bytes_
+};
+
+DEFINE_AND_INSTANTIATE_OneGenericStructArrayAfterFixedReflectionTest(one_struct_array_after_fixed);
+
+vector<uint8_t> one_length_type_value_struct{
+ // _size_(value):16 type value
+ 0x04, 0x00, 0x01, 'o', 'n', 'e', // ONE
+ 0x04, 0x00, 0x02, 't', 'w', 'o', // TWO
+ 0x06, 0x00, 0x03, 't', 'h', 'r', 'e', 'e', // THREE
+};
+
+DEFINE_AND_INSTANTIATE_OneLengthTypeValueStructReflectionTest(one_length_type_value_struct);
+
+TEST(GeneratedPacketTest, testOneLengthTypeValueStruct) {
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes =
+ std::make_shared<std::vector<uint8_t>>(one_length_type_value_struct);
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = OneLengthTypeValueStructView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ auto one = view.GetOneArray();
+ size_t entry_id = 0;
+ for (const auto& entry : one) {
+ switch (entry_id++) {
+ case 0:
+ ASSERT_EQ(entry.type_, DataType::ONE);
+ ASSERT_EQ(entry.value_, std::vector<uint8_t>({'o', 'n', 'e'}));
+ break;
+ case 1:
+ ASSERT_EQ(entry.type_, DataType::TWO);
+ ASSERT_EQ(entry.value_, std::vector<uint8_t>({'t', 'w', 'o'}));
+ break;
+ case 2:
+ ASSERT_EQ(entry.type_, DataType::THREE);
+ ASSERT_EQ(entry.value_, std::vector<uint8_t>({'t', 'h', 'r', 'e', 'e'}));
+ break;
+ default:
+ ASSERT_EQ(entry.type_, DataType::UNUSED);
+ }
+ }
+}
+
+vector<uint8_t> one_length_type_value_struct_padded_20{
+ 0x27, // _size_(payload),
+ // _size_(value):16 type value
+ 0x04, 0x00, 0x01, 'o', 'n', 'e', // ONE
+ 0x04, 0x00, 0x02, 't', 'w', 'o', // TWO
+ 0x06, 0x00, 0x03, 't', 'h', 'r', 'e', 'e', // THREE
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding to 30
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding to 40
+};
+
+vector<uint8_t> one_length_type_value_struct_padded_28{
+ 0x27, // _size_(payload),
+ // _size_(value):16 type value
+ 0x04, 0x00, 0x01, 'o', 'n', 'e', // ONE
+ 0x04, 0x00, 0x02, 't', 'w', 'o', // TWO
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding to 20
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding to 30
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // padding to 40
+};
+
+// TODO: Revisit LTV parsing. Right now, the padding bytes are parsed
+// DEFINE_AND_INSTANTIATE_OneLengthTypeValueStructPaddedReflectionTest(one_length_type_value_struct_padded_20,
+// one_length_type_value_struct_padded_28);
+
+TEST(GeneratedPacketTest, testOneLengthTypeValueStructPaddedGeneration) {
+ std::vector<LengthTypeValueStruct> ltv_vector;
+ LengthTypeValueStruct ltv;
+ ltv.type_ = DataType::ONE;
+ ltv.value_ = {
+ 'o',
+ 'n',
+ 'e',
+ };
+ ltv_vector.push_back(ltv);
+ ltv.type_ = DataType::TWO;
+ ltv.value_ = {
+ 't',
+ 'w',
+ 'o',
+ };
+ ltv_vector.push_back(ltv);
+
+ auto packet = OneLengthTypeValueStructPaddedBuilder::Create(ltv_vector);
+ ASSERT_EQ(one_length_type_value_struct_padded_28.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(one_length_type_value_struct_padded_28.size(), packet_bytes->size());
+ for (size_t i = 0; i < one_length_type_value_struct_padded_28.size(); i++) {
+ ASSERT_EQ(one_length_type_value_struct_padded_28[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = OneLengthTypeValueStructPaddedView::Create(SizedParentView::Create(packet_bytes_view));
+ ASSERT_TRUE(view.IsValid());
+ auto an_array = view.GetOneArray();
+ // TODO: Revisit LTV parsing. Right now, the padding bytes are parsed
+ // ASSERT_EQ(ltv_vector.size(), an_array.size());
+ for (size_t i = 0; i < ltv_vector.size(); i++) {
+ ASSERT_EQ(ltv_vector[i].type_, an_array[i].type_);
+ ASSERT_EQ(ltv_vector[i].value_, an_array[i].value_);
+ }
+}
+
+vector<uint8_t> byte_sized{
+ 0x11, // 1
+ 0x21, 0x22, // 2
+ 0x31, 0x32, 0x33, // 3
+ 0x41, 0x42, 0x43, 0x44, // 4
+ 0x51, 0x52, 0x53, 0x54, 0x55, // 5
+ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, // 6
+ 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, // 7
+ 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, // 8
+};
+
+TEST(GeneratedPacketTest, testByteSizedFields) {
+ uint64_t array[9]{
+ 0xbadbadbad,
+ 0x11, // 1
+ 0x2221, // 2
+ 0x333231, // 3
+ 0x44434241, // 4
+ 0x5554535251, // 5
+ 0x666564636261, // 6
+ 0x77767574737271, // 7
+ 0x8887868584838281, // 8
+ };
+ auto packet =
+ ByteSizedFieldsBuilder::Create(array[1], array[2], array[3], array[4], array[5], array[6], array[7], array[8]);
+ ASSERT_EQ(byte_sized.size(), packet->size());
+
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ packet->Serialize(it);
+
+ ASSERT_EQ(byte_sized.size(), packet_bytes->size());
+ for (size_t i = 0; i < byte_sized.size(); i++) {
+ ASSERT_EQ(byte_sized[i], packet_bytes->at(i));
+ }
+
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto view = ByteSizedFieldsView::Create(packet_bytes_view);
+ ASSERT_TRUE(view.IsValid());
+ ASSERT_EQ(array[1], view.GetOne());
+ ASSERT_EQ(array[2], view.GetTwo());
+ ASSERT_EQ(array[3], view.GetThree());
+ ASSERT_EQ(array[4], view.GetFour());
+ ASSERT_EQ(array[5], view.GetFive());
+ ASSERT_EQ(array[6], view.GetSix());
+ ASSERT_EQ(array[7], view.GetSeven());
+ ASSERT_EQ(array[8], view.GetEight());
+}
+
+DEFINE_AND_INSTANTIATE_ByteSizedFieldsReflectionTest(byte_sized);
+
+} // namespace parser
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/parser/test/simple_sum.h b/gd/packet/parser/test/simple_sum.h
new file mode 100644
index 0000000..95c4888
--- /dev/null
+++ b/gd/packet/parser/test/simple_sum.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+namespace bluetooth {
+namespace packet {
+namespace parser {
+namespace test {
+
+class SimpleSum {
+ public:
+ void Initialize() {
+ sum = 0;
+ }
+
+ void AddByte(uint8_t byte) {
+ sum += byte;
+ }
+
+ uint16_t GetChecksum() const {
+ return sum;
+ }
+
+ private:
+ uint16_t sum;
+};
+
+} // namespace test
+} // namespace parser
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/parser/test/six_bytes.cc b/gd/packet/parser/test/six_bytes.cc
new file mode 100644
index 0000000..614dbaa
--- /dev/null
+++ b/gd/packet/parser/test/six_bytes.cc
@@ -0,0 +1,35 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "six_bytes.h"
+
+namespace bluetooth {
+namespace packet {
+namespace parser {
+namespace test {
+
+static_assert(sizeof(SixBytes) == 6, "SixBytes must be 6 bytes long!");
+
+SixBytes::SixBytes(const uint8_t (&six)[6]) {
+ std::copy(six, six + kLength, six_bytes);
+};
+
+} // namespace test
+} // namespace parser
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/parser/test/six_bytes.h b/gd/packet/parser/test/six_bytes.h
new file mode 100644
index 0000000..0f26324
--- /dev/null
+++ b/gd/packet/parser/test/six_bytes.h
@@ -0,0 +1,61 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdint.h>
+#include <string>
+
+namespace bluetooth {
+namespace packet {
+namespace parser {
+namespace test {
+
+class SixBytes final {
+ public:
+ static constexpr unsigned int kLength = 6;
+
+ uint8_t six_bytes[kLength];
+
+ SixBytes() = default;
+ SixBytes(const uint8_t (&addr)[6]);
+
+ bool operator<(const SixBytes& rhs) const {
+ return (std::memcmp(six_bytes, rhs.six_bytes, sizeof(six_bytes)) < 0);
+ }
+ bool operator==(const SixBytes& rhs) const {
+ return (std::memcmp(six_bytes, rhs.six_bytes, sizeof(six_bytes)) == 0);
+ }
+ bool operator>(const SixBytes& rhs) const {
+ return (rhs < *this);
+ }
+ bool operator<=(const SixBytes& rhs) const {
+ return !(*this > rhs);
+ }
+ bool operator>=(const SixBytes& rhs) const {
+ return !(*this < rhs);
+ }
+ bool operator!=(const SixBytes& rhs) const {
+ return !(*this == rhs);
+ }
+};
+
+} // namespace test
+} // namespace parser
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/parser/test/test_packets.pdl b/gd/packet/parser/test/test_packets.pdl
new file mode 100644
index 0000000..2b612cc
--- /dev/null
+++ b/gd/packet/parser/test/test_packets.pdl
@@ -0,0 +1,407 @@
+little_endian_packets
+
+custom_field SixBytes : 48 "packet/parser/test/"
+custom_field Variable "packet/parser/test/"
+
+packet Parent {
+ _fixed_ = 0x12 : 8,
+ _size_(_payload_) : 8,
+ _payload_,
+ footer : 8,
+}
+
+packet Child : Parent {
+ field_name : 16,
+}
+
+enum FourBits : 4 {
+ ONE = 1,
+ TWO = 2,
+ THREE = 3,
+ FIVE = 5,
+ TEN = 10,
+ LAZY_ME = 15,
+}
+
+packet ParentTwo {
+ _reserved_ : 4,
+ four_bits : FourBits,
+ _payload_,
+}
+
+packet ChildTwoThree : ParentTwo (four_bits = THREE) {
+ more_bits : FourBits,
+ _reserved_ : 4,
+ sixteen_bits : 16
+}
+
+packet ChildTwoTwo : ParentTwo (four_bits = TWO) {
+ more_bits : FourBits,
+ _reserved_ : 4,
+}
+
+packet ChildTwoTwoThree :ChildTwoTwo (more_bits = THREE) {
+}
+
+enum TwoBits : 2 {
+ ZERO = 0,
+ ONE = 1,
+ TWO = 2,
+ THREE = 3,
+}
+
+packet MiddleFourBits {
+ low_two : TwoBits,
+ next_four : FourBits,
+ straddle : FourBits,
+ four_more : FourBits,
+ high_two : TwoBits,
+}
+
+packet ParentWithSixBytes {
+ two_bytes : 16,
+ six_bytes : SixBytes,
+ _payload_,
+}
+
+packet ChildWithSixBytes : ParentWithSixBytes (two_bytes = 0x1234) {
+ child_six_bytes : SixBytes,
+}
+
+checksum SimpleSum : 16 "packet/parser/test/"
+
+packet ParentWithSum {
+ two_bytes : 16,
+ _checksum_start_(example_checksum),
+ sum_bytes : 16,
+ _payload_,
+ example_checksum : SimpleSum,
+}
+
+packet ChildWithSum : ParentWithSum {
+ more_bytes : 32,
+ another_byte : 8,
+}
+
+packet ChildWithNestedSum : ParentWithSum {
+ _checksum_start_(nested_checksum),
+ more_bytes : 32,
+ nested_checksum : SimpleSum,
+}
+
+packet ParentSizeModifier {
+ _size_(_payload_) : 8,
+ _payload_ : [+2*8], // Include two_bytes in the size
+ two_bytes : 16,
+}
+
+packet ChildSizeModifier : ParentSizeModifier (two_bytes = 0x1211) {
+ more_bytes : 32,
+}
+
+packet FieldsEndWithNumbers {
+ field_1 : 16,
+ field_2 : 16,
+ field_10 : 16,
+ field_11 : 16,
+}
+
+enum ForArrays : 16 {
+ ONE = 0x0001,
+ TWO = 0x0002,
+ ONE_TWO = 0x0201,
+ TWO_THREE = 0x0302,
+ FFFF = 0xffff,
+}
+
+packet FixedArrayEnum {
+ enum_array : ForArrays[5],
+}
+
+packet SizedArrayEnum {
+ _size_(enum_array) : 16,
+ enum_array : ForArrays[],
+}
+
+packet CountArrayEnum {
+ _count_(enum_array) : 8,
+ enum_array : ForArrays[],
+}
+
+packet SizedArrayCustom {
+ _size_(six_bytes_array) : 8,
+ an_extra_byte : 8,
+ six_bytes_array : SixBytes[+1*8],
+}
+
+packet FixedArrayCustom {
+ six_bytes_array : SixBytes[5],
+}
+
+packet CountArrayCustom {
+ _count_(six_bytes_array) : 8,
+ six_bytes_array : SixBytes[],
+}
+
+packet PacketWithFixedArraysOfBytes {
+ fixed_256bit_in_bytes : 8[32],
+ fixed_256bit_in_words : 32[8],
+}
+
+packet OneVariable {
+ one : Variable,
+}
+
+packet SizedArrayVariable {
+ _size_(variable_array) : 8,
+ variable_array : Variable[],
+}
+
+packet FixedArrayVariable {
+ variable_array : Variable[5],
+}
+
+packet CountArrayVariable {
+ _count_(variable_array) : 8,
+ variable_array : Variable[],
+}
+
+struct TwoRelatedNumbers {
+ id : 8,
+ count : 16,
+}
+
+packet OneStruct {
+ one : TwoRelatedNumbers,
+}
+
+packet TwoStructs {
+ one : TwoRelatedNumbers,
+ two : TwoRelatedNumbers,
+}
+
+packet VectorOfStruct {
+ _count_(array) : 8,
+ array : TwoRelatedNumbers[],
+}
+
+packet ArrayOfStruct {
+ the_count : 8,
+ array : TwoRelatedNumbers[4],
+}
+
+struct StructWithFixedTypes {
+ four_bits : FourBits,
+ _reserved_ : 4,
+ _checksum_start_(example_checksum),
+ _fixed_ = 0xf3 : 8,
+ id : 8,
+ array : 8[3],
+ example_checksum : SimpleSum,
+ six_bytes : SixBytes,
+}
+
+packet OneFixedTypesStruct {
+ one : StructWithFixedTypes,
+}
+
+packet ArrayOfStructAndAnother {
+ _count_(array) : 8,
+ array : TwoRelatedNumbers[],
+ another : TwoRelatedNumbers,
+}
+
+packet SizedArrayOfStructAndAnother {
+ _size_(array) : 8,
+ array : TwoRelatedNumbers[],
+ another : TwoRelatedNumbers,
+}
+
+struct ArrayOfStructAndAnotherStruct {
+ _count_(array) : 8,
+ array : TwoRelatedNumbers[],
+ another : TwoRelatedNumbers,
+}
+
+struct SizedArrayOfStructAndAnotherStruct {
+ _size_(array) : 8,
+ array : TwoRelatedNumbers[],
+ another : TwoRelatedNumbers,
+}
+
+packet OneArrayOfStructAndAnotherStruct {
+ one : ArrayOfStructAndAnotherStruct,
+}
+
+packet OneSizedArrayOfStructAndAnotherStruct {
+ one : SizedArrayOfStructAndAnotherStruct,
+}
+
+group BitFieldGroup {
+ seven_bits : 7,
+ straddle : 4,
+ five_bits : 5,
+}
+
+packet BitFieldGroupPacket {
+ BitFieldGroup,
+}
+
+packet BitFieldGroupAfterPayloadPacket {
+ _payload_,
+ BitFieldGroup,
+}
+
+packet BitFieldGroupAfterUnsizedArrayPacket : BitFieldGroupAfterPayloadPacket {
+ array : 8[],
+}
+
+struct BitField {
+ seven_bits : 7,
+ straddle : 4,
+ five_bits : 5,
+}
+
+packet BitFieldPacket {
+ bit_field : BitField,
+}
+
+packet BitFieldAfterPayloadPacket {
+ _payload_,
+ bit_field : BitField,
+}
+
+packet BitFieldAfterUnsizedArrayPacket : BitFieldAfterPayloadPacket {
+ array : 8[],
+}
+
+packet BitFieldArrayPacket {
+ _size_(array): 8,
+ array : BitField[],
+}
+
+struct VersionlessStruct {
+ one_number : 8,
+}
+
+packet OneVersionlessStructPacket {
+ versionless : VersionlessStruct,
+ _payload_,
+}
+
+packet OneVersionedStructPacket : OneVersionlessStructPacket {
+ version : 8,
+ _payload_,
+}
+
+packet OneVersionOneStructPacket : OneVersionedStructPacket(version = 0x01) {
+ just_one_number : 8,
+}
+
+packet OneVersionTwoStructPacket : OneVersionedStructPacket(version = 0x02) {
+ one_number : 8,
+ another_number : 8,
+}
+
+enum StructType : 8 {
+ ZERO_BYTE = 0x00,
+ TWO_BYTE = 0x02,
+ FOUR_BYTE = 0x04,
+ AT_LEAST_FOUR_BYTE = 0x05,
+ VARIABLE = 0x06,
+}
+
+struct UnusedParentStruct {
+ struct_type : StructType,
+ _body_,
+}
+
+struct TwoByteStruct : UnusedParentStruct (struct_type = TWO_BYTE) {
+ two_bytes : 16,
+}
+
+struct FourByteStruct : UnusedParentStruct (struct_type = FOUR_BYTE) {
+ four_bytes : 32,
+}
+
+struct AtLeastFourByteStruct : UnusedParentStruct (struct_type = AT_LEAST_FOUR_BYTE) {
+ four_bytes : 32,
+ struct_type : StructType,
+ _body_,
+}
+
+struct OnlyFourByteStruct : AtLeastFourByteStruct (struct_type = ZERO_BYTE) {
+}
+
+struct SixByteStruct : AtLeastFourByteStruct (struct_type = TWO_BYTE) {
+ two_bytes : 16,
+}
+
+struct EightByteStruct : AtLeastFourByteStruct (struct_type = FOUR_BYTE) {
+ four_bytes : 32,
+}
+
+packet OneFourByteStruct {
+ one_struct : FourByteStruct,
+}
+
+packet OneGenericStruct {
+ base_struct : UnusedParentStruct,
+}
+
+packet OneGenericStructArray {
+ an_array : UnusedParentStruct[],
+}
+
+packet OneGenericStructFourArray {
+ an_array : UnusedParentStruct[4],
+}
+
+packet ParentWithOnlyFixed {
+ two_bytes : 16,
+ _body_,
+}
+
+packet OneGenericStructArrayAfterFixed : ParentWithOnlyFixed {
+ an_array : UnusedParentStruct[],
+}
+
+enum DataType : 8 {
+ ONE = 0x01,
+ TWO = 0x02,
+ THREE = 0x03,
+ FOUR = 0x04,
+ FIVE = 0x05,
+ UNUSED = 0x06,
+}
+
+struct LengthTypeValueStruct {
+ _size_(value) : 16,
+ type : DataType,
+ value : 8[+1*8],
+}
+
+packet OneLengthTypeValueStruct {
+ one_array : LengthTypeValueStruct[],
+}
+
+packet SizedParent {
+ _size_(payload) : 8,
+ _payload_,
+}
+
+packet OneLengthTypeValueStructPadded : SizedParent {
+ one_array : LengthTypeValueStruct[],
+ _padding_[40],
+}
+
+packet ByteSizedFields {
+ one : 8,
+ two : 16,
+ three : 24,
+ four : 32,
+ five : 40,
+ six : 48,
+ seven : 56,
+ eight : 64,
+}
diff --git a/gd/packet/parser/test/variable.cc b/gd/packet/parser/test/variable.cc
new file mode 100644
index 0000000..23443bf
--- /dev/null
+++ b/gd/packet/parser/test/variable.cc
@@ -0,0 +1,48 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "variable.h"
+
+#include <stdio.h>
+#include <sstream>
+
+namespace bluetooth {
+namespace packet {
+namespace parser {
+namespace test {
+
+Variable::Variable(const std::string& str) : data(str) {}
+
+void Variable::Serialize(BitInserter& bi) const {
+ if (data.size() > 255) {
+ fprintf(stderr, "data.size() > 255: (%zu)", data.size());
+ abort();
+ }
+ bi.insert_byte((uint8_t)data.size());
+ for (auto byte : data) {
+ bi.insert_byte(byte);
+ }
+}
+
+size_t Variable::size() const {
+ return data.size() + 1;
+}
+} // namespace test
+} // namespace parser
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/parser/test/variable.h b/gd/packet/parser/test/variable.h
new file mode 100644
index 0000000..c452a37
--- /dev/null
+++ b/gd/packet/parser/test/variable.h
@@ -0,0 +1,70 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <stdint.h>
+#include <optional>
+#include <sstream>
+#include <string>
+
+#include "packet/bit_inserter.h"
+#include "packet/iterator.h"
+
+namespace bluetooth {
+namespace packet {
+namespace parser {
+namespace test {
+
+class Variable final {
+ public:
+ std::string data;
+
+ Variable() = default;
+ Variable(const Variable&) = default;
+ Variable(const std::string& str);
+
+ void Serialize(BitInserter& bi) const;
+
+ size_t size() const;
+
+ template <bool little_endian>
+ static std::optional<Iterator<little_endian>> Parse(Variable* instance, Iterator<little_endian> it) {
+ if (it.NumBytesRemaining() < 1) {
+ return {};
+ }
+ size_t data_length = it.template extract<uint8_t>();
+ if (data_length > 255) {
+ return {};
+ }
+ if (it.NumBytesRemaining() < data_length) {
+ return {};
+ }
+ std::stringstream ss;
+ for (size_t i = 0; i < data_length; i++) {
+ ss << it.template extract<char>();
+ }
+ *instance = ss.str();
+ return it;
+ }
+};
+
+} // namespace test
+} // namespace parser
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/parser/type_def.h b/gd/packet/parser/type_def.h
new file mode 100644
index 0000000..811dca8
--- /dev/null
+++ b/gd/packet/parser/type_def.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <iostream>
+
+#include "fields/packet_field.h"
+
+class TypeDef {
+ public:
+ TypeDef(std::string name) : name_(name) {}
+
+ TypeDef(std::string name, int size) : name_(name), size_(size) {}
+
+ virtual ~TypeDef() = default;
+
+ std::string GetTypeName() const {
+ return name_;
+ }
+
+ enum class Type {
+ INVALID,
+ ENUM,
+ CHECKSUM,
+ CUSTOM,
+ PACKET,
+ STRUCT,
+ };
+
+ virtual Type GetDefinitionType() const = 0;
+
+ virtual PacketField* GetNewField(const std::string& name, ParseLocation loc) const = 0;
+
+ const std::string name_;
+ const int size_{-1};
+};
diff --git a/gd/packet/parser/util.h b/gd/packet/parser/util.h
new file mode 100644
index 0000000..a8b881d
--- /dev/null
+++ b/gd/packet/parser/util.h
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <iostream>
+#include <regex>
+#include <string>
+
+#include "logging.h"
+
+namespace util {
+
+inline std::string GetTypeForSize(int size) {
+ if (size > 64) {
+ ERROR() << __func__ << ": Cannot use a type larger than 64 bits. (" << size << ")\n";
+ }
+
+ if (size <= 8) return "uint8_t";
+
+ if (size <= 16) return "uint16_t";
+
+ if (size <= 32) return "uint32_t";
+
+ return "uint64_t";
+}
+
+inline int RoundSizeUp(int size) {
+ if (size > 64) {
+ ERROR() << __func__ << ": Cannot use a type larger than 64 bits. (" << size << ")\n";
+ }
+
+ if (size <= 8) return 8;
+ if (size <= 16) return 16;
+ if (size <= 32) return 32;
+ return 64;
+}
+
+// Returns the max value that can be contained unsigned in a number of bits.
+inline uint64_t GetMaxValueForBits(int bits) {
+ if (bits > 64) {
+ ERROR() << __func__ << ": Cannot use a type larger than 64 bits. (" << bits << ")\n";
+ }
+
+ // Set all the bits to 1, then shift off extras.
+ return ~(static_cast<uint64_t>(0)) >> (64 - bits);
+}
+
+inline std::string CamelCaseToUnderScore(std::string value) {
+ if (value[0] < 'A' || value[0] > 'Z') {
+ ERROR() << value << " doesn't look like CamelCase";
+ }
+
+ // Use static to avoid compiling the regex more than once.
+ static const std::regex camel_case_regex("[A-Z][a-z0-9]*");
+
+ // Add an underscore to the end of each pattern match.
+ value = std::regex_replace(value, camel_case_regex, "$&_");
+
+ // Remove the last underscore at the end of the string.
+ value.pop_back();
+
+ // Convert all characters to lowercase.
+ std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) { return std::tolower(c); });
+
+ return value;
+}
+
+inline std::string UnderscoreToCamelCase(std::string value) {
+ if (value[0] < 'a' || value[0] > 'z') {
+ ERROR() << value << " invalid identifier";
+ }
+
+ std::ostringstream camel_case;
+
+ bool capitalize = true;
+ for (unsigned char c : value) {
+ if (c == '_') {
+ capitalize = true;
+ } else {
+ if (capitalize) {
+ c = std::toupper(c);
+ capitalize = false;
+ }
+ camel_case << c;
+ }
+ }
+
+ return camel_case.str();
+}
+
+inline bool IsEnumCase(std::string value) {
+ if (value[0] < 'A' || value[0] > 'Z') {
+ return false;
+ }
+
+ // Use static to avoid compiling the regex more than once.
+ static const std::regex enum_regex("[A-Z][A-Z0-9_]*");
+
+ return std::regex_match(value, enum_regex);
+}
+
+inline std::string StringJoin(const std::string& delimiter, const std::vector<std::string>& vec) {
+ std::stringstream ss;
+ for (size_t i = 0; i < vec.size(); i++) {
+ ss << vec[i];
+ if (i != (vec.size() - 1)) {
+ ss << delimiter;
+ }
+ }
+ return ss.str();
+}
+
+inline std::string StringFindAndReplaceAll(std::string text, const std::string& old, const std::string& replacement) {
+ auto pos = text.find(old);
+ while (pos != std::string::npos) {
+ text.replace(pos, old.size(), replacement);
+ pos = text.find(old, pos + replacement.size());
+ }
+ return text;
+}
+
+} // namespace util
diff --git a/gd/packet/python3_module.cc b/gd/packet/python3_module.cc
new file mode 100644
index 0000000..879732b
--- /dev/null
+++ b/gd/packet/python3_module.cc
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2019 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 <cstring>
+#include <memory>
+
+#include <pybind11/pybind11.h>
+#include <pybind11/stl.h>
+
+#include "packet/base_packet_builder.h"
+#include "packet/bit_inserter.h"
+#include "packet/iterator.h"
+#include "packet/packet_builder.h"
+#include "packet/packet_struct.h"
+#include "packet/packet_view.h"
+#include "packet/parser/checksum_type_checker.h"
+#include "packet/parser/custom_type_checker.h"
+
+namespace py = pybind11;
+
+namespace bluetooth {
+
+namespace hci {
+void define_hci_packets_submodule(py::module&);
+}
+namespace l2cap {
+void define_l2cap_packets_submodule(py::module&);
+}
+namespace security {
+void define_smp_packets_submodule(py::module&);
+}
+
+namespace packet {
+
+using ::bluetooth::packet::BasePacketBuilder;
+using ::bluetooth::packet::BaseStruct;
+using ::bluetooth::packet::BitInserter;
+using ::bluetooth::packet::CustomTypeChecker;
+using ::bluetooth::packet::Iterator;
+using ::bluetooth::packet::kLittleEndian;
+using ::bluetooth::packet::PacketBuilder;
+using ::bluetooth::packet::PacketStruct;
+using ::bluetooth::packet::PacketView;
+using ::bluetooth::packet::parser::ChecksumTypeChecker;
+
+PYBIND11_MODULE(bluetooth_packets_python3, m) {
+ py::class_<BasePacketBuilder>(m, "BasePacketBuilder");
+ py::class_<PacketBuilder<kLittleEndian>, BasePacketBuilder>(m, "PacketBuilderLittleEndian");
+ py::class_<PacketBuilder<!kLittleEndian>, BasePacketBuilder>(m, "PacketBuilderBigEndian");
+ py::class_<BaseStruct>(m, "BaseStruct");
+ py::class_<PacketStruct<kLittleEndian>, BaseStruct>(m, "PacketStructLittleEndian");
+ py::class_<PacketStruct<!kLittleEndian>, BaseStruct>(m, "PacketStructBigEndian");
+ py::class_<Iterator<kLittleEndian>>(m, "IteratorLittleEndian");
+ py::class_<Iterator<!kLittleEndian>>(m, "IteratorBigEndian");
+ py::class_<PacketView<kLittleEndian>>(m, "PacketViewLittleEndian").def(py::init([](std::vector<uint8_t> bytes) {
+ // Make a copy
+ auto bytes_shared = std::make_shared<std::vector<uint8_t>>(bytes);
+ return std::make_unique<PacketView<kLittleEndian>>(bytes_shared);
+ }));
+ py::class_<PacketView<!kLittleEndian>>(m, "PacketViewBigEndian").def(py::init([](std::vector<uint8_t> bytes) {
+ // Make a copy
+ auto bytes_shared = std::make_shared<std::vector<uint8_t>>(bytes);
+ return std::make_unique<PacketView<!kLittleEndian>>(bytes_shared);
+ }));
+
+ bluetooth::hci::define_hci_packets_submodule(m);
+ bluetooth::l2cap::define_l2cap_packets_submodule(m);
+ bluetooth::security::define_smp_packets_submodule(m);
+}
+
+} // namespace packet
+} // namespace bluetooth
diff --git a/gd/packet/raw_builder.cc b/gd/packet/raw_builder.cc
index fd61417..ec2ff68 100644
--- a/gd/packet/raw_builder.cc
+++ b/gd/packet/raw_builder.cc
@@ -17,16 +17,18 @@
#include "packet/raw_builder.h"
#include <algorithm>
+#include <utility>
#include "os/log.h"
+using bluetooth::hci::Address;
using std::vector;
-using bluetooth::common::Address;
namespace bluetooth {
namespace packet {
RawBuilder::RawBuilder(size_t max_bytes) : max_bytes_(max_bytes) {}
+RawBuilder::RawBuilder(std::vector<uint8_t> vec) : payload_(std::move(vec)) {}
bool RawBuilder::AddOctets(size_t octets, const vector<uint8_t>& bytes) {
if (payload_.size() + octets > max_bytes_) return false;
diff --git a/gd/packet/raw_builder.h b/gd/packet/raw_builder.h
index 8f9edf5..1c9552a 100644
--- a/gd/packet/raw_builder.h
+++ b/gd/packet/raw_builder.h
@@ -19,7 +19,7 @@
#include <cstdint>
#include <vector>
-#include "common/address.h"
+#include "hci/address.h"
#include "packet/bit_inserter.h"
#include "packet/packet_builder.h"
@@ -30,6 +30,7 @@
public:
RawBuilder() = default;
RawBuilder(size_t max_bytes);
+ RawBuilder(std::vector<uint8_t> vec);
virtual ~RawBuilder() = default;
virtual size_t size() const override;
@@ -38,7 +39,7 @@
// Add |address| to the payload. Return true if:
// - the new size of the payload is still <= |max_bytes_|
- bool AddAddress(const common::Address& address);
+ bool AddAddress(const hci::Address& address);
// Return true if |num_bytes| can be added to the payload.
bool CanAddOctets(size_t num_bytes) const;
@@ -63,7 +64,7 @@
// - the new size of the payload is still <= |max_bytes_|
bool AddOctets(size_t octets, uint64_t value);
- size_t max_bytes_{255};
+ size_t max_bytes_{0xffff};
// Underlying containers for storing the actual packet
std::vector<uint8_t> payload_;
diff --git a/gd/packet/raw_builder_unittest.cc b/gd/packet/raw_builder_unittest.cc
index 27cecd6..64ca0ed 100644
--- a/gd/packet/raw_builder_unittest.cc
+++ b/gd/packet/raw_builder_unittest.cc
@@ -20,9 +20,9 @@
#include <forward_list>
#include <memory>
-#include "common/address.h"
+#include "hci/address.h"
-using bluetooth::common::Address;
+using bluetooth::hci::Address;
using bluetooth::packet::BitInserter;
using std::vector;
@@ -65,5 +65,48 @@
ASSERT_EQ(count, packet);
}
+TEST(RawBuilderTest, buildStartingWithVector) {
+ std::vector<uint8_t> count_first(count.begin(), count.begin() + 0x8);
+ std::unique_ptr<RawBuilder> count_builder = std::make_unique<RawBuilder>(count_first);
+ count_builder->AddOctets4(0x0b0a0908);
+ count_builder->AddOctets2(0x0d0c);
+ count_builder->AddOctets1(0x0e);
+ count_builder->AddOctets1(0x0f);
+ count_builder->AddOctets8(0x1716151413121110);
+ std::vector<uint8_t> count_last(count.begin() + 0x18, count.end());
+ count_builder->AddOctets(count_last);
+
+ ASSERT_EQ(count.size(), count_builder->size());
+
+ std::vector<uint8_t> packet;
+ BitInserter it(packet);
+
+ count_builder->Serialize(it);
+
+ ASSERT_EQ(count, packet);
+}
+
+TEST(RawBuilderTest, testMaxBytes) {
+ const size_t kMaxBytes = count.size();
+ std::unique_ptr<RawBuilder> count_builder = std::make_unique<RawBuilder>(kMaxBytes);
+ ASSERT_TRUE(count_builder->AddOctets(count));
+ ASSERT_FALSE(count_builder->AddOctets4(0x0b0a0908));
+ ASSERT_FALSE(count_builder->AddOctets2(0x0d0c));
+ ASSERT_FALSE(count_builder->AddOctets1(0x0e));
+ ASSERT_FALSE(count_builder->AddOctets1(0x0f));
+ ASSERT_FALSE(count_builder->AddOctets8(0x1716151413121110));
+ std::vector<uint8_t> count_last(count.begin() + 0x18, count.end());
+ ASSERT_FALSE(count_builder->AddOctets(count_last));
+
+ ASSERT_EQ(count.size(), count_builder->size());
+
+ std::vector<uint8_t> packet;
+ BitInserter it(packet);
+
+ count_builder->Serialize(it);
+
+ ASSERT_EQ(count, packet);
+}
+
} // namespace packet
} // namespace bluetooth
diff --git a/gd/packet/view.h b/gd/packet/view.h
index 4f3b508..3b8b679 100644
--- a/gd/packet/view.h
+++ b/gd/packet/view.h
@@ -17,6 +17,7 @@
#pragma once
#include <cstdint>
+#include <memory>
#include <vector>
namespace bluetooth {
diff --git a/gd/security/Android.bp b/gd/security/Android.bp
new file mode 100644
index 0000000..7762461
--- /dev/null
+++ b/gd/security/Android.bp
@@ -0,0 +1,26 @@
+filegroup {
+ name: "BluetoothSecuritySources",
+ srcs: [
+ "ecc/multprecision.cc",
+ "ecc/p_256_ecc_pp.cc",
+ "ecdh_keys.cc",
+ "pairing_handler_le.cc",
+ "pairing_handler_le_legacy.cc",
+ "pairing_handler_le_secure_connections.cc",
+ "security_manager.cc",
+ "internal/security_manager_impl.cc",
+ "security_module.cc",
+ ":BluetoothSecurityChannelSources",
+ ],
+}
+
+filegroup {
+ name: "BluetoothSecurityTestSources",
+ srcs: [
+ "ecc/multipoint_test.cc",
+ "pairing_handler_le_unittest.cc",
+ "test/fake_l2cap_test.cc",
+ "test/pairing_handler_le_pair_test.cc",
+ ":BluetoothSecurityChannelTestSources",
+ ],
+}
diff --git a/gd/security/channel/Android.bp b/gd/security/channel/Android.bp
new file mode 100644
index 0000000..653902b
--- /dev/null
+++ b/gd/security/channel/Android.bp
@@ -0,0 +1,13 @@
+filegroup {
+ name: "BluetoothSecurityChannelSources",
+ srcs: [
+ "security_manager_channel.cc",
+ ]
+}
+
+filegroup {
+ name: "BluetoothSecurityChannelTestSources",
+ srcs: [
+ "security_manager_channel_unittest.cc",
+ ]
+}
diff --git a/gd/security/channel/security_manager_channel.cc b/gd/security/channel/security_manager_channel.cc
new file mode 100644
index 0000000..331bbec
--- /dev/null
+++ b/gd/security/channel/security_manager_channel.cc
@@ -0,0 +1,93 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "security_manager_channel.h"
+
+#include "security/smp_packets.h"
+
+using namespace bluetooth::hci;
+using namespace bluetooth::packet;
+using namespace bluetooth::security::channel;
+
+void SecurityManagerChannel::SendCommand(std::shared_ptr<hci::Device> device,
+ std::unique_ptr<SecurityCommandBuilder> command) {
+ hci_security_interface_->EnqueueCommand(
+ std::move(command), common::BindOnce(&SecurityManagerChannel::OnCommandComplete, common::Unretained(this)),
+ handler_);
+}
+
+void SecurityManagerChannel::OnCommandComplete(CommandCompleteView packet) {
+ ASSERT_LOG(packet.IsValid(), "Received invalid packet: %hx", packet.GetCommandOpCode());
+ // TODO(optedoblivion): Verify HCI commands
+}
+
+void SecurityManagerChannel::OnHciEventReceived(EventPacketView packet) {
+ ASSERT_LOG(listener_ != nullptr, "No listener set!");
+ std::shared_ptr<Device> device = nullptr;
+ auto event = EventPacketView::Create(std::move(packet));
+ ASSERT_LOG(event.IsValid(), "Received invalid packet");
+ const hci::EventCode code = event.GetEventCode();
+ switch (code) {
+ case hci::EventCode::CHANGE_CONNECTION_LINK_KEY_COMPLETE:
+ listener_->OnChangeConnectionLinkKeyComplete(device,
+ hci::ChangeConnectionLinkKeyCompleteView::Create(std::move(event)));
+ break;
+ case hci::EventCode::MASTER_LINK_KEY_COMPLETE:
+ listener_->OnMasterLinkKeyComplete(device, hci::MasterLinkKeyCompleteView::Create(std::move(event)));
+ break;
+ case hci::EventCode::PIN_CODE_REQUEST:
+ listener_->OnPinCodeRequest(device, hci::PinCodeRequestView::Create(std::move(event)));
+ break;
+ case hci::EventCode::LINK_KEY_REQUEST:
+ listener_->OnLinkKeyRequest(device, hci::LinkKeyRequestView::Create(std::move(event)));
+ break;
+ case hci::EventCode::LINK_KEY_NOTIFICATION:
+ listener_->OnLinkKeyNotification(device, hci::LinkKeyNotificationView::Create(std::move(event)));
+ break;
+ case hci::EventCode::IO_CAPABILITY_REQUEST:
+ listener_->OnIoCapabilityRequest(device, hci::IoCapabilityRequestView::Create(std::move(event)));
+ break;
+ case hci::EventCode::IO_CAPABILITY_RESPONSE:
+ listener_->OnIoCapabilityResponse(device, IoCapabilityResponseView::Create(std::move(event)));
+ break;
+ case hci::EventCode::SIMPLE_PAIRING_COMPLETE:
+ listener_->OnSimplePairingComplete(device, SimplePairingCompleteView::Create(std::move(event)));
+ break;
+ case hci::EventCode::RETURN_LINK_KEYS:
+ listener_->OnReturnLinkKeys(device, hci::ReturnLinkKeysView::Create(std::move(event)));
+ break;
+ case hci::EventCode::ENCRYPTION_CHANGE:
+ listener_->OnEncryptionChange(device, hci::EncryptionChangeView::Create(std::move(event)));
+ break;
+ case hci::EventCode::ENCRYPTION_KEY_REFRESH_COMPLETE:
+ listener_->OnEncryptionKeyRefreshComplete(device,
+ hci::EncryptionKeyRefreshCompleteView::Create(std::move(event)));
+ break;
+ case hci::EventCode::REMOTE_OOB_DATA_REQUEST:
+ listener_->OnRemoteOobDataRequest(device, hci::RemoteOobDataRequestView::Create(std::move(event)));
+ break;
+ case hci::EventCode::USER_PASSKEY_NOTIFICATION:
+ listener_->OnUserPasskeyNotification(device, hci::UserPasskeyNotificationView::Create(std::move(event)));
+ break;
+ case hci::EventCode::KEYPRESS_NOTIFICATION:
+ listener_->OnKeypressNotification(device, hci::KeypressNotificationView::Create(std::move(event)));
+ break;
+ default:
+ ASSERT_LOG(false, "Invalid packet received: %hhx", code);
+ break;
+ }
+}
diff --git a/gd/security/channel/security_manager_channel.h b/gd/security/channel/security_manager_channel.h
new file mode 100644
index 0000000..02d0357
--- /dev/null
+++ b/gd/security/channel/security_manager_channel.h
@@ -0,0 +1,116 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include "hci/classic_device.h"
+#include "hci/hci_layer.h"
+#include "hci/security_interface.h"
+#include "security/smp_packets.h"
+
+namespace bluetooth {
+namespace security {
+namespace channel {
+
+using hci::CommandCompleteView;
+using hci::EventPacketView;
+using hci::SecurityCommandBuilder;
+using hci::SecurityCommandView;
+
+/**
+ * Interface for listening to the channel for SMP commands.
+ */
+class ISecurityManagerChannelListener {
+ public:
+ virtual ~ISecurityManagerChannelListener() = default;
+
+ virtual void OnChangeConnectionLinkKeyComplete(std::shared_ptr<hci::Device> device,
+ hci::ChangeConnectionLinkKeyCompleteView packet) = 0;
+ virtual void OnMasterLinkKeyComplete(std::shared_ptr<hci::Device> device, hci::MasterLinkKeyCompleteView packet) = 0;
+ virtual void OnPinCodeRequest(std::shared_ptr<hci::Device> device, hci::PinCodeRequestView packet) = 0;
+ virtual void OnLinkKeyRequest(std::shared_ptr<hci::Device> device, hci::LinkKeyRequestView packet) = 0;
+ virtual void OnLinkKeyNotification(std::shared_ptr<hci::Device> device, hci::LinkKeyNotificationView packet) = 0;
+ virtual void OnIoCapabilityRequest(std::shared_ptr<hci::Device> device, hci::IoCapabilityRequestView packet) = 0;
+ virtual void OnIoCapabilityResponse(std::shared_ptr<hci::Device> device, hci::IoCapabilityResponseView packet) = 0;
+ virtual void OnSimplePairingComplete(std::shared_ptr<hci::Device> device, hci::SimplePairingCompleteView packet) = 0;
+ virtual void OnReturnLinkKeys(std::shared_ptr<hci::Device> device, hci::ReturnLinkKeysView packet) = 0;
+ virtual void OnEncryptionChange(std::shared_ptr<hci::Device> device, hci::EncryptionChangeView packet) = 0;
+ virtual void OnEncryptionKeyRefreshComplete(std::shared_ptr<hci::Device> device,
+ hci::EncryptionKeyRefreshCompleteView packet) = 0;
+ virtual void OnRemoteOobDataRequest(std::shared_ptr<hci::Device> device, hci::RemoteOobDataRequestView packet) = 0;
+ virtual void OnUserPasskeyNotification(std::shared_ptr<hci::Device> device,
+ hci::UserPasskeyNotificationView packet) = 0;
+ virtual void OnKeypressNotification(std::shared_ptr<hci::Device> device, hci::KeypressNotificationView packet) = 0;
+};
+
+/**
+ * Channel for consolidating traffic and making the transport agnostic.
+ */
+class SecurityManagerChannel {
+ public:
+ explicit SecurityManagerChannel(os::Handler* handler, hci::HciLayer* hci_layer)
+ : listener_(nullptr),
+ hci_security_interface_(hci_layer->GetSecurityInterface(
+ common::Bind(&SecurityManagerChannel::OnHciEventReceived, common::Unretained(this)), handler)),
+ handler_(handler) {}
+ ~SecurityManagerChannel() {
+ delete listener_;
+ }
+
+ /**
+ * Send a given SMP command over the SecurityManagerChannel
+ *
+ * @param device target where command will be sent
+ * @param command smp command to send
+ */
+ void SendCommand(std::shared_ptr<hci::Device> device, std::unique_ptr<SecurityCommandBuilder> command);
+
+ /**
+ * Sets the listener to listen for channel events
+ *
+ * @param listener the caller interested in events
+ */
+ void SetChannelListener(ISecurityManagerChannelListener* listener) {
+ listener_ = listener;
+ }
+
+ /**
+ * Called when an incoming HCI event happens
+ *
+ * @param event_packet
+ */
+ void OnHciEventReceived(EventPacketView packet);
+
+ /**
+ * Called when an HCI command is completed
+ *
+ * @param on_complete
+ */
+ void OnCommandComplete(CommandCompleteView packet);
+
+ private:
+ ISecurityManagerChannelListener* listener_;
+ hci::SecurityInterface* hci_security_interface_;
+ os::Handler* handler_;
+};
+
+} // namespace channel
+} // namespace security
+} // namespace bluetooth
diff --git a/gd/security/channel/security_manager_channel_unittest.cc b/gd/security/channel/security_manager_channel_unittest.cc
new file mode 100644
index 0000000..b111e7f
--- /dev/null
+++ b/gd/security/channel/security_manager_channel_unittest.cc
@@ -0,0 +1,558 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "security_manager_channel.h"
+
+#include <gtest/gtest.h>
+
+#include "hci/device.h"
+#include "hci/device_database.h"
+#include "hci/hci_packets.h"
+#include "packet/raw_builder.h"
+#include "security/smp_packets.h"
+#include "security/test/fake_hci_layer.h"
+
+namespace bluetooth {
+namespace security {
+namespace channel {
+namespace {
+
+using bluetooth::security::channel::SecurityManagerChannel;
+using hci::AuthenticationRequirements;
+using hci::CommandCompleteBuilder;
+using hci::Device;
+using hci::DeviceDatabase;
+using hci::IoCapabilityRequestReplyBuilder;
+using hci::IoCapabilityRequestView;
+using hci::OobDataPresent;
+using hci::OpCode;
+using os::Handler;
+using os::Thread;
+using packet::RawBuilder;
+
+static DeviceDatabase kDeviceDatabase;
+
+class SecurityManagerChannelCallback : public ISecurityManagerChannelListener {
+ public:
+ // HCI
+ bool receivedChangeConnectionLinkKeyComplete = false;
+ bool receivedMasterLinkKeyComplete = false;
+ bool receivedPinCodeRequest = false;
+ bool receivedLinkKeyRequest = false;
+ bool receivedLinkKeyNotification = false;
+ bool receivedIoCapabilityRequest = false;
+ bool receivedIoCapabilityResponse = false;
+ bool receivedSimplePairingComplete = false;
+ bool receivedReturnLinkKeys = false;
+ bool receivedEncryptionChange = false;
+ bool receivedEncryptionKeyRefreshComplete = false;
+ bool receivedRemoteOobDataRequest = false;
+ bool receivedUserPasskeyNotification = false;
+ bool receivedKeypressNotification = false;
+
+ void OnChangeConnectionLinkKeyComplete(std::shared_ptr<hci::Device> device,
+ hci::ChangeConnectionLinkKeyCompleteView packet) {
+ EXPECT_TRUE(packet.IsValid());
+ receivedChangeConnectionLinkKeyComplete = true;
+ }
+ void OnMasterLinkKeyComplete(std::shared_ptr<hci::Device> device, hci::MasterLinkKeyCompleteView packet) {
+ EXPECT_TRUE(packet.IsValid());
+ receivedMasterLinkKeyComplete = true;
+ }
+ void OnPinCodeRequest(std::shared_ptr<hci::Device> device, hci::PinCodeRequestView packet) {
+ EXPECT_TRUE(packet.IsValid());
+ receivedPinCodeRequest = true;
+ }
+ void OnLinkKeyRequest(std::shared_ptr<hci::Device> device, hci::LinkKeyRequestView packet) {
+ EXPECT_TRUE(packet.IsValid());
+ receivedLinkKeyRequest = true;
+ }
+ void OnLinkKeyNotification(std::shared_ptr<hci::Device> device, hci::LinkKeyNotificationView packet) {
+ EXPECT_TRUE(packet.IsValid());
+ receivedLinkKeyNotification = true;
+ }
+ void OnIoCapabilityRequest(std::shared_ptr<Device> device, hci::IoCapabilityRequestView packet) {
+ EXPECT_TRUE(packet.IsValid());
+ receivedIoCapabilityRequest = true;
+ }
+ void OnIoCapabilityResponse(std::shared_ptr<Device> device, hci::IoCapabilityResponseView packet) {
+ EXPECT_TRUE(packet.IsValid());
+ receivedIoCapabilityResponse = true;
+ }
+ void OnSimplePairingComplete(std::shared_ptr<Device> device, hci::SimplePairingCompleteView packet) {
+ EXPECT_TRUE(packet.IsValid());
+ receivedSimplePairingComplete = true;
+ }
+ void OnReturnLinkKeys(std::shared_ptr<Device> device, hci::ReturnLinkKeysView packet) {
+ EXPECT_TRUE(packet.IsValid());
+ receivedReturnLinkKeys = true;
+ }
+ void OnEncryptionChange(std::shared_ptr<Device> device, hci::EncryptionChangeView packet) {
+ EXPECT_TRUE(packet.IsValid());
+ receivedEncryptionChange = true;
+ }
+ void OnEncryptionKeyRefreshComplete(std::shared_ptr<Device> device, hci::EncryptionKeyRefreshCompleteView packet) {
+ EXPECT_TRUE(packet.IsValid());
+ receivedEncryptionKeyRefreshComplete = true;
+ }
+ void OnRemoteOobDataRequest(std::shared_ptr<Device> device, hci::RemoteOobDataRequestView packet) {
+ EXPECT_TRUE(packet.IsValid());
+ receivedRemoteOobDataRequest = true;
+ }
+ void OnUserPasskeyNotification(std::shared_ptr<hci::Device> device, hci::UserPasskeyNotificationView packet) {
+ EXPECT_TRUE(packet.IsValid());
+ receivedUserPasskeyNotification = true;
+ }
+ void OnKeypressNotification(std::shared_ptr<hci::Device> device, hci::KeypressNotificationView packet) {
+ EXPECT_TRUE(packet.IsValid());
+ receivedKeypressNotification = true;
+ }
+};
+
+class SecurityManagerChannelTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ device_ = kDeviceDatabase.CreateClassicDevice(hci::Address({0x01, 0x02, 0x03, 0x04, 0x05, 0x06}));
+ handler_ = new Handler(&thread_);
+ callback_ = new SecurityManagerChannelCallback();
+ hci_layer_ = new FakeHciLayer();
+ fake_registry_.InjectTestModule(&FakeHciLayer::Factory, hci_layer_);
+ fake_registry_.Start<FakeHciLayer>(&thread_);
+ channel_ = new SecurityManagerChannel(handler_, hci_layer_);
+ channel_->SetChannelListener(callback_);
+ }
+
+ void TearDown() override {
+ channel_->SetChannelListener(nullptr);
+ handler_->Clear();
+ fake_registry_.SynchronizeModuleHandler(&FakeHciLayer::Factory, std::chrono::milliseconds(20));
+ fake_registry_.StopAll();
+ delete handler_;
+ delete channel_;
+ delete callback_;
+ }
+
+ TestModuleRegistry fake_registry_;
+ Thread& thread_ = fake_registry_.GetTestThread();
+ Handler* handler_ = nullptr;
+ FakeHciLayer* hci_layer_ = nullptr;
+ SecurityManagerChannel* channel_ = nullptr;
+ SecurityManagerChannelCallback* callback_ = nullptr;
+ std::shared_ptr<Device> device_ = nullptr;
+};
+
+TEST_F(SecurityManagerChannelTest, setup_teardown) {}
+
+TEST_F(SecurityManagerChannelTest, recv_io_cap_request) {
+ hci_layer_->IncomingEvent(hci::IoCapabilityRequestBuilder::Create(device_->GetAddress()));
+ EXPECT_TRUE(callback_->receivedIoCapabilityRequest);
+}
+
+TEST_F(SecurityManagerChannelTest, send_io_cap_request_reply) {
+ // Arrange
+ hci::IoCapability io_capability = (hci::IoCapability)0x00;
+ OobDataPresent oob_present = (OobDataPresent)0x00;
+ AuthenticationRequirements authentication_requirements = (AuthenticationRequirements)0x00;
+ auto packet = hci::IoCapabilityRequestReplyBuilder::Create(device_->GetAddress(), io_capability, oob_present,
+ authentication_requirements);
+
+ // Act
+ channel_->SendCommand(device_, std::move(packet));
+ auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+ // Assert
+ EXPECT_TRUE(packet_view.IsValid());
+ EXPECT_EQ(OpCode::IO_CAPABILITY_REQUEST_REPLY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_io_cap_request_neg_reply) {
+ // Arrange
+ auto packet =
+ hci::IoCapabilityRequestNegativeReplyBuilder::Create(device_->GetAddress(), hci::ErrorCode::COMMAND_DISALLOWED);
+
+ // Act
+ channel_->SendCommand(device_, std::move(packet));
+ auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+ // Assert
+ EXPECT_TRUE(packet_view.IsValid());
+ EXPECT_EQ(OpCode::IO_CAPABILITY_REQUEST_NEGATIVE_REPLY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, recv_io_cap_response) {
+ hci::IoCapability io_capability = (hci::IoCapability)0x00;
+ OobDataPresent oob_present = (OobDataPresent)0x00;
+ AuthenticationRequirements authentication_requirements = (AuthenticationRequirements)0x00;
+ hci_layer_->IncomingEvent(hci::IoCapabilityResponseBuilder::Create(device_->GetAddress(), io_capability, oob_present,
+ authentication_requirements));
+ EXPECT_TRUE(callback_->receivedIoCapabilityResponse);
+}
+
+TEST_F(SecurityManagerChannelTest, recv_pin_code_request) {
+ hci_layer_->IncomingEvent(hci::PinCodeRequestBuilder::Create(device_->GetAddress()));
+ EXPECT_TRUE(callback_->receivedPinCodeRequest);
+}
+
+TEST_F(SecurityManagerChannelTest, send_pin_code_request_reply) {
+ // Arrange
+ uint8_t pin_code_length = 6;
+ std::array<uint8_t, 16> pin_code = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5};
+ auto packet = hci::PinCodeRequestReplyBuilder::Create(device_->GetAddress(), pin_code_length, pin_code);
+
+ // Act
+ channel_->SendCommand(device_, std::move(packet));
+ auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+ // Assert
+ EXPECT_TRUE(packet_view.IsValid());
+ EXPECT_EQ(OpCode::PIN_CODE_REQUEST_REPLY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_pin_code_request_neg_reply) {
+ // Arrange
+ auto packet = hci::PinCodeRequestNegativeReplyBuilder::Create(device_->GetAddress());
+
+ // Act
+ channel_->SendCommand(device_, std::move(packet));
+ auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+ // Assert
+ EXPECT_TRUE(packet_view.IsValid());
+ EXPECT_EQ(OpCode::PIN_CODE_REQUEST_NEGATIVE_REPLY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, recv_user_passkey_notification) {
+ uint32_t passkey = 0x00;
+ hci_layer_->IncomingEvent(hci::UserPasskeyNotificationBuilder::Create(device_->GetAddress(), passkey));
+ EXPECT_TRUE(callback_->receivedUserPasskeyNotification);
+}
+
+TEST_F(SecurityManagerChannelTest, send_user_confirmation_request_reply) {
+ // Arrange
+ auto packet = hci::UserConfirmationRequestReplyBuilder::Create(device_->GetAddress());
+
+ // Act
+ channel_->SendCommand(device_, std::move(packet));
+ auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+ // Assert
+ EXPECT_TRUE(packet_view.IsValid());
+ EXPECT_EQ(OpCode::USER_CONFIRMATION_REQUEST_REPLY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_user_confirmation_request_neg_reply) {
+ // Arrange
+ auto packet = hci::UserConfirmationRequestNegativeReplyBuilder::Create(device_->GetAddress());
+
+ // Act
+ channel_->SendCommand(device_, std::move(packet));
+ auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+ // Assert
+ EXPECT_TRUE(packet_view.IsValid());
+ EXPECT_EQ(OpCode::USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, recv_remote_oob_data_request) {
+ hci_layer_->IncomingEvent(hci::RemoteOobDataRequestBuilder::Create(device_->GetAddress()));
+ EXPECT_TRUE(callback_->receivedRemoteOobDataRequest);
+}
+
+TEST_F(SecurityManagerChannelTest, send_remote_oob_data_request_reply) {
+ // Arrange
+ std::array<uint8_t, 16> c = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5};
+ std::array<uint8_t, 16> r = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5};
+ auto packet = hci::RemoteOobDataRequestReplyBuilder::Create(device_->GetAddress(), c, r);
+
+ // Act
+ channel_->SendCommand(device_, std::move(packet));
+ auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+ // Assert
+ EXPECT_TRUE(packet_view.IsValid());
+ EXPECT_EQ(OpCode::REMOTE_OOB_DATA_REQUEST_REPLY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_remote_oob_data_request_neg_reply) {
+ // Arrange
+ auto packet = hci::RemoteOobDataRequestNegativeReplyBuilder::Create(device_->GetAddress());
+
+ // Act
+ channel_->SendCommand(device_, std::move(packet));
+ auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+ // Assert
+ EXPECT_TRUE(packet_view.IsValid());
+ EXPECT_EQ(OpCode::REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_read_local_oob_data) {
+ // Arrange
+ auto packet = hci::ReadLocalOobDataBuilder::Create();
+
+ // Act
+ channel_->SendCommand(device_, std::move(packet));
+ auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+ // Assert
+ EXPECT_TRUE(packet_view.IsValid());
+ EXPECT_EQ(OpCode::READ_LOCAL_OOB_DATA, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_read_local_oob_extended_data) {
+ // Arrange
+ auto packet = hci::ReadLocalOobExtendedDataBuilder::Create();
+
+ // Act
+ channel_->SendCommand(device_, std::move(packet));
+ auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+ // Assert
+ EXPECT_TRUE(packet_view.IsValid());
+ EXPECT_EQ(OpCode::READ_LOCAL_OOB_EXTENDED_DATA, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, recv_link_key_request) {
+ hci_layer_->IncomingEvent(hci::LinkKeyRequestBuilder::Create(device_->GetAddress()));
+ EXPECT_TRUE(callback_->receivedLinkKeyRequest);
+}
+
+TEST_F(SecurityManagerChannelTest, recv_link_key_notification) {
+ std::array<uint8_t, 16> link_key = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5};
+ hci_layer_->IncomingEvent(
+ hci::LinkKeyNotificationBuilder::Create(device_->GetAddress(), link_key, hci::KeyType::DEBUG_COMBINATION));
+ EXPECT_TRUE(callback_->receivedLinkKeyNotification);
+}
+
+TEST_F(SecurityManagerChannelTest, recv_master_link_key_complete) {
+ uint16_t connection_handle = 0x0;
+ hci_layer_->IncomingEvent(
+ hci::MasterLinkKeyCompleteBuilder::Create(hci::ErrorCode::SUCCESS, connection_handle, hci::KeyFlag::TEMPORARY));
+ EXPECT_TRUE(callback_->receivedMasterLinkKeyComplete);
+}
+
+TEST_F(SecurityManagerChannelTest, recv_change_connection_link_key_complete) {
+ uint16_t connection_handle = 0x0;
+ hci_layer_->IncomingEvent(
+ hci::ChangeConnectionLinkKeyCompleteBuilder::Create(hci::ErrorCode::SUCCESS, connection_handle));
+ EXPECT_TRUE(callback_->receivedChangeConnectionLinkKeyComplete);
+}
+
+TEST_F(SecurityManagerChannelTest, recv_return_link_keys) {
+ std::vector<hci::ZeroKeyAndAddress> keys;
+ hci_layer_->IncomingEvent(hci::ReturnLinkKeysBuilder::Create(keys));
+ EXPECT_TRUE(callback_->receivedReturnLinkKeys);
+}
+
+TEST_F(SecurityManagerChannelTest, send_link_key_request_reply) {
+ // Arrange
+ std::array<uint8_t, 16> link_key = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5};
+ auto packet = hci::LinkKeyRequestReplyBuilder::Create(device_->GetAddress(), link_key);
+
+ // Act
+ channel_->SendCommand(device_, std::move(packet));
+ auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+ // Assert
+ EXPECT_TRUE(packet_view.IsValid());
+ EXPECT_EQ(OpCode::LINK_KEY_REQUEST_REPLY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_link_key_request_neg_reply) {
+ // Arrange
+ auto packet = hci::LinkKeyRequestNegativeReplyBuilder::Create(device_->GetAddress());
+
+ // Act
+ channel_->SendCommand(device_, std::move(packet));
+ auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+ // Assert
+ EXPECT_TRUE(packet_view.IsValid());
+ EXPECT_EQ(OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_read_stored_link_key) {
+ // Arrange
+ auto packet = hci::ReadStoredLinkKeyBuilder::Create(device_->GetAddress(), hci::ReadStoredLinkKeyReadAllFlag::ALL);
+
+ // Act
+ channel_->SendCommand(device_, std::move(packet));
+ auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+ // Assert
+ EXPECT_TRUE(packet_view.IsValid());
+ EXPECT_EQ(OpCode::READ_STORED_LINK_KEY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_write_stored_link_key) {
+ // Arrange
+ std::vector<hci::KeyAndAddress> keys_to_write;
+ auto packet = hci::WriteStoredLinkKeyBuilder::Create(keys_to_write);
+
+ // Act
+ channel_->SendCommand(device_, std::move(packet));
+ auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+ // Assert
+ EXPECT_TRUE(packet_view.IsValid());
+ EXPECT_EQ(OpCode::WRITE_STORED_LINK_KEY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_delete_stored_link_key) {
+ // Arrange
+ auto packet =
+ hci::DeleteStoredLinkKeyBuilder::Create(device_->GetAddress(), hci::DeleteStoredLinkKeyDeleteAllFlag::ALL);
+
+ // Act
+ channel_->SendCommand(device_, std::move(packet));
+ auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+ // Assert
+ EXPECT_TRUE(packet_view.IsValid());
+ EXPECT_EQ(OpCode::DELETE_STORED_LINK_KEY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, recv_encryption_change) {
+ uint16_t connection_handle = 0x0;
+ hci_layer_->IncomingEvent(
+ hci::EncryptionChangeBuilder::Create(hci::ErrorCode::SUCCESS, connection_handle, hci::EncryptionEnabled::ON));
+ EXPECT_TRUE(callback_->receivedEncryptionChange);
+}
+
+TEST_F(SecurityManagerChannelTest, send_refresh_encryption_key) {
+ // Arrange
+ uint16_t connection_handle = 0x0;
+ auto packet = hci::RefreshEncryptionKeyBuilder::Create(connection_handle);
+
+ // Act
+ channel_->SendCommand(device_, std::move(packet));
+ auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+ // Assert
+ EXPECT_TRUE(packet_view.IsValid());
+ EXPECT_EQ(OpCode::REFRESH_ENCRYPTION_KEY, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_read_encryption_key_size) {
+ // Arrange
+ uint16_t connection_handle = 0x0;
+ auto packet = hci::ReadEncryptionKeySizeBuilder::Create(connection_handle);
+
+ // Act
+ channel_->SendCommand(device_, std::move(packet));
+ auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+ // Assert
+ EXPECT_TRUE(packet_view.IsValid());
+ EXPECT_EQ(OpCode::READ_ENCRYPTION_KEY_SIZE, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, recv_simple_pairing_complete) {
+ hci_layer_->IncomingEvent(hci::SimplePairingCompleteBuilder::Create(hci::ErrorCode::SUCCESS, device_->GetAddress()));
+ EXPECT_TRUE(callback_->receivedSimplePairingComplete);
+}
+
+TEST_F(SecurityManagerChannelTest, send_read_simple_pairing_mode) {
+ // Arrange
+ auto packet = hci::ReadSimplePairingModeBuilder::Create();
+
+ // Act
+ channel_->SendCommand(device_, std::move(packet));
+ auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+ // Assert
+ EXPECT_TRUE(packet_view.IsValid());
+ EXPECT_EQ(OpCode::READ_SIMPLE_PAIRING_MODE, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, send_write_simple_pairing_mode) {
+ // Arrange
+ auto packet = hci::WriteSimplePairingModeBuilder::Create(hci::Enable::ENABLED);
+
+ // Act
+ channel_->SendCommand(device_, std::move(packet));
+ auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+ // Assert
+ EXPECT_TRUE(packet_view.IsValid());
+ EXPECT_EQ(OpCode::WRITE_SIMPLE_PAIRING_MODE, packet_view.GetOpCode());
+}
+
+TEST_F(SecurityManagerChannelTest, recv_keypress_notification) {
+ hci_layer_->IncomingEvent(
+ hci::KeypressNotificationBuilder::Create(device_->GetAddress(), hci::KeypressNotificationType::ENTRY_COMPLETED));
+ EXPECT_TRUE(callback_->receivedKeypressNotification);
+}
+
+TEST_F(SecurityManagerChannelTest, send_keypress_notification) {
+ // Arrange
+ auto packet =
+ hci::SendKeypressNotificationBuilder::Create(device_->GetAddress(), hci::KeypressNotificationType::ENTRY_STARTED);
+
+ // Act
+ channel_->SendCommand(device_, std::move(packet));
+ auto last_command = std::move(hci_layer_->GetLastCommand()->command);
+ auto command_packet = GetPacketView(std::move(last_command));
+ hci::CommandPacketView packet_view = hci::CommandPacketView::Create(command_packet);
+
+ // Assert
+ EXPECT_TRUE(packet_view.IsValid());
+ EXPECT_EQ(OpCode::SEND_KEYPRESS_NOTIFICATION, packet_view.GetOpCode());
+}
+
+} // namespace
+} // namespace channel
+} // namespace security
+} // namespace bluetooth
diff --git a/gd/security/ecc/multipoint_test.cc b/gd/security/ecc/multipoint_test.cc
new file mode 100644
index 0000000..95e43d4
--- /dev/null
+++ b/gd/security/ecc/multipoint_test.cc
@@ -0,0 +1,112 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 <gtest/gtest.h>
+
+#include "security/ecc/p_256_ecc_pp.h"
+
+namespace bluetooth {
+namespace security {
+namespace ecc {
+
+// Test ECC point validation
+TEST(SmpEccValidationTest, test_valid_points) {
+ Point p;
+
+ // Test data from Bluetooth Core Specification
+ // Version 5.0 | Vol 2, Part G | 7.1.2
+
+ // Sample 1
+ p.x[7] = 0x20b003d2;
+ p.x[6] = 0xf297be2c;
+ p.x[5] = 0x5e2c83a7;
+ p.x[4] = 0xe9f9a5b9;
+ p.x[3] = 0xeff49111;
+ p.x[2] = 0xacf4fddb;
+ p.x[1] = 0xcc030148;
+ p.x[0] = 0x0e359de6;
+
+ p.y[7] = 0xdc809c49;
+ p.y[6] = 0x652aeb6d;
+ p.y[5] = 0x63329abf;
+ p.y[4] = 0x5a52155c;
+ p.y[3] = 0x766345c2;
+ p.y[2] = 0x8fed3024;
+ p.y[1] = 0x741c8ed0;
+ p.y[0] = 0x1589d28b;
+
+ EXPECT_TRUE(ECC_ValidatePoint(p));
+
+ // Sample 2
+ p.x[7] = 0x2c31a47b;
+ p.x[6] = 0x5779809e;
+ p.x[5] = 0xf44cb5ea;
+ p.x[4] = 0xaf5c3e43;
+ p.x[3] = 0xd5f8faad;
+ p.x[2] = 0x4a8794cb;
+ p.x[1] = 0x987e9b03;
+ p.x[0] = 0x745c78dd;
+
+ p.y[7] = 0x91951218;
+ p.y[6] = 0x3898dfbe;
+ p.y[5] = 0xcd52e240;
+ p.y[4] = 0x8e43871f;
+ p.y[3] = 0xd0211091;
+ p.y[2] = 0x17bd3ed4;
+ p.y[1] = 0xeaf84377;
+ p.y[0] = 0x43715d4f;
+
+ EXPECT_TRUE(ECC_ValidatePoint(p));
+}
+
+TEST(SmpEccValidationTest, test_invalid_points) {
+ Point p;
+ multiprecision_init(p.x);
+ multiprecision_init(p.y);
+
+ EXPECT_FALSE(ECC_ValidatePoint(p));
+
+ // Sample 1
+ p.x[7] = 0x20b003d2;
+ p.x[6] = 0xf297be2c;
+ p.x[5] = 0x5e2c83a7;
+ p.x[4] = 0xe9f9a5b9;
+ p.x[3] = 0xeff49111;
+ p.x[2] = 0xacf4fddb;
+ p.x[1] = 0xcc030148;
+ p.x[0] = 0x0e359de6;
+
+ EXPECT_FALSE(ECC_ValidatePoint(p));
+
+ p.y[7] = 0xdc809c49;
+ p.y[6] = 0x652aeb6d;
+ p.y[5] = 0x63329abf;
+ p.y[4] = 0x5a52155c;
+ p.y[3] = 0x766345c2;
+ p.y[2] = 0x8fed3024;
+ p.y[1] = 0x741c8ed0;
+ p.y[0] = 0x1589d28b;
+
+ p.y[0]--;
+
+ EXPECT_FALSE(ECC_ValidatePoint(p));
+}
+
+} // namespace ecc
+} // namespace security
+} // namespace bluetooth
diff --git a/gd/security/ecc/multprecision.cc b/gd/security/ecc/multprecision.cc
new file mode 100644
index 0000000..c2583ed
--- /dev/null
+++ b/gd/security/ecc/multprecision.cc
@@ -0,0 +1,504 @@
+/******************************************************************************
+ *
+ * Copyright 2006-2015 Broadcom Corporation
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * This file contains simple pairing algorithms
+ *
+ ******************************************************************************/
+
+#include "security/ecc/multprecision.h"
+#include <string.h>
+
+namespace bluetooth {
+namespace security {
+namespace ecc {
+
+#define DWORD_BITS 32
+#define DWORD_BYTES 4
+#define DWORD_BITS_SHIFT 5
+
+void multiprecision_init(uint32_t* c) {
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) c[i] = 0;
+}
+
+void multiprecision_copy(uint32_t* c, const uint32_t* a) {
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) c[i] = a[i];
+}
+
+int multiprecision_compare(const uint32_t* a, const uint32_t* b) {
+ for (int i = KEY_LENGTH_DWORDS_P256 - 1; i >= 0; i--) {
+ if (a[i] > b[i]) return 1;
+ if (a[i] < b[i]) return -1;
+ }
+ return 0;
+}
+
+int multiprecision_iszero(const uint32_t* a) {
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++)
+ if (a[i]) return 0;
+
+ return 1;
+}
+
+uint32_t multiprecision_dword_bits(uint32_t a) {
+ uint32_t i;
+ for (i = 0; i < DWORD_BITS; i++, a >>= 1)
+ if (a == 0) break;
+
+ return i;
+}
+
+uint32_t multiprecision_most_signdwords(const uint32_t* a) {
+ int i;
+ for (i = KEY_LENGTH_DWORDS_P256 - 1; i >= 0; i--)
+ if (a[i]) break;
+ return (i + 1);
+}
+
+uint32_t multiprecision_most_signbits(const uint32_t* a) {
+ int aMostSignDWORDs;
+
+ aMostSignDWORDs = multiprecision_most_signdwords(a);
+ if (aMostSignDWORDs == 0) return 0;
+
+ return (((aMostSignDWORDs - 1) << DWORD_BITS_SHIFT) + multiprecision_dword_bits(a[aMostSignDWORDs - 1]));
+}
+
+uint32_t multiprecision_add(uint32_t* c, const uint32_t* a, const uint32_t* b) {
+ uint32_t carrier;
+ uint32_t temp;
+
+ carrier = 0;
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) {
+ temp = a[i] + carrier;
+ carrier = (temp < carrier);
+ temp += b[i];
+ carrier |= (temp < b[i]);
+ c[i] = temp;
+ }
+
+ return carrier;
+}
+
+// c=a-b
+uint32_t multiprecision_sub(uint32_t* c, const uint32_t* a, const uint32_t* b) {
+ uint32_t borrow;
+ uint32_t temp;
+
+ borrow = 0;
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) {
+ temp = a[i] - borrow;
+ borrow = (temp > a[i]);
+ c[i] = temp - b[i];
+ borrow |= (c[i] > temp);
+ }
+
+ return borrow;
+}
+
+// c = a << 1
+void multiprecision_lshift_mod(uint32_t* c, const uint32_t* a, const uint32_t* modp) {
+ uint32_t carrier = multiprecision_lshift(c, a);
+ if (carrier) {
+ multiprecision_sub(c, c, modp);
+ } else if (multiprecision_compare(c, modp) >= 0) {
+ multiprecision_sub(c, c, modp);
+ }
+}
+
+// c=a>>1
+void multiprecision_rshift(uint32_t* c, const uint32_t* a) {
+ int j;
+ uint32_t b = 1;
+
+ j = DWORD_BITS - b;
+
+ uint32_t carrier = 0;
+ uint32_t temp;
+ for (int i = KEY_LENGTH_DWORDS_P256 - 1; i >= 0; i--) {
+ temp = a[i]; // in case of c==a
+ c[i] = (temp >> b) | carrier;
+ carrier = temp << j;
+ }
+}
+
+// Curve specific optimization when p is a pseudo-Mersenns prime,
+// p=2^(KEY_LENGTH_BITS)-omega
+void multiprecision_mersenns_mult_mod(uint32_t* c, const uint32_t* a, const uint32_t* b, const uint32_t* modp) {
+ uint32_t cc[2 * KEY_LENGTH_DWORDS_P256];
+
+ multiprecision_mult(cc, a, b);
+ multiprecision_fast_mod_P256(c, cc, modp);
+}
+
+// Curve specific optimization when p is a pseudo-Mersenns prime
+void multiprecision_mersenns_squa_mod(uint32_t* c, const uint32_t* a, const uint32_t* modp) {
+ multiprecision_mersenns_mult_mod(c, a, a, modp);
+}
+
+// c=(a+b) mod p, b<p, a<p
+void multiprecision_add_mod(uint32_t* c, const uint32_t* a, const uint32_t* b, const uint32_t* modp) {
+ uint32_t carrier = multiprecision_add(c, a, b);
+ if (carrier) {
+ multiprecision_sub(c, c, modp);
+ } else if (multiprecision_compare(c, modp) >= 0) {
+ multiprecision_sub(c, c, modp);
+ }
+}
+
+// c=(a-b) mod p, a<p, b<p
+void multiprecision_sub_mod(uint32_t* c, const uint32_t* a, const uint32_t* b, const uint32_t* modp) {
+ uint32_t borrow;
+
+ borrow = multiprecision_sub(c, a, b);
+ if (borrow) multiprecision_add(c, c, modp);
+}
+
+// c=a<<b, b<DWORD_BITS, c has a buffer size of Numuint32_ts+1
+uint32_t multiprecision_lshift(uint32_t* c, const uint32_t* a) {
+ int j;
+ uint32_t b = 1;
+ j = DWORD_BITS - b;
+
+ uint32_t carrier = 0;
+ uint32_t temp;
+
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) {
+ temp = a[i]; // in case c==a
+ c[i] = (temp << b) | carrier;
+ carrier = temp >> j;
+ }
+
+ return carrier;
+}
+
+// c=a*b; c must have a buffer of 2*Key_LENGTH_uint32_tS, c != a != b
+void multiprecision_mult(uint32_t* c, const uint32_t* a, const uint32_t* b) {
+ uint32_t W;
+ uint32_t U;
+ uint32_t V;
+
+ U = V = W = 0;
+ multiprecision_init(c);
+
+ // assume little endian right now
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) {
+ U = 0;
+ for (uint32_t j = 0; j < KEY_LENGTH_DWORDS_P256; j++) {
+ uint64_t result;
+ result = ((uint64_t)a[i]) * ((uint64_t)b[j]);
+ W = result >> 32;
+ V = a[i] * b[j];
+ V = V + U;
+ U = (V < U);
+ U += W;
+ V = V + c[i + j];
+ U += (V < c[i + j]);
+ c[i + j] = V;
+ }
+ c[i + KEY_LENGTH_DWORDS_P256] = U;
+ }
+}
+
+void multiprecision_fast_mod_P256(uint32_t* c, const uint32_t* a, const uint32_t* modp) {
+ uint32_t A;
+ uint32_t B;
+ uint32_t C;
+ uint32_t D;
+ uint32_t E;
+ uint32_t F;
+ uint32_t G;
+ uint8_t UA;
+ uint8_t UB;
+ uint8_t UC;
+ uint8_t UD;
+ uint8_t UE;
+ uint8_t UF;
+ uint8_t UG;
+ uint32_t U;
+
+ // C = a[13] + a[14] + a[15];
+ C = a[13];
+ C += a[14];
+ UC = (C < a[14]);
+ C += a[15];
+ UC += (C < a[15]);
+
+ // E = a[8] + a[9];
+ E = a[8];
+ E += a[9];
+ UE = (E < a[9]);
+
+ // F = a[9] + a[10];
+ F = a[9];
+ F += a[10];
+ UF = (F < a[10]);
+
+ // G = a[10] + a[11]
+ G = a[10];
+ G += a[11];
+ UG = (G < a[11]);
+
+ // B = a[12] + a[13] + a[14] + a[15] == C + a[12]
+ B = C;
+ UB = UC;
+ B += a[12];
+ UB += (B < a[12]);
+
+ // A = a[11] + a[12] + a[13] + a[14] == B + a[11] - a[15]
+ A = B;
+ UA = UB;
+ A += a[11];
+ UA += (A < a[11]);
+ UA -= (A < a[15]);
+ A -= a[15];
+
+ // D = a[10] + a[11] + a[12] + a[13] == A + a[10] - a[14]
+ D = A;
+ UD = UA;
+ D += a[10];
+ UD += (D < a[10]);
+ UD -= (D < a[14]);
+ D -= a[14];
+
+ c[0] = a[0];
+ c[0] += E;
+ U = (c[0] < E);
+ U += UE;
+ U -= (c[0] < A);
+ U -= UA;
+ c[0] -= A;
+
+ if (U & 0x80000000) {
+ uint32_t UU;
+ UU = 0 - U;
+ U = (a[1] < UU);
+ c[1] = a[1] - UU;
+ } else {
+ c[1] = a[1] + U;
+ U = (c[1] < a[1]);
+ }
+
+ c[1] += F;
+ U += (c[1] < F);
+ U += UF;
+ U -= (c[1] < B);
+ U -= UB;
+ c[1] -= B;
+
+ if (U & 0x80000000) {
+ uint32_t UU;
+ UU = 0 - U;
+ U = (a[2] < UU);
+ c[2] = a[2] - UU;
+ } else {
+ c[2] = a[2] + U;
+ U = (c[2] < a[2]);
+ }
+
+ c[2] += G;
+ U += (c[2] < G);
+ U += UG;
+ U -= (c[2] < C);
+ U -= UC;
+ c[2] -= C;
+
+ if (U & 0x80000000) {
+ uint32_t UU;
+ UU = 0 - U;
+ U = (a[3] < UU);
+ c[3] = a[3] - UU;
+ } else {
+ c[3] = a[3] + U;
+ U = (c[3] < a[3]);
+ }
+
+ c[3] += A;
+ U += (c[3] < A);
+ U += UA;
+ c[3] += a[11];
+ U += (c[3] < a[11]);
+ c[3] += a[12];
+ U += (c[3] < a[12]);
+ U -= (c[3] < a[14]);
+ c[3] -= a[14];
+ U -= (c[3] < a[15]);
+ c[3] -= a[15];
+ U -= (c[3] < E);
+ U -= UE;
+ c[3] -= E;
+
+ if (U & 0x80000000) {
+ uint32_t UU;
+ UU = 0 - U;
+ U = (a[4] < UU);
+ c[4] = a[4] - UU;
+ } else {
+ c[4] = a[4] + U;
+ U = (c[4] < a[4]);
+ }
+
+ c[4] += B;
+ U += (c[4] < B);
+ U += UB;
+ U -= (c[4] < a[15]);
+ c[4] -= a[15];
+ c[4] += a[12];
+ U += (c[4] < a[12]);
+ c[4] += a[13];
+ U += (c[4] < a[13]);
+ U -= (c[4] < F);
+ U -= UF;
+ c[4] -= F;
+
+ if (U & 0x80000000) {
+ uint32_t UU;
+ UU = 0 - U;
+ U = (a[5] < UU);
+ c[5] = a[5] - UU;
+ } else {
+ c[5] = a[5] + U;
+ U = (c[5] < a[5]);
+ }
+
+ c[5] += C;
+ U += (c[5] < C);
+ U += UC;
+ c[5] += a[13];
+ U += (c[5] < a[13]);
+ c[5] += a[14];
+ U += (c[5] < a[14]);
+ U -= (c[5] < G);
+ U -= UG;
+ c[5] -= G;
+
+ if (U & 0x80000000) {
+ uint32_t UU;
+ UU = 0 - U;
+ U = (a[6] < UU);
+ c[6] = a[6] - UU;
+ } else {
+ c[6] = a[6] + U;
+ U = (c[6] < a[6]);
+ }
+
+ c[6] += C;
+ U += (c[6] < C);
+ U += UC;
+ c[6] += a[14];
+ U += (c[6] < a[14]);
+ c[6] += a[14];
+ U += (c[6] < a[14]);
+ c[6] += a[15];
+ U += (c[6] < a[15]);
+ U -= (c[6] < E);
+ U -= UE;
+ c[6] -= E;
+
+ if (U & 0x80000000) {
+ uint32_t UU;
+ UU = 0 - U;
+ U = (a[7] < UU);
+ c[7] = a[7] - UU;
+ } else {
+ c[7] = a[7] + U;
+ U = (c[7] < a[7]);
+ }
+
+ c[7] += a[15];
+ U += (c[7] < a[15]);
+ c[7] += a[15];
+ U += (c[7] < a[15]);
+ c[7] += a[15];
+ U += (c[7] < a[15]);
+ c[7] += a[8];
+ U += (c[7] < a[8]);
+ U -= (c[7] < D);
+ U -= UD;
+ c[7] -= D;
+
+ if (U & 0x80000000) {
+ while (U) {
+ multiprecision_add(c, c, modp);
+ U++;
+ }
+ } else if (U) {
+ while (U) {
+ multiprecision_sub(c, c, modp);
+ U--;
+ }
+ }
+
+ if (multiprecision_compare(c, modp) >= 0) multiprecision_sub(c, c, modp);
+}
+
+void multiprecision_inv_mod(uint32_t* aminus, uint32_t* u, const uint32_t* modp) {
+ uint32_t v[KEY_LENGTH_DWORDS_P256];
+ uint32_t A[KEY_LENGTH_DWORDS_P256 + 1];
+ uint32_t C[KEY_LENGTH_DWORDS_P256 + 1];
+
+ multiprecision_copy(v, modp);
+ multiprecision_init(A);
+ multiprecision_init(C);
+ A[0] = 1;
+
+ while (!multiprecision_iszero(u)) {
+ while (!(u[0] & 0x01)) // u is even
+ {
+ multiprecision_rshift(u, u);
+ if (!(A[0] & 0x01)) // A is even
+ multiprecision_rshift(A, A);
+ else {
+ A[KEY_LENGTH_DWORDS_P256] = multiprecision_add(A, A, modp); // A =A+p
+ multiprecision_rshift(A, A);
+ A[KEY_LENGTH_DWORDS_P256 - 1] |= (A[KEY_LENGTH_DWORDS_P256] << 31);
+ }
+ }
+
+ while (!(v[0] & 0x01)) // v is even
+ {
+ multiprecision_rshift(v, v);
+ if (!(C[0] & 0x01)) // C is even
+ {
+ multiprecision_rshift(C, C);
+ } else {
+ C[KEY_LENGTH_DWORDS_P256] = multiprecision_add(C, C, modp); // C =C+p
+ multiprecision_rshift(C, C);
+ C[KEY_LENGTH_DWORDS_P256 - 1] |= (C[KEY_LENGTH_DWORDS_P256] << 31);
+ }
+ }
+
+ if (multiprecision_compare(u, v) >= 0) {
+ multiprecision_sub(u, u, v);
+ multiprecision_sub_mod(A, A, C, modp);
+ } else {
+ multiprecision_sub(v, v, u);
+ multiprecision_sub_mod(C, C, A, modp);
+ }
+ }
+
+ if (multiprecision_compare(C, modp) >= 0)
+ multiprecision_sub(aminus, C, modp);
+ else
+ multiprecision_copy(aminus, C);
+}
+
+} // namespace ecc
+} // namespace security
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/security/ecc/multprecision.h b/gd/security/ecc/multprecision.h
new file mode 100644
index 0000000..ad149cd
--- /dev/null
+++ b/gd/security/ecc/multprecision.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ * Copyright 2006-2015 Broadcom Corporation
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * This file contains simple pairing algorithms
+ *
+ ******************************************************************************/
+#pragma once
+
+#include <cstdint>
+
+namespace bluetooth {
+namespace security {
+namespace ecc {
+
+#define KEY_LENGTH_DWORDS_P256 8
+/* Arithmetic Operations*/
+int multiprecision_compare(const uint32_t* a, const uint32_t* b);
+int multiprecision_iszero(const uint32_t* a);
+void multiprecision_init(uint32_t* c);
+void multiprecision_copy(uint32_t* c, const uint32_t* a);
+uint32_t multiprecision_dword_bits(uint32_t a);
+uint32_t multiprecision_most_signdwords(const uint32_t* a);
+uint32_t multiprecision_most_signbits(const uint32_t* a);
+void multiprecision_inv_mod(uint32_t* aminus, uint32_t* a, const uint32_t* modp);
+uint32_t multiprecision_add(uint32_t* c, const uint32_t* a, const uint32_t* b); // c=a+b
+void multiprecision_add_mod(uint32_t* c, const uint32_t* a, const uint32_t* b, const uint32_t* modp);
+uint32_t multiprecision_sub(uint32_t* c, const uint32_t* a, const uint32_t* b); // c=a-b
+void multiprecision_sub_mod(uint32_t* c, const uint32_t* a, const uint32_t* b, const uint32_t* modp);
+void multiprecision_rshift(uint32_t* c, const uint32_t* a); // c=a>>1, return carrier
+void multiprecision_lshift_mod(uint32_t* c, const uint32_t* a, const uint32_t* modp); // c=a<<b, return carrier
+uint32_t multiprecision_lshift(uint32_t* c, const uint32_t* a);
+void multiprecision_mult(uint32_t* c, const uint32_t* a, const uint32_t* b); // c=a*b
+void multiprecision_mersenns_mult_mod(uint32_t* c, const uint32_t* a, const uint32_t* b, const uint32_t* modp);
+void multiprecision_mersenns_squa_mod(uint32_t* c, const uint32_t* a, const uint32_t* modp);
+void multiprecision_fast_mod_P256(uint32_t* c, const uint32_t* a, const uint32_t* modp);
+
+} // namespace ecc
+} // namespace security
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/security/ecc/p_256_ecc_pp.cc b/gd/security/ecc/p_256_ecc_pp.cc
new file mode 100644
index 0000000..ecb805c
--- /dev/null
+++ b/gd/security/ecc/p_256_ecc_pp.cc
@@ -0,0 +1,264 @@
+/******************************************************************************
+ *
+ * Copyright 2006-2015 Broadcom Corporation
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * This file contains simple pairing algorithms using Elliptic Curve
+ * Cryptography for private public key
+ *
+ ******************************************************************************/
+#include "security/ecc/p_256_ecc_pp.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "security/ecc/multprecision.h"
+
+namespace bluetooth {
+namespace security {
+namespace ecc {
+
+const uint32_t* modp = curve_p256.p;
+
+static void p_256_init_point(Point* q) {
+ memset(q, 0, sizeof(Point));
+}
+
+static void p_256_copy_point(Point* q, const Point* p) {
+ memcpy(q, p, sizeof(Point));
+}
+
+// q=2q
+static void ECC_Double(Point* q, const Point* p) {
+ uint32_t t1[KEY_LENGTH_DWORDS_P256];
+ uint32_t t2[KEY_LENGTH_DWORDS_P256];
+ uint32_t t3[KEY_LENGTH_DWORDS_P256];
+ const uint32_t* x1;
+ uint32_t* x3;
+ const uint32_t* y1;
+ uint32_t* y3;
+ const uint32_t* z1;
+ uint32_t* z3;
+
+ if (multiprecision_iszero(p->z)) {
+ multiprecision_init(q->z);
+ return; // return infinity
+ }
+
+ x1 = p->x;
+ y1 = p->y;
+ z1 = p->z;
+ x3 = q->x;
+ y3 = q->y;
+ z3 = q->z;
+
+ multiprecision_mersenns_squa_mod(t1, z1, modp); // t1=z1^2
+ multiprecision_sub_mod(t2, x1, t1, modp); // t2=x1-t1
+ multiprecision_add_mod(t1, x1, t1, modp); // t1=x1+t1
+ multiprecision_mersenns_mult_mod(t2, t1, t2, modp); // t2=t2*t1
+ multiprecision_lshift_mod(t3, t2, modp);
+ multiprecision_add_mod(t2, t3, t2, modp); // t2=3t2
+
+ multiprecision_mersenns_mult_mod(z3, y1, z1, modp); // z3=y1*z1
+ multiprecision_lshift_mod(z3, z3, modp);
+
+ multiprecision_mersenns_squa_mod(y3, y1, modp); // y3=y1^2
+ multiprecision_lshift_mod(y3, y3, modp);
+ multiprecision_mersenns_mult_mod(t3, y3, x1, modp); // t3=y3*x1=x1*y1^2
+ multiprecision_lshift_mod(t3, t3, modp);
+ multiprecision_mersenns_squa_mod(y3, y3, modp); // y3=y3^2=y1^4
+ multiprecision_lshift_mod(y3, y3, modp);
+
+ multiprecision_mersenns_squa_mod(x3, t2, modp); // x3=t2^2
+ multiprecision_lshift_mod(t1, t3, modp); // t1=2t3
+ multiprecision_sub_mod(x3, x3, t1, modp); // x3=x3-t1
+ multiprecision_sub_mod(t1, t3, x3, modp); // t1=t3-x3
+ multiprecision_mersenns_mult_mod(t1, t1, t2, modp); // t1=t1*t2
+ multiprecision_sub_mod(y3, t1, y3, modp); // y3=t1-y3
+}
+
+// q=q+p, zp must be 1
+static void ECC_Add(Point* r, Point* p, const Point* q) {
+ uint32_t t1[KEY_LENGTH_DWORDS_P256];
+ uint32_t t2[KEY_LENGTH_DWORDS_P256];
+ uint32_t* x1;
+ const uint32_t* x2;
+ uint32_t* x3;
+ uint32_t* y1;
+ const uint32_t* y2;
+ uint32_t* y3;
+ uint32_t* z1;
+ const uint32_t* z2;
+ uint32_t* z3;
+
+ x1 = p->x;
+ y1 = p->y;
+ z1 = p->z;
+ x2 = q->x;
+ y2 = q->y;
+ z2 = q->z;
+ x3 = r->x;
+ y3 = r->y;
+ z3 = r->z;
+
+ // if Q=infinity, return p
+ if (multiprecision_iszero(z2)) {
+ p_256_copy_point(r, p);
+ return;
+ }
+
+ // if P=infinity, return q
+ if (multiprecision_iszero(z1)) {
+ p_256_copy_point(r, q);
+ return;
+ }
+
+ multiprecision_mersenns_squa_mod(t1, z1, modp); // t1=z1^2
+ multiprecision_mersenns_mult_mod(t2, z1, t1, modp); // t2=t1*z1
+ multiprecision_mersenns_mult_mod(t1, x2, t1, modp); // t1=t1*x2
+ multiprecision_mersenns_mult_mod(t2, y2, t2, modp); // t2=t2*y2
+
+ multiprecision_sub_mod(t1, t1, x1, modp); // t1=t1-x1
+ multiprecision_sub_mod(t2, t2, y1, modp); // t2=t2-y1
+
+ if (multiprecision_iszero(t1)) {
+ if (multiprecision_iszero(t2)) {
+ ECC_Double(r, q);
+ return;
+ } else {
+ multiprecision_init(z3);
+ return; // return infinity
+ }
+ }
+
+ multiprecision_mersenns_mult_mod(z3, z1, t1, modp); // z3=z1*t1
+ multiprecision_mersenns_squa_mod(y3, t1, modp); // t3=t1^2
+ multiprecision_mersenns_mult_mod(z1, y3, t1, modp); // t4=t3*t1
+ multiprecision_mersenns_mult_mod(y3, y3, x1, modp); // t3=t3*x1
+ multiprecision_lshift_mod(t1, y3, modp); // t1=2*t3
+ multiprecision_mersenns_squa_mod(x3, t2, modp); // x3=t2^2
+ multiprecision_sub_mod(x3, x3, t1, modp); // x3=x3-t1
+ multiprecision_sub_mod(x3, x3, z1, modp); // x3=x3-t4
+ multiprecision_sub_mod(y3, y3, x3, modp); // t3=t3-x3
+ multiprecision_mersenns_mult_mod(y3, y3, t2, modp); // t3=t3*t2
+ multiprecision_mersenns_mult_mod(z1, z1, y1, modp); // t4=t4*t1
+ multiprecision_sub_mod(y3, y3, z1, modp);
+}
+
+// Computing the Non-Adjacent Form of a positive integer
+static void ECC_NAF(uint8_t* naf, uint32_t* NumNAF, uint32_t* k) {
+ uint32_t sign;
+ int i = 0;
+ int j;
+ uint32_t var;
+
+ while ((var = multiprecision_most_signbits(k)) >= 1) {
+ if (k[0] & 0x01) // k is odd
+ {
+ sign = (k[0] & 0x03); // 1 or 3
+
+ // k = k-naf[i]
+ if (sign == 1)
+ k[0] = k[0] & 0xFFFFFFFE;
+ else {
+ k[0] = k[0] + 1;
+ if (k[0] == 0) // overflow
+ {
+ j = 1;
+ do {
+ k[j]++;
+ } while (k[j++] == 0); // overflow
+ }
+ }
+ } else
+ sign = 0;
+
+ multiprecision_rshift(k, k);
+ naf[i / 4] |= (sign) << ((i % 4) * 2);
+ i++;
+ }
+
+ *NumNAF = i;
+}
+
+// Binary Non-Adjacent Form for point multiplication
+void ECC_PointMult_Bin_NAF(Point* q, const Point* p, uint32_t* n) {
+ uint32_t sign;
+ uint8_t naf[256 / 4 + 1];
+ uint32_t NumNaf;
+ Point minus_p;
+ Point r;
+
+ p_256_init_point(&r);
+
+ // initialization
+ p_256_init_point(q);
+
+ // -p
+ multiprecision_copy(minus_p.x, p->x);
+ multiprecision_sub(minus_p.y, modp, p->y);
+
+ multiprecision_init(minus_p.z);
+ minus_p.z[0] = 1;
+
+ // NAF
+ memset(naf, 0, sizeof(naf));
+ ECC_NAF(naf, &NumNaf, n);
+
+ for (int i = NumNaf - 1; i >= 0; i--) {
+ p_256_copy_point(&r, q);
+ ECC_Double(q, &r);
+ sign = (naf[i / 4] >> ((i % 4) * 2)) & 0x03;
+
+ if (sign == 1) {
+ p_256_copy_point(&r, q);
+ ECC_Add(q, &r, p);
+ } else if (sign == 3) {
+ p_256_copy_point(&r, q);
+ ECC_Add(q, &r, &minus_p);
+ }
+ }
+
+ multiprecision_inv_mod(minus_p.x, q->z, modp);
+ multiprecision_mersenns_squa_mod(q->z, minus_p.x, modp);
+ multiprecision_mersenns_mult_mod(q->x, q->x, q->z, modp);
+ multiprecision_mersenns_mult_mod(q->z, q->z, minus_p.x, modp);
+ multiprecision_mersenns_mult_mod(q->y, q->y, q->z, modp);
+}
+
+bool ECC_ValidatePoint(const Point& pt) {
+ // Ensure y^2 = x^3 + a*x + b (mod p); a = -3
+
+ // y^2 mod p
+ uint32_t y2_mod[KEY_LENGTH_DWORDS_P256] = {0};
+ multiprecision_mersenns_squa_mod(y2_mod, (uint32_t*)pt.y, modp);
+
+ // Right hand side calculation
+ uint32_t rhs[KEY_LENGTH_DWORDS_P256] = {0};
+ multiprecision_mersenns_squa_mod(rhs, (uint32_t*)pt.x, modp);
+ uint32_t three[KEY_LENGTH_DWORDS_P256] = {0};
+ three[0] = 3;
+ multiprecision_sub_mod(rhs, rhs, three, modp);
+ multiprecision_mersenns_mult_mod(rhs, rhs, (uint32_t*)pt.x, modp);
+ multiprecision_add_mod(rhs, rhs, curve_p256.b, modp);
+
+ return multiprecision_compare(rhs, y2_mod) == 0;
+}
+
+} // namespace ecc
+} // namespace security
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/security/ecc/p_256_ecc_pp.h b/gd/security/ecc/p_256_ecc_pp.h
new file mode 100644
index 0000000..93af7ee
--- /dev/null
+++ b/gd/security/ecc/p_256_ecc_pp.h
@@ -0,0 +1,75 @@
+/******************************************************************************
+ *
+ * Copyright 2006-2015 Broadcom Corporation
+ *
+ * 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.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * This file contains simple pairing algorithms using Elliptic Curve
+ *Cryptography for private public key
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "security/ecc/multprecision.h"
+
+namespace bluetooth {
+namespace security {
+namespace ecc {
+
+struct Point {
+ uint32_t x[KEY_LENGTH_DWORDS_P256];
+ uint32_t y[KEY_LENGTH_DWORDS_P256];
+ uint32_t z[KEY_LENGTH_DWORDS_P256];
+};
+
+struct elliptic_curve_t {
+ // curve's coefficients
+ uint32_t a[KEY_LENGTH_DWORDS_P256];
+ uint32_t b[KEY_LENGTH_DWORDS_P256];
+
+ // prime modulus
+ uint32_t p[KEY_LENGTH_DWORDS_P256];
+
+ // Omega, p = 2^m -omega
+ uint32_t omega[KEY_LENGTH_DWORDS_P256];
+
+ // base point, a point on E of order r
+ Point G;
+};
+
+// P-256 elliptic curve, as per BT Spec 5.1 Vol 2, Part H 7.6
+static constexpr elliptic_curve_t curve_p256{
+ .a = {0},
+ .b = {0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0, 0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8},
+ .p = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x0, 0x0, 0x0, 0x00000001, 0xFFFFFFFF},
+ .omega = {0},
+
+ .G = {.x = {0xd898c296, 0xf4a13945, 0x2deb33a0, 0x77037d81, 0x63a440f2, 0xf8bce6e5, 0xe12c4247, 0x6b17d1f2},
+ .y = {0x37bf51f5, 0xcbb64068, 0x6b315ece, 0x2bce3357, 0x7c0f9e16, 0x8ee7eb4a, 0xfe1a7f9b, 0x4fe342e2}},
+};
+
+/* This function checks that point is on the elliptic curve*/
+bool ECC_ValidatePoint(const Point& point);
+
+void ECC_PointMult_Bin_NAF(Point* q, const Point* p, uint32_t* n);
+
+#define ECC_PointMult(q, p, n) ECC_PointMult_Bin_NAF(q, p, n)
+
+} // namespace ecc
+} // namespace security
+} // namespace bluetooth
diff --git a/gd/security/ecdh_keys.cc b/gd/security/ecdh_keys.cc
new file mode 100644
index 0000000..fa3d794
--- /dev/null
+++ b/gd/security/ecdh_keys.cc
@@ -0,0 +1,82 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "security/ecdh_keys.h"
+
+/**********************************************************************************************************************
+ TODO: We should have random number management in separate file, and we
+ should honour all the random number requirements from the spec!!
+**********************************************************************************************************************/
+#include <chrono>
+#include <cstdlib>
+
+#include "security/ecc/p_256_ecc_pp.h"
+
+namespace {
+template <size_t SIZE>
+static std::array<uint8_t, SIZE> GenerateRandom() {
+ // TODO: We need a proper random number generator here.
+ // use current time as seed for random generator
+ std::srand(std::time(nullptr));
+ std::array<uint8_t, SIZE> r;
+ for (size_t i = 0; i < SIZE; i++) r[i] = std::rand();
+ return r;
+}
+} // namespace
+/*********************************************************************************************************************/
+
+namespace bluetooth {
+namespace security {
+
+std::pair<std::array<uint8_t, 32>, EcdhPublicKey> GenerateECDHKeyPair() {
+ std::array<uint8_t, 32> private_key = GenerateRandom<32>();
+ ecc::Point public_key;
+
+ ECC_PointMult(&public_key, &(ecc::curve_p256.G), (uint32_t*)private_key.data());
+
+ EcdhPublicKey pk;
+ memcpy(pk.x.data(), public_key.x, 32);
+ memcpy(pk.y.data(), public_key.y, 32);
+
+ /* private_key, public key pair */
+ return std::make_pair<std::array<uint8_t, 32>, EcdhPublicKey>(std::move(private_key), std::move(pk));
+}
+
+bool ValidateECDHPoint(EcdhPublicKey pk) {
+ ecc::Point public_key;
+ memcpy(public_key.x, pk.x.data(), 32);
+ memcpy(public_key.y, pk.y.data(), 32);
+ memset(public_key.z, 0, 32);
+ return ECC_ValidatePoint(public_key);
+}
+
+std::array<uint8_t, 32> ComputeDHKey(std::array<uint8_t, 32> my_private_key, EcdhPublicKey remote_public_key) {
+ ecc::Point peer_publ_key, new_publ_key;
+ uint32_t private_key[8];
+ memcpy(private_key, my_private_key.data(), 32);
+ memcpy(peer_publ_key.x, remote_public_key.x.data(), 32);
+ memcpy(peer_publ_key.y, remote_public_key.y.data(), 32);
+ ECC_PointMult(&new_publ_key, &peer_publ_key, (uint32_t*)private_key);
+
+ std::array<uint8_t, 32> dhkey;
+ memcpy(dhkey.data(), new_publ_key.x, 32);
+ return dhkey;
+}
+
+} // namespace security
+} // namespace bluetooth
diff --git a/gd/security/ecdh_keys.h b/gd/security/ecdh_keys.h
new file mode 100644
index 0000000..8ec25a8
--- /dev/null
+++ b/gd/security/ecdh_keys.h
@@ -0,0 +1,40 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+#pragma once
+
+#include <array>
+
+namespace bluetooth {
+namespace security {
+
+struct EcdhPublicKey {
+ std::array<uint8_t, 32> x;
+ std::array<uint8_t, 32> y;
+};
+
+/* this generates private and public Eliptic Curve Diffie Helman keys */
+std::pair<std::array<uint8_t, 32>, EcdhPublicKey> GenerateECDHKeyPair();
+
+/* This function validates that the given public key (point) lays on the special
+ * Bluetooth curve */
+bool ValidateECDHPoint(EcdhPublicKey pk);
+
+std::array<uint8_t, 32> ComputeDHKey(std::array<uint8_t, 32> my_private_key, EcdhPublicKey remote_public_key);
+
+} // namespace security
+} // namespace bluetooth
diff --git a/gd/security/initial_informations.h b/gd/security/initial_informations.h
new file mode 100644
index 0000000..db560bd
--- /dev/null
+++ b/gd/security/initial_informations.h
@@ -0,0 +1,112 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <optional>
+
+#include "common/bidi_queue.h"
+#include "common/callback.h"
+#include "crypto_toolbox/crypto_toolbox.h"
+#include "hci/address_with_type.h"
+#include "hci/le_security_interface.h"
+#include "os/handler.h"
+#include "packet/base_packet_builder.h"
+#include "packet/packet_view.h"
+#include "security/pairing_failure.h"
+#include "security/smp_packets.h"
+#include "security/ui.h"
+
+namespace bluetooth {
+namespace security {
+
+using DistributedKeys =
+ std::tuple<std::optional<crypto_toolbox::Octet16> /* ltk */, std::optional<uint16_t> /*ediv*/,
+ std::optional<std::array<uint8_t, 8>> /* rand */, std::optional<Address> /* Identity address */,
+ AddrType, std::optional<crypto_toolbox::Octet16> /* IRK */,
+ std::optional<crypto_toolbox::Octet16>> /* Signature Key */;
+
+/* This class represents the result of pairing, as returned from Pairing Handler */
+struct PairingResult {
+ hci::AddressWithType connection_address;
+ DistributedKeys distributed_keys;
+};
+
+using PairingResultOrFailure = std::variant<PairingResult, PairingFailure>;
+
+/* Data we use for Out Of Band Pairing */
+struct MyOobData {
+ /* private key is just for this single pairing only, so it might be safe to
+ * expose it to other parts of stack. It should not be exposed to upper
+ * layers though */
+ std::array<uint8_t, 32> private_key;
+ EcdhPublicKey public_key;
+ crypto_toolbox::Octet16 c;
+ crypto_toolbox::Octet16 r;
+};
+
+/* This structure is filled and send to PairingHandlerLe to initiate the Pairing process with remote device */
+struct InitialInformations {
+ hci::Role my_role;
+ hci::AddressWithType my_connection_address;
+
+ /* My capabilities, as in pairing request/response */
+ struct {
+ IoCapability io_capability;
+ OobDataFlag oob_data_flag;
+ uint8_t auth_req;
+ uint8_t maximum_encryption_key_size;
+ uint8_t initiator_key_distribution;
+ uint8_t responder_key_distribution;
+ } myPairingCapabilities;
+
+ /* was it remote device that initiated the Pairing ? */
+ bool remotely_initiated;
+ uint16_t connection_handle;
+ hci::AddressWithType remote_connection_address;
+ std::string remote_name;
+
+ /* contains pairing request, if the pairing was remotely initiated */
+ std::optional<PairingRequestView> pairing_request;
+
+ struct out_of_band_data {
+ crypto_toolbox::Octet16 le_sc_c; /* LE Secure Connections Confirmation Value */
+ crypto_toolbox::Octet16 le_sc_r; /* LE Secure Connections Random Value */
+
+ crypto_toolbox::Octet16 security_manager_tk_value; /* OOB data for LE Legacy Pairing */
+ };
+
+ // If we received OOB data from remote device, this field contains it.
+ std::optional<out_of_band_data> remote_oob_data;
+ std::optional<MyOobData> my_oob_data;
+
+ /* Used by Pairing Handler to present user with requests*/
+ UI* ui_handler;
+
+ /* HCI interface to use */
+ hci::LeSecurityInterface* le_security_interface;
+
+ os::EnqueueBuffer<packet::BasePacketBuilder>* proper_l2cap_interface;
+ os::Handler* l2cap_handler;
+
+ /* Callback to execute once the Pairing process is finished */
+ std::function<void(PairingResultOrFailure)> OnPairingFinished;
+};
+
+} // namespace security
+} // namespace bluetooth
diff --git a/gd/security/internal/security_manager_impl.cc b/gd/security/internal/security_manager_impl.cc
new file mode 100644
index 0000000..b245ff9
--- /dev/null
+++ b/gd/security/internal/security_manager_impl.cc
@@ -0,0 +1,142 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "security_manager_impl.h"
+
+#include <iostream>
+#include <unordered_map>
+
+#include "os/log.h"
+#include "security/pairing/classic_pairing_handler.h"
+#include "security/security_manager.h"
+
+using namespace bluetooth::security::internal;
+using bluetooth::hci::Device;
+using bluetooth::hci::DeviceType;
+using bluetooth::security::ISecurityManagerListener;
+using bluetooth::security::pairing::PairingHandler;
+
+namespace {
+std::unordered_map<std::shared_ptr<Device>, std::unique_ptr<PairingHandler>> pairing_handler_map_;
+
+void dispatch_new_pairing_handler(std::shared_ptr<bluetooth::security::record::SecurityRecord> record) {
+ auto entry = pairing_handler_map_.find(record->GetDevice());
+ if (entry != pairing_handler_map_.end()) {
+ LOG_WARN("Device already has a pairing handler, and is in the middle of pairing!");
+ return;
+ }
+ std::unique_ptr<PairingHandler> pairing_handler = nullptr;
+ switch (record->GetDevice()->GetDeviceType()) {
+ case DeviceType::CLASSIC:
+ pairing_handler = std::make_unique<bluetooth::security::pairing::ClassicPairingHandler>(record);
+ break;
+ default:
+ ASSERT_LOG(false, "Pairing type %d not implemented!", record->GetDevice()->GetDeviceType());
+ }
+ auto new_entry = std::pair<std::shared_ptr<Device>, std::unique_ptr<PairingHandler>>(record->GetDevice(),
+ std::move(pairing_handler));
+ pairing_handler_map_.insert(std::move(new_entry));
+}
+} // namespace
+
+void SecurityManagerImpl::Init() {
+ // TODO(optedoblivion): Populate security record memory map from disk
+ // security_manager_channel_->SetChannelListener(this);
+}
+
+void SecurityManagerImpl::CreateBond(std::shared_ptr<hci::ClassicDevice> device) {
+ std::string uuid = device->GetUuid();
+ // Security record check
+ // if (device_database_->GetDeviceById(uuid) != nullptr) {
+ // LOG_WARN("Device already exists in the database");
+ // TODO(optedoblivion): Check security record if device is already bonded
+ // if no security record, need to initiate bonding
+ // if security record and not bonded, need to initiate bonding
+ // if security record and is bonded, then do nothing
+ // }
+
+ // device_database_->AddDevice(device);
+ // Create security record
+ // Pass to pairing handler
+ std::shared_ptr<record::SecurityRecord> record = std::make_shared<record::SecurityRecord>(device);
+ dispatch_new_pairing_handler(record);
+ // init the pairing handler
+ // Update bonded flag on security record
+ // Update bonded flag on device to BONDING (pairing handler does this)
+}
+
+void SecurityManagerImpl::CancelBond(std::shared_ptr<hci::ClassicDevice> device) {
+ auto entry = pairing_handler_map_.find(device);
+ if (entry != pairing_handler_map_.end()) {
+ pairing_handler_map_.erase(device);
+ }
+ // Remove from DB
+ // device_database_->RemoveDevice(device);
+ // Remove from map, no longer will the event queue use it
+ // If currently bonding, cancel pairing handler job
+ // else, cancel fails
+}
+
+void SecurityManagerImpl::RemoveBond(std::shared_ptr<hci::ClassicDevice> device) {
+ CancelBond(device);
+ // Update bonded flag on device to UNBONDED
+ // Signal disconnect
+ // Signal unbonding
+ // Remove security record
+ // Signal Remove from database
+}
+
+void SecurityManagerImpl::RegisterCallbackListener(ISecurityManagerListener* listener, os::Handler* handler) {
+ for (auto it = listeners_.begin(); it != listeners_.end(); ++it) {
+ if (it->first == listener) {
+ LOG_ALWAYS_FATAL("Listener has already been registered!");
+ }
+ }
+
+ listeners_.push_back({listener, handler});
+}
+
+void SecurityManagerImpl::UnregisterCallbackListener(ISecurityManagerListener* listener) {
+ for (auto it = listeners_.begin(); it != listeners_.end(); ++it) {
+ if (it->first == listener) {
+ listeners_.erase(it);
+ return;
+ }
+ }
+
+ LOG_ALWAYS_FATAL("Listener has not been registered!");
+}
+
+void SecurityManagerImpl::NotifyDeviceBonded(hci::AddressWithType device) {
+ for (auto& iter : listeners_) {
+ iter.second->Post(common::Bind(&ISecurityManagerListener::OnDeviceBonded, common::Unretained(iter.first), device));
+ }
+}
+
+void SecurityManagerImpl::NotifyDeviceBondFailed(hci::AddressWithType device) {
+ for (auto& iter : listeners_) {
+ iter.second->Post(
+ common::Bind(&ISecurityManagerListener::OnDeviceBondFailed, common::Unretained(iter.first), device));
+ }
+}
+
+void SecurityManagerImpl::NotifyDeviceUnbonded(hci::AddressWithType device) {
+ for (auto& iter : listeners_) {
+ iter.second->Post(
+ common::Bind(&ISecurityManagerListener::OnDeviceUnbonded, common::Unretained(iter.first), device));
+ }
+}
diff --git a/gd/security/internal/security_manager_impl.h b/gd/security/internal/security_manager_impl.h
new file mode 100644
index 0000000..d6768c9
--- /dev/null
+++ b/gd/security/internal/security_manager_impl.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "hci/classic_device.h"
+#include "l2cap/classic/l2cap_classic_module.h"
+#include "l2cap/le/l2cap_le_module.h"
+#include "os/handler.h"
+#include "security/channel/security_manager_channel.h"
+
+#include <utility>
+
+namespace bluetooth {
+namespace security {
+
+class ISecurityManagerListener;
+
+namespace internal {
+
+class SecurityManagerImpl /*: public channel::ISecurityManagerChannelListener*/ {
+ public:
+ explicit SecurityManagerImpl(os::Handler* security_handler, l2cap::le::L2capLeModule* l2cap_le_module,
+ l2cap::classic::L2capClassicModule* l2cap_classic_module,
+ channel::SecurityManagerChannel* security_manager_channel)
+ : security_handler_(security_handler), l2cap_le_module_(l2cap_le_module),
+ l2cap_classic_module_(l2cap_classic_module), security_manager_channel_(security_manager_channel) {}
+ virtual ~SecurityManagerImpl() = default;
+
+ // All APIs must be invoked in SM layer handler
+
+ /**
+ * Initialize the security record map from an internal device database.
+ */
+ void Init();
+
+ /**
+ * Checks the device for existing bond, if not bonded, initiates pairing.
+ *
+ * @param device pointer to device we want to bond with
+ * @return true if bonded or pairing started successfully, false if currently pairing
+ */
+ void CreateBond(std::shared_ptr<hci::ClassicDevice> device);
+
+ /* void CreateBond(std::shared_ptr<hci::LeDevice> device); */
+
+ /**
+ * Cancels the pairing process for this device.
+ *
+ * @param device pointer to device with which we want to cancel our bond
+ * @return <code>true</code> if successfully stopped
+ */
+ void CancelBond(std::shared_ptr<bluetooth::hci::ClassicDevice> device);
+
+ /* void CancelBond(std::shared_ptr<hci::LeDevice> device); */
+
+ /**
+ * Disassociates the device and removes the persistent LTK
+ *
+ * @param device pointer to device we want to forget
+ * @return true if removed
+ */
+ void RemoveBond(std::shared_ptr<bluetooth::hci::ClassicDevice> device);
+
+ /* void RemoveBond(std::shared_ptr<hci::LeDevice> device); */
+
+ /**
+ * Register to listen for callback events from SecurityManager
+ *
+ * @param listener ISecurityManagerListener instance to handle callbacks
+ */
+ void RegisterCallbackListener(ISecurityManagerListener* listener, os::Handler* handler);
+
+ /**
+ * Unregister listener for callback events from SecurityManager
+ *
+ * @param listener ISecurityManagerListener instance to unregister
+ */
+ void UnregisterCallbackListener(ISecurityManagerListener* listener);
+
+ protected:
+ std::vector<std::pair<ISecurityManagerListener*, os::Handler*>> listeners_;
+ void NotifyDeviceBonded(hci::AddressWithType device);
+ void NotifyDeviceBondFailed(hci::AddressWithType device);
+ void NotifyDeviceUnbonded(hci::AddressWithType device);
+
+ // ISecurityManagerChannel
+ void OnChangeConnectionLinkKeyComplete(std::shared_ptr<hci::Device> device,
+ hci::ChangeConnectionLinkKeyCompleteView packet);
+ void OnMasterLinkKeyComplete(std::shared_ptr<hci::Device> device, hci::MasterLinkKeyCompleteView packet);
+ void OnPinCodeRequest(std::shared_ptr<hci::Device> device, hci::PinCodeRequestView packet);
+ void OnLinkKeyRequest(std::shared_ptr<hci::Device> device, hci::LinkKeyRequestView packet);
+ void OnLinkKeyNotification(std::shared_ptr<hci::Device> device, hci::LinkKeyNotificationView packet);
+ void OnIoCapabilityRequest(std::shared_ptr<hci::Device> device, hci::IoCapabilityRequestView packet);
+ void OnIoCapabilityResponse(std::shared_ptr<hci::Device> device, hci::IoCapabilityResponseView packet);
+ void OnSimplePairingComplete(std::shared_ptr<hci::Device> device, hci::SimplePairingCompleteView packet);
+ void OnReturnLinkKeys(std::shared_ptr<hci::Device> device, hci::ReturnLinkKeysView packet);
+ void OnEncryptionChange(std::shared_ptr<hci::Device> device, hci::EncryptionChangeView packet);
+ void OnEncryptionKeyRefreshComplete(std::shared_ptr<hci::Device> device,
+ hci::EncryptionKeyRefreshCompleteView packet);
+ void OnRemoteOobDataRequest(std::shared_ptr<hci::Device> device, hci::RemoteOobDataRequestView packet);
+
+ private:
+ os::Handler* security_handler_ __attribute__((unused));
+ l2cap::le::L2capLeModule* l2cap_le_module_ __attribute__((unused));
+ l2cap::classic::L2capClassicModule* l2cap_classic_module_ __attribute__((unused));
+ channel::SecurityManagerChannel* security_manager_channel_ __attribute__((unused));
+};
+} // namespace internal
+} // namespace security
+} // namespace bluetooth
diff --git a/gd/security/pairing/classic_pairing_handler.h b/gd/security/pairing/classic_pairing_handler.h
new file mode 100644
index 0000000..fc8eed4
--- /dev/null
+++ b/gd/security/pairing/classic_pairing_handler.h
@@ -0,0 +1,42 @@
+/******************************************************************************
+ *
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License") override;
+ * 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.
+ *
+ ******************************************************************************/
+#pragma once
+
+#include "pairing_handler.h"
+
+#include "security/smp_packets.h"
+
+using namespace bluetooth::security::pairing;
+
+namespace bluetooth {
+namespace security {
+namespace pairing {
+
+class ClassicPairingHandler : public PairingHandler {
+ public:
+ explicit ClassicPairingHandler(std::shared_ptr<record::SecurityRecord> record) : PairingHandler(record) {}
+
+ void Init() {
+ // Set auth required
+ // Connect to device
+ }
+};
+
+} // namespace pairing
+} // namespace security
+} // namespace bluetooth
diff --git a/gd/security/pairing/pairing_handler.h b/gd/security/pairing/pairing_handler.h
new file mode 100644
index 0000000..61cad62
--- /dev/null
+++ b/gd/security/pairing/pairing_handler.h
@@ -0,0 +1,52 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include "hci/device.h"
+#include "security/channel/security_manager_channel.h"
+#include "security/record/security_record.h"
+#include "security/smp_packets.h"
+
+namespace bluetooth {
+namespace security {
+namespace pairing {
+
+/**
+ * Base structure for handling pairing events.
+ *
+ * <p>Extend this class in order to implement a new style of pairing.
+ */
+class PairingHandler {
+ public:
+ PairingHandler(std::shared_ptr<record::SecurityRecord> record) : record_(record){};
+ virtual ~PairingHandler() = default;
+
+ std::shared_ptr<record::SecurityRecord> GetRecord() {
+ return record_;
+ }
+
+ private:
+ std::shared_ptr<record::SecurityRecord> record_ __attribute__((unused));
+};
+
+} // namespace pairing
+} // namespace security
+} // namespace bluetooth
diff --git a/gd/security/pairing_failure.h b/gd/security/pairing_failure.h
new file mode 100644
index 0000000..f7bbbae
--- /dev/null
+++ b/gd/security/pairing_failure.h
@@ -0,0 +1,57 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <string>
+
+#include "security/smp_packets.h"
+
+namespace bluetooth {
+namespace security {
+
+/* This structure holds the information about the failure in case of airing failure */
+struct PairingFailure {
+ /* A place in code that triggered this failure. It can be modified by functions that pass the error to a location that
+ * better reflect the current state of flow. i.e. instead of generic location responsible for waiting for packet,
+ * replace it with location of receiving specific packet in a specific flow */
+ // base::Location location;
+
+ /* This is the failure message, that will be passed, either into upper layers,
+ * or to the metrics in future */
+ std::string message;
+
+ /* If failure is due to mismatch of received code, this contains the received opcode */
+ Code received_code_;
+
+ /* if the failure is due to "SMP failure", this field contains the reson code
+ */
+ PairingFailedReason reason;
+
+ PairingFailure(/*const base::Location& location, */ const std::string& message)
+ : /*location(location), */ message(message) {}
+
+ PairingFailure(/*const base::Location& location, */ const std::string& message, Code received_code)
+ : /*location(location), */ message(message), received_code_(received_code) {}
+
+ PairingFailure(/*const base::Location& location, */ const std::string& message, PairingFailedReason reason)
+ : /*location(location),*/ message(message), reason(reason) {}
+};
+
+} // namespace security
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/security/pairing_handler_le.cc b/gd/security/pairing_handler_le.cc
new file mode 100644
index 0000000..0484971
--- /dev/null
+++ b/gd/security/pairing_handler_le.cc
@@ -0,0 +1,391 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "security/pairing_handler_le.h"
+
+namespace bluetooth {
+namespace security {
+
+void PairingHandlerLe::PairingMain(InitialInformations i) {
+ LOG_INFO("Pairing Started");
+
+ if (i.remotely_initiated) {
+ LOG_INFO("Was remotely initiated, presenting user with the accept prompt");
+ i.ui_handler->DisplayPairingPrompt(i.remote_connection_address, i.remote_name);
+
+ // If pairing was initiated by remote device, wait for the user to accept
+ // the request from the UI.
+ LOG_INFO("Waiting for the prompt response");
+ std::optional<PairingEvent> pairingAccepted = WaitUiPairingAccept();
+ if (!pairingAccepted || pairingAccepted->ui_value == 0) {
+ LOG_INFO("User either did not accept the remote pairing, or the prompt timed out");
+ SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::UNSPECIFIED_REASON));
+ i.OnPairingFinished(PairingFailure("User either did not accept the remote pairing, or the prompt timed out"));
+ return;
+ }
+
+ LOG_INFO("Pairing prompt accepted");
+ }
+
+ /************************************************ PHASE 1 *********************************************************/
+ Phase1ResultOrFailure phase_1_result = ExchangePairingFeature(i);
+ if (std::holds_alternative<PairingFailure>(phase_1_result)) {
+ LOG_WARN("Pairing failed in phase 1");
+ // We already send pairing fialed in lower layer. Which one should do that ? how about disconneciton?
+ // SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::UNSPECIFIED_REASON));
+ // TODO: disconnect?
+ i.OnPairingFinished(std::get<PairingFailure>(phase_1_result));
+ return;
+ }
+
+ auto [pairing_request, pairing_response] = std::get<Phase1Result>(phase_1_result);
+
+ /************************************************ PHASE 2 *********************************************************/
+ if (pairing_request.GetAuthReq() & pairing_response.GetAuthReq() & AuthReqMaskSc) {
+ // 2.3.5.6 LE Secure Connections pairing phase 2
+ LOG_INFO("Pairing Phase 2 LE Secure connections Started");
+
+ /*
+ TODO: what to do with this piece of spec ?
+ If Secure Connections pairing has been initiated over BR/EDR, the
+ following fields of the SM Pairing Request PDU are reserved for future use:
+ • the IO Capability field,
+ • the OOB data flag field, and
+ • all bits in the Auth Req field except the CT2 bit.
+ */
+
+ OobDataFlag remote_have_oob_data =
+ IAmMaster(i) ? pairing_response.GetOobDataFlag() : pairing_request.GetOobDataFlag();
+
+ auto key_exchange_result = ExchangePublicKeys(i, remote_have_oob_data);
+ if (std::holds_alternative<PairingFailure>(key_exchange_result)) {
+ LOG_ERROR("Public key exchange failed");
+ i.OnPairingFinished(std::get<PairingFailure>(key_exchange_result));
+ return;
+ }
+ auto [PKa, PKb, dhkey] = std::get<KeyExchangeResult>(key_exchange_result);
+
+ // Public key exchange finished, Diffie-Hellman key computed.
+
+ Stage1ResultOrFailure stage1result = DoSecureConnectionsStage1(i, PKa, PKb, pairing_request, pairing_response);
+ if (std::holds_alternative<PairingFailure>(stage1result)) {
+ i.OnPairingFinished(std::get<PairingFailure>(stage1result));
+ return;
+ }
+
+ Stage2ResultOrFailure stage_2_result = DoSecureConnectionsStage2(i, PKa, PKb, pairing_request, pairing_response,
+ std::get<Stage1Result>(stage1result), dhkey);
+ if (std::holds_alternative<PairingFailure>(stage_2_result)) {
+ i.OnPairingFinished(std::get<PairingFailure>(stage_2_result));
+ return;
+ }
+
+ Octet16 ltk = std::get<Octet16>(stage_2_result);
+ if (IAmMaster(i)) {
+ SendHciLeStartEncryption(i, i.connection_handle, {0}, {0}, ltk);
+ }
+
+ } else {
+ // 2.3.5.5 LE legacy pairing phase 2
+ LOG_INFO("Pairing Phase 2 LE legacy pairing Started");
+
+ LegacyStage1ResultOrFailure stage1result = DoLegacyStage1(i, pairing_request, pairing_response);
+ if (std::holds_alternative<PairingFailure>(stage1result)) {
+ LOG_ERROR("Phase 1 failed");
+ i.OnPairingFinished(std::get<PairingFailure>(stage1result));
+ return;
+ }
+
+ Octet16 tk = std::get<Octet16>(stage1result);
+ StkOrFailure stage2result = DoLegacyStage2(i, pairing_request, pairing_response, tk);
+ if (std::holds_alternative<PairingFailure>(stage2result)) {
+ LOG_ERROR("stage 2 failed");
+ i.OnPairingFinished(std::get<PairingFailure>(stage2result));
+ return;
+ }
+
+ Octet16 stk = std::get<Octet16>(stage2result);
+ if (IAmMaster(i)) {
+ SendHciLeStartEncryption(i, i.connection_handle, {0}, {0}, stk);
+ }
+ }
+
+ /************************************************ PHASE 3 *********************************************************/
+ auto encryption_change_result = WaitEncryptionChanged();
+ if (std::holds_alternative<PairingFailure>(encryption_change_result)) {
+ LOG_ERROR("encryption change failed");
+ i.OnPairingFinished(std::get<PairingFailure>(encryption_change_result));
+ return;
+ } else if (std::holds_alternative<EncryptionChangeView>(encryption_change_result)) {
+ EncryptionChangeView encryption_changed = std::get<EncryptionChangeView>(encryption_change_result);
+ if (encryption_changed.GetStatus() != hci::ErrorCode::SUCCESS ||
+ encryption_changed.GetEncryptionEnabled() != hci::EncryptionEnabled::ON) {
+ i.OnPairingFinished(PairingFailure("Encryption change failed"));
+ }
+ } else if (std::holds_alternative<EncryptionKeyRefreshCompleteView>(encryption_change_result)) {
+ EncryptionKeyRefreshCompleteView encryption_changed =
+ std::get<EncryptionKeyRefreshCompleteView>(encryption_change_result);
+ if (encryption_changed.GetStatus() != hci::ErrorCode::SUCCESS) {
+ i.OnPairingFinished(PairingFailure("Encryption key refresh failed"));
+ }
+ } else {
+ i.OnPairingFinished(PairingFailure("Unknown case of encryption change result"));
+ }
+
+ DistributedKeysOrFailure keyExchangeStatus = DistributeKeys(i, pairing_response);
+ if (std::holds_alternative<PairingFailure>(keyExchangeStatus)) {
+ i.OnPairingFinished(std::get<PairingFailure>(keyExchangeStatus));
+ LOG_ERROR("Key exchange failed");
+ return;
+ }
+
+ i.OnPairingFinished(PairingResult{
+ .connection_address = i.remote_connection_address,
+ .distributed_keys = std::get<DistributedKeys>(keyExchangeStatus),
+ });
+}
+
+Phase1ResultOrFailure PairingHandlerLe::ExchangePairingFeature(const InitialInformations& i) {
+ LOG_INFO("Phase 1 start");
+
+ if (IAmMaster(i)) {
+ // Send Pairing Request
+ const auto& x = i.myPairingCapabilities;
+ auto pairing_request_builder =
+ PairingRequestBuilder::Create(x.io_capability, x.oob_data_flag, x.auth_req, x.maximum_encryption_key_size,
+ x.initiator_key_distribution, x.responder_key_distribution);
+ // basically pairing_request = myPairingCapabilities;
+
+ // Convert builder to view
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ pairing_request_builder->Serialize(it);
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto temp_cmd_view = CommandView::Create(packet_bytes_view);
+ auto pairing_request = PairingRequestView::Create(temp_cmd_view);
+ ASSERT(pairing_request.IsValid());
+
+ LOG_INFO("Sending Pairing Request");
+ SendL2capPacket(i, std::move(pairing_request_builder));
+
+ LOG_INFO("Waiting for Pairing Response");
+ auto response = WaitPairingResponse();
+
+ /* There is a potential collision where the slave initiates the pairing at the same time we initiate it, by sending
+ * security request. */
+ if (std::holds_alternative<PairingFailure>(response) &&
+ std::get<PairingFailure>(response).received_code_ == Code::SECURITY_REQUEST) {
+ LOG_INFO("Received security request, waiting for Pairing Response again...");
+ response = WaitPairingResponse();
+ }
+
+ if (std::holds_alternative<PairingFailure>(response)) {
+ // TODO: should the failure reason be different in some cases ? How about
+ // when we lost connection ? Don't send anything at all, or have L2CAP
+ // layer ignore it?
+ SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::UNSPECIFIED_REASON));
+ return std::get<PairingFailure>(response);
+ }
+
+ auto pairing_response = std::get<PairingResponseView>(response);
+
+ LOG_INFO("Phase 1 finish");
+ return Phase1Result{pairing_request, pairing_response};
+ } else {
+ std::optional<PairingRequestView> pairing_request;
+
+ if (i.remotely_initiated) {
+ if (!i.pairing_request.has_value()) {
+ return PairingFailure("You must pass PairingRequest as a initial information to slave!");
+ }
+
+ pairing_request = i.pairing_request.value();
+
+ if (!pairing_request->IsValid()) return PairingFailure("Malformed PairingRequest");
+ } else {
+ SendL2capPacket(i, SecurityRequestBuilder::Create(i.myPairingCapabilities.auth_req));
+
+ LOG_INFO("Waiting for Pairing Request");
+ auto request = WaitPairingRequest();
+ if (std::holds_alternative<PairingFailure>(request)) {
+ LOG_INFO("%s", std::get<PairingFailure>(request).message.c_str());
+ SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::UNSPECIFIED_REASON));
+ return std::get<PairingFailure>(request);
+ }
+
+ pairing_request = std::get<PairingRequestView>(request);
+ }
+
+ // Send Pairing Request
+ const auto& x = i.myPairingCapabilities;
+ // basically pairing_response_builder = my_first_packet;
+ // We are not allowed to enable bits that the remote did not allow us to set in initiator_key_dist and
+ // responder_key_distribution
+ auto pairing_response_builder =
+ PairingResponseBuilder::Create(x.io_capability, x.oob_data_flag, x.auth_req, x.maximum_encryption_key_size,
+ x.initiator_key_distribution & pairing_request->GetInitiatorKeyDistribution(),
+ x.responder_key_distribution & pairing_request->GetResponderKeyDistribution());
+
+ // Convert builder to view
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ pairing_response_builder->Serialize(it);
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto temp_cmd_view = CommandView::Create(packet_bytes_view);
+ auto pairing_response = PairingResponseView::Create(temp_cmd_view);
+ ASSERT(pairing_response.IsValid());
+
+ LOG_INFO("Sending Pairing Response");
+ SendL2capPacket(i, std::move(pairing_response_builder));
+
+ LOG_INFO("Phase 1 finish");
+ return Phase1Result{pairing_request.value(), pairing_response};
+ }
+}
+
+DistributedKeysOrFailure PairingHandlerLe::DistributeKeys(const InitialInformations& i,
+ const PairingResponseView& pairing_response) {
+ LOG_INFO("Key distribution start");
+
+ const uint8_t& keys_i_receive =
+ IAmMaster(i) ? pairing_response.GetResponderKeyDistribution() : pairing_response.GetInitiatorKeyDistribution();
+ const uint8_t& keys_i_send =
+ IAmMaster(i) ? pairing_response.GetInitiatorKeyDistribution() : pairing_response.GetResponderKeyDistribution();
+
+ // TODO: obtain actual values!
+
+ Octet16 my_ltk = {0};
+ uint16_t my_ediv{0};
+ std::array<uint8_t, 8> my_rand = {0};
+
+ Octet16 my_irk = {0x01};
+ Address my_identity_address;
+ AddrType my_identity_address_type = AddrType::PUBLIC;
+ Octet16 my_signature_key{0};
+
+ if (IAmMaster(i)) {
+ // EncKey is unused for LE Secure Connections
+ DistributedKeysOrFailure keys = ReceiveKeys(keys_i_receive);
+ if (std::holds_alternative<PairingFailure>(keys)) {
+ return keys;
+ }
+
+ SendKeys(i, keys_i_send, my_ltk, my_ediv, my_rand, my_irk, my_identity_address, my_identity_address_type,
+ my_signature_key);
+ LOG_INFO("Key distribution finish");
+ return keys;
+ } else {
+ SendKeys(i, keys_i_send, my_ltk, my_ediv, my_rand, my_irk, my_identity_address, my_identity_address_type,
+ my_signature_key);
+
+ DistributedKeysOrFailure keys = ReceiveKeys(keys_i_receive);
+ if (std::holds_alternative<PairingFailure>(keys)) {
+ return keys;
+ }
+ LOG_INFO("Key distribution finish");
+ return keys;
+ }
+}
+
+DistributedKeysOrFailure PairingHandlerLe::ReceiveKeys(const uint8_t& keys_i_receive) {
+ std::optional<Octet16> ltk; /* Legacy only */
+ std::optional<uint16_t> ediv; /* Legacy only */
+ std::optional<std::array<uint8_t, 8>> rand; /* Legacy only */
+ std::optional<Address> identity_address;
+ AddrType identity_address_type;
+ std::optional<Octet16> irk;
+ std::optional<Octet16> signature_key;
+
+ if (keys_i_receive & KeyMaskEnc) {
+ {
+ auto packet = WaitEncryptionInformation();
+ if (std::holds_alternative<PairingFailure>(packet)) {
+ LOG_ERROR(" Was expecting Encryption Information but did not receive!");
+ return std::get<PairingFailure>(packet);
+ }
+ ltk = std::get<EncryptionInformationView>(packet).GetLongTermKey();
+ }
+
+ {
+ auto packet = WaitMasterIdentification();
+ if (std::holds_alternative<PairingFailure>(packet)) {
+ LOG_ERROR(" Was expecting Master Identification but did not receive!");
+ return std::get<PairingFailure>(packet);
+ }
+ ediv = std::get<MasterIdentificationView>(packet).GetEdiv();
+ rand = std::get<MasterIdentificationView>(packet).GetRand();
+ }
+ }
+
+ if (keys_i_receive & KeyMaskId) {
+ auto packet = WaitIdentityInformation();
+ if (std::holds_alternative<PairingFailure>(packet)) {
+ LOG_ERROR(" Was expecting Identity Information but did not receive!");
+ return std::get<PairingFailure>(packet);
+ }
+
+ LOG_INFO("Received Identity Information");
+ irk = std::get<IdentityInformationView>(packet).GetIdentityResolvingKey();
+
+ auto iapacket = WaitIdentityAddressInformation();
+ if (std::holds_alternative<PairingFailure>(iapacket)) {
+ LOG_ERROR(
+ "Was expecting Identity Address Information but did "
+ "not receive!");
+ return std::get<PairingFailure>(iapacket);
+ }
+ LOG_INFO("Received Identity Address Information");
+ identity_address = std::get<IdentityAddressInformationView>(iapacket).GetBdAddr();
+ identity_address_type = std::get<IdentityAddressInformationView>(iapacket).GetAddrType();
+ }
+
+ if (keys_i_receive & KeyMaskSign) {
+ auto packet = WaitSigningInformation();
+ if (std::holds_alternative<PairingFailure>(packet)) {
+ LOG_ERROR(" Was expecting Signing Information but did not receive!");
+ return std::get<PairingFailure>(packet);
+ }
+
+ LOG_INFO("Received Signing Information");
+ signature_key = std::get<SigningInformationView>(packet).GetSignatureKey();
+ }
+
+ return DistributedKeys{ltk, ediv, rand, identity_address, identity_address_type, irk, signature_key};
+}
+
+void PairingHandlerLe::SendKeys(const InitialInformations& i, const uint8_t& keys_i_send, Octet16 ltk, uint16_t ediv,
+ std::array<uint8_t, 8> rand, Octet16 irk, Address identity_address,
+ AddrType identity_addres_type, Octet16 signature_key) {
+ if (keys_i_send & KeyMaskEnc) {
+ SendL2capPacket(i, EncryptionInformationBuilder::Create(ltk));
+ SendL2capPacket(i, MasterIdentificationBuilder::Create(ediv, rand));
+ }
+
+ if (keys_i_send & KeyMaskId) {
+ SendL2capPacket(i, IdentityInformationBuilder::Create(irk));
+
+ SendL2capPacket(i, IdentityAddressInformationBuilder::Create(identity_addres_type, identity_address));
+ }
+
+ if (keys_i_send & KeyMaskSign) {
+ SendL2capPacket(i, SigningInformationBuilder::Create(signature_key));
+ }
+}
+
+} // namespace security
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/security/pairing_handler_le.h b/gd/security/pairing_handler_le.h
new file mode 100644
index 0000000..4c7fc0c
--- /dev/null
+++ b/gd/security/pairing_handler_le.h
@@ -0,0 +1,493 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <array>
+#include <chrono>
+#include <condition_variable>
+#include <mutex>
+#include <optional>
+#include <queue>
+#include <thread>
+#include <variant>
+
+#include "common/bind.h"
+#include "crypto_toolbox/crypto_toolbox.h"
+#include "hci/hci_packets.h"
+#include "hci/le_security_interface.h"
+#include "packet/packet_view.h"
+#include "security/ecdh_keys.h"
+#include "security/initial_informations.h"
+#include "security/pairing_failure.h"
+#include "security/smp_packets.h"
+#include "security/ui.h"
+
+// Code generated by PDL does not allow us ot do || and && operations on bits
+// efficiently. Use those masks on fields requiring them until this is solved
+constexpr uint8_t AuthReqMaskBondingFlag = 0x01;
+constexpr uint8_t AuthReqMaskMitm = 0x02;
+constexpr uint8_t AuthReqMaskSc = 0x04;
+constexpr uint8_t AuthReqMaskKeypress = 0x08;
+constexpr uint8_t AuthReqMaskCt2 = 0x10;
+
+constexpr uint8_t KeyMaskEnc = 0x01;
+constexpr uint8_t KeyMaskId = 0x02;
+constexpr uint8_t KeyMaskSign = 0x04;
+constexpr uint8_t KeyMaskLink = 0x08;
+
+using bluetooth::hci::EncryptionChangeView;
+using bluetooth::hci::EncryptionKeyRefreshCompleteView;
+
+namespace bluetooth {
+namespace security {
+
+using crypto_toolbox::Octet16;
+
+/* This class represents an event send from other subsystems into SMP Pairing Handler,
+ * i.e. user request from the UI, L2CAP or HCI interaction */
+class PairingEvent {
+ public:
+ enum TYPE { EXIT, L2CAP, HCI_EVENT, UI };
+ TYPE type;
+
+ std::optional<CommandView> l2cap_packet;
+
+ std::optional<hci::EventPacketView> hci_event;
+
+ enum UI_ACTION_TYPE { PAIRING_ACCEPTED, CONFIRM_YESNO, PASSKEY };
+ UI_ACTION_TYPE ui_action;
+ uint32_t ui_value;
+
+ PairingEvent(TYPE type) : type(type) {}
+ PairingEvent(CommandView l2cap_packet) : type(L2CAP), l2cap_packet(l2cap_packet) {}
+ PairingEvent(UI_ACTION_TYPE ui_action, uint32_t ui_value) : type(UI), ui_action(ui_action), ui_value(ui_value) {}
+ PairingEvent(hci::EventPacketView hci_event) : type(HCI_EVENT), hci_event(hci_event) {}
+};
+
+constexpr int SMP_TIMEOUT = 30;
+
+using CommandViewOrFailure = std::variant<CommandView, PairingFailure>;
+using Phase1Result = std::pair<PairingRequestView /* pairning_request*/, PairingResponseView /* pairing_response */>;
+using Phase1ResultOrFailure = std::variant<PairingFailure, Phase1Result>;
+using KeyExchangeResult =
+ std::tuple<EcdhPublicKey /* PKa */, EcdhPublicKey /* PKb */, std::array<uint8_t, 32> /*dhkey*/>;
+using Stage1Result = std::tuple<Octet16, Octet16, Octet16, Octet16>;
+using Stage1ResultOrFailure = std::variant<PairingFailure, Stage1Result>;
+using Stage2ResultOrFailure = std::variant<PairingFailure, Octet16 /* LTK */>;
+using DistributedKeysOrFailure = std::variant<PairingFailure, DistributedKeys, std::monostate>;
+
+using LegacyStage1Result = Octet16 /*TK*/;
+using LegacyStage1ResultOrFailure = std::variant<PairingFailure, LegacyStage1Result>;
+using StkOrFailure = std::variant<PairingFailure, Octet16 /* STK */>;
+
+/* PairingHandlerLe takes care of the Pairing process. Pairing is strictly defined
+ * exchange of messages and UI interactions, divided into PHASES.
+ *
+ * Each PairingHandlerLe have a thread executing |PairingMain| method. Thread is
+ * blocked when waiting for UI/L2CAP/HCI interactions, and moves through all the
+ * phases.
+ */
+class PairingHandlerLe {
+ public:
+ // This is the phase of pairing as defined in BT Spec (with exception of
+ // accept prompt)
+ // * ACCEPT_PROMPT - we're waiting for the user to accept remotely initiated pairing
+ // * PHASE1 - feature exchange
+ // * PHASE2 - authentication
+ // * PHASE3 - key exchange
+ enum PAIRING_PHASE { ACCEPT_PROMPT, PHASE1, PHASE2, PHASE3 };
+ PAIRING_PHASE phase;
+
+ // All the knowledge to initiate the pairing process must be passed into this function
+ PairingHandlerLe(PAIRING_PHASE phase, InitialInformations informations)
+ : phase(phase), queue_guard(), thread_(&PairingHandlerLe::PairingMain, this, informations) {}
+
+ ~PairingHandlerLe() {
+ SendExitSignal();
+ // we need ot check if thread is joinable, because tests call join form
+ // within WaitUntilPairingFinished
+ if (thread_.joinable()) thread_.join();
+ }
+
+ void PairingMain(InitialInformations i);
+
+ Phase1ResultOrFailure ExchangePairingFeature(const InitialInformations& i);
+
+ void SendL2capPacket(const InitialInformations& i, std::unique_ptr<bluetooth::security::CommandBuilder> command) {
+ i.proper_l2cap_interface->Enqueue(std::move(command), i.l2cap_handler);
+ }
+
+ void SendHciLeStartEncryption(const InitialInformations& i, uint16_t conn_handle, const std::array<uint8_t, 8>& rand,
+ const uint16_t& ediv, const Octet16& ltk) {
+ i.le_security_interface->EnqueueCommand(hci::LeStartEncryptionBuilder::Create(conn_handle, rand, ediv, ltk),
+ common::BindOnce([](hci::CommandStatusView) {
+ // TODO: handle command status. It's important - can show we are not
+ // connected any more.
+ }),
+ nullptr);
+ }
+
+ std::variant<PairingFailure, EncryptionChangeView, EncryptionKeyRefreshCompleteView> WaitEncryptionChanged() {
+ PairingEvent e = WaitForEvent();
+ if (e.type != PairingEvent::HCI_EVENT) return PairingFailure("Was expecting HCI event but received something else");
+
+ if (!e.hci_event->IsValid()) return PairingFailure("Received invalid HCI event");
+
+ if (e.hci_event->GetEventCode() == hci::EventCode::ENCRYPTION_CHANGE) {
+ EncryptionChangeView enc_chg_packet = EncryptionChangeView::Create(*e.hci_event);
+ if (!enc_chg_packet.IsValid()) {
+ return PairingFailure("Invalid EncryptionChange packet received");
+ }
+ return enc_chg_packet;
+ }
+
+ if (e.hci_event->GetEventCode() == hci::EventCode::ENCRYPTION_KEY_REFRESH_COMPLETE) {
+ hci::EncryptionKeyRefreshCompleteView enc_packet = EncryptionKeyRefreshCompleteView::Create(*e.hci_event);
+ if (!enc_packet.IsValid()) {
+ return PairingFailure("Invalid EncryptionChange packet received");
+ }
+ return enc_packet;
+ }
+
+ return PairingFailure("Was expecting Encryption Change or Key Refresh Complete but received something else");
+ }
+
+ inline bool IAmMaster(const InitialInformations& i) {
+ return i.my_role == hci::Role::MASTER;
+ }
+
+ /* This function generates data that should be passed to remote device, except
+ the private key. */
+ static MyOobData GenerateOobData() {
+ MyOobData data;
+ std::tie(data.private_key, data.public_key) = GenerateECDHKeyPair();
+
+ data.r = GenerateRandom<16>();
+ data.c = crypto_toolbox::f4(data.public_key.x.data(), data.public_key.x.data(), data.r, 0);
+ return data;
+ }
+
+ std::variant<PairingFailure, KeyExchangeResult> ExchangePublicKeys(const InitialInformations& i,
+ OobDataFlag remote_have_oob_data);
+
+ Stage1ResultOrFailure DoSecureConnectionsStage1(const InitialInformations& i, const EcdhPublicKey& PKa,
+ const EcdhPublicKey& PKb, const PairingRequestView& pairing_request,
+ const PairingResponseView& pairing_response);
+
+ Stage1ResultOrFailure SecureConnectionsNumericComparison(const InitialInformations& i, const EcdhPublicKey& PKa,
+ const EcdhPublicKey& PKb);
+
+ Stage1ResultOrFailure SecureConnectionsJustWorks(const InitialInformations& i, const EcdhPublicKey& PKa,
+ const EcdhPublicKey& PKb);
+
+ Stage1ResultOrFailure SecureConnectionsPasskeyEntry(const InitialInformations& i, const EcdhPublicKey& PKa,
+ const EcdhPublicKey& PKb, IoCapability my_iocaps,
+ IoCapability remote_iocaps);
+
+ Stage1ResultOrFailure SecureConnectionsOutOfBand(const InitialInformations& i, const EcdhPublicKey& Pka,
+ const EcdhPublicKey& Pkb, OobDataFlag my_oob_flag,
+ OobDataFlag remote_oob_flag);
+
+ Stage2ResultOrFailure DoSecureConnectionsStage2(const InitialInformations& i, const EcdhPublicKey& PKa,
+ const EcdhPublicKey& PKb, const PairingRequestView& pairing_request,
+ const PairingResponseView& pairing_response,
+ const Stage1Result stage1result,
+ const std::array<uint8_t, 32>& dhkey);
+
+ DistributedKeysOrFailure DistributeKeys(const InitialInformations& i, const PairingResponseView& pairing_response);
+
+ DistributedKeysOrFailure ReceiveKeys(const uint8_t& keys_i_receive);
+
+ LegacyStage1ResultOrFailure DoLegacyStage1(const InitialInformations& i, const PairingRequestView& pairing_request,
+ const PairingResponseView& pairing_response);
+ LegacyStage1ResultOrFailure LegacyOutOfBand(const InitialInformations& i);
+ LegacyStage1ResultOrFailure LegacyJustWorks();
+ LegacyStage1ResultOrFailure LegacyPasskeyEntry(const InitialInformations& i, const IoCapability& my_iocaps,
+ const IoCapability& remote_iocaps);
+ StkOrFailure DoLegacyStage2(const InitialInformations& i, const PairingRequestView& pairing_request,
+ const PairingResponseView& pairing_response, const Octet16& tk);
+
+ void SendKeys(const InitialInformations& i, const uint8_t& keys_i_send, Octet16 ltk, uint16_t ediv,
+ std::array<uint8_t, 8> rand, Octet16 irk, Address identity_address, AddrType identity_addres_type,
+ Octet16 signature_key);
+
+ /* This can be called from any thread to immediately finish the pairing in progress. */
+ void SendExitSignal() {
+ {
+ std::unique_lock<std::mutex> lock(queue_guard);
+ queue.push(PairingEvent(PairingEvent::EXIT));
+ }
+ pairing_thread_blocker_.notify_one();
+ }
+
+ /* SMP Command received from remote device */
+ void OnCommandView(CommandView packet) {
+ {
+ std::unique_lock<std::mutex> lock(queue_guard);
+ queue.push(PairingEvent(std::move(packet)));
+ }
+ pairing_thread_blocker_.notify_one();
+ }
+
+ /* SMP Command received from remote device */
+ void OnHciEvent(hci::EventPacketView hci_event) {
+ {
+ std::unique_lock<std::mutex> lock(queue_guard);
+ queue.push(PairingEvent(std::move(hci_event)));
+ }
+ pairing_thread_blocker_.notify_one();
+ }
+
+ /* Interaction from user */
+ void OnUiAction(PairingEvent::UI_ACTION_TYPE ui_action, uint32_t ui_value) {
+ {
+ std::unique_lock<std::mutex> lock(queue_guard);
+ queue.push(PairingEvent(ui_action, ui_value));
+ }
+ pairing_thread_blocker_.notify_one();
+ }
+
+ /* Blocks the pairing process until some external interaction, or timeout happens */
+ PairingEvent WaitForEvent() {
+ std::unique_lock<std::mutex> lock(queue_guard);
+ do {
+ if (!queue.empty()) {
+ PairingEvent e = queue.front();
+ queue.pop();
+ return e;
+ }
+ // This releases the lock while blocking.
+ if (pairing_thread_blocker_.wait_for(lock, std::chrono::seconds(SMP_TIMEOUT)) == std::cv_status::timeout) {
+ return PairingEvent(PairingEvent::EXIT);
+ }
+
+ } while (true);
+ }
+
+ std::optional<PairingEvent> WaitUiPairingAccept() {
+ PairingEvent e = WaitForEvent();
+ if (e.type == PairingEvent::UI & e.ui_action == PairingEvent::PAIRING_ACCEPTED) {
+ return e;
+ } else {
+ return std::nullopt;
+ }
+ }
+
+ std::optional<PairingEvent> WaitUiConfirmYesNo() {
+ PairingEvent e = WaitForEvent();
+ if (e.type == PairingEvent::UI & e.ui_action == PairingEvent::CONFIRM_YESNO) {
+ return e;
+ } else {
+ return std::nullopt;
+ }
+ }
+
+ std::optional<PairingEvent> WaitUiPasskey() {
+ PairingEvent e = WaitForEvent();
+ if (e.type == PairingEvent::UI & e.ui_action == PairingEvent::PASSKEY) {
+ return e;
+ } else {
+ return std::nullopt;
+ }
+ }
+
+ template <Code C>
+ struct CodeToPacketView;
+ template <>
+ struct CodeToPacketView<Code::PAIRING_REQUEST> {
+ typedef PairingRequestView type;
+ };
+ template <>
+ struct CodeToPacketView<Code::PAIRING_RESPONSE> {
+ typedef PairingResponseView type;
+ };
+ template <>
+ struct CodeToPacketView<Code::PAIRING_CONFIRM> {
+ typedef PairingConfirmView type;
+ };
+ template <>
+ struct CodeToPacketView<Code::PAIRING_RANDOM> {
+ typedef PairingRandomView type;
+ };
+ template <>
+ struct CodeToPacketView<Code::PAIRING_FAILED> {
+ typedef PairingFailedView type;
+ };
+ template <>
+ struct CodeToPacketView<Code::ENCRYPTION_INFORMATION> {
+ typedef EncryptionInformationView type;
+ };
+ template <>
+ struct CodeToPacketView<Code::MASTER_IDENTIFICATION> {
+ typedef MasterIdentificationView type;
+ };
+ template <>
+ struct CodeToPacketView<Code::IDENTITY_INFORMATION> {
+ typedef IdentityInformationView type;
+ };
+ template <>
+ struct CodeToPacketView<Code::IDENTITY_ADDRESS_INFORMATION> {
+ typedef IdentityAddressInformationView type;
+ };
+ template <>
+ struct CodeToPacketView<Code::SIGNING_INFORMATION> {
+ typedef SigningInformationView type;
+ };
+ template <>
+ struct CodeToPacketView<Code::SECURITY_REQUEST> {
+ typedef SecurityRequestView type;
+ };
+ template <>
+ struct CodeToPacketView<Code::PAIRING_PUBLIC_KEY> {
+ typedef PairingPublicKeyView type;
+ };
+ template <>
+ struct CodeToPacketView<Code::PAIRING_DH_KEY_CHECK> {
+ typedef PairingDhKeyCheckView type;
+ };
+ template <>
+ struct CodeToPacketView<Code::PAIRING_KEYPRESS_NOTIFICATION> {
+ typedef PairingKeypressNotificationView type;
+ };
+
+ template <Code CODE>
+ std::variant<typename CodeToPacketView<CODE>::type, PairingFailure> WaitPacket() {
+ PairingEvent e = WaitForEvent();
+ switch (e.type) {
+ case PairingEvent::EXIT:
+ return PairingFailure(
+ /*FROM_HERE,*/ "Was expecting L2CAP Packet " + CodeText(CODE) + ", but received EXIT instead");
+
+ case PairingEvent::HCI_EVENT:
+ return PairingFailure(
+ /*FROM_HERE,*/ "Was expecting L2CAP Packet " + CodeText(CODE) + ", but received HCI_EVENT instead");
+
+ case PairingEvent::UI:
+ return PairingFailure(
+ /*FROM_HERE,*/ "Was expecting L2CAP Packet " + CodeText(CODE) + ", but received UI instead");
+
+ case PairingEvent::L2CAP: {
+ auto l2cap_packet = e.l2cap_packet.value();
+ if (!l2cap_packet.IsValid()) {
+ return PairingFailure("Malformed L2CAP packet received!");
+ }
+
+ const auto& received_code = l2cap_packet.GetCode();
+ if (received_code != CODE) {
+ if (received_code == Code::PAIRING_FAILED) {
+ auto pkt = PairingFailedView::Create(l2cap_packet);
+ if (!pkt.IsValid()) return PairingFailure("Malformed " + CodeText(CODE) + " packet");
+ return PairingFailure(/*FROM_HERE,*/
+ "Was expecting " + CodeText(CODE) + ", but received PAIRING_FAILED instead",
+ pkt.GetReason());
+ }
+
+ return PairingFailure(/*FROM_HERE,*/
+ "Was expecting " + CodeText(CODE) + ", but received " + CodeText(received_code) +
+ " instead",
+ received_code);
+ }
+
+ auto pkt = CodeToPacketView<CODE>::type::Create(l2cap_packet);
+ if (!pkt.IsValid()) return PairingFailure("Malformed " + CodeText(CODE) + " packet");
+ return pkt;
+ }
+ }
+ }
+
+ auto WaitPairingRequest() {
+ return WaitPacket<Code::PAIRING_REQUEST>();
+ }
+
+ auto WaitPairingResponse() {
+ return WaitPacket<Code::PAIRING_RESPONSE>();
+ }
+
+ auto WaitPairingConfirm() {
+ return WaitPacket<Code::PAIRING_CONFIRM>();
+ }
+
+ auto WaitPairingRandom() {
+ return WaitPacket<Code::PAIRING_RANDOM>();
+ }
+
+ auto WaitPairingPublicKey() {
+ return WaitPacket<Code::PAIRING_PUBLIC_KEY>();
+ }
+
+ auto WaitPairingDHKeyCheck() {
+ return WaitPacket<Code::PAIRING_DH_KEY_CHECK>();
+ }
+
+ auto WaitEncryptionInformationRequest() {
+ return WaitPacket<Code::ENCRYPTION_INFORMATION>();
+ }
+
+ auto WaitEncryptionInformation() {
+ return WaitPacket<Code::ENCRYPTION_INFORMATION>();
+ }
+
+ auto WaitMasterIdentification() {
+ return WaitPacket<Code::MASTER_IDENTIFICATION>();
+ }
+
+ auto WaitIdentityInformation() {
+ return WaitPacket<Code::IDENTITY_INFORMATION>();
+ }
+
+ auto WaitIdentityAddressInformation() {
+ return WaitPacket<Code::IDENTITY_ADDRESS_INFORMATION>();
+ }
+
+ auto WaitSigningInformation() {
+ return WaitPacket<Code::SIGNING_INFORMATION>();
+ }
+
+ template <size_t SIZE>
+ static std::array<uint8_t, SIZE> GenerateRandom() {
+ // TODO: We need a proper random number generator here.
+ // use current time as seed for random generator
+ std::srand(std::time(nullptr));
+ std::array<uint8_t, SIZE> r;
+ for (size_t i = 0; i < SIZE; i++) r[i] = std::rand();
+ return r;
+ }
+
+ uint32_t GenerateRandom() {
+ // TODO: We need a proper random number generator here.
+ // use current time as seed for random generator
+ std::srand(std::time(nullptr));
+ return std::rand();
+ }
+
+ /* This is just for test, never use in production code! */
+ void WaitUntilPairingFinished() {
+ thread_.join();
+ }
+
+ private:
+ std::condition_variable pairing_thread_blocker_;
+
+ std::mutex queue_guard;
+ std::queue<PairingEvent> queue;
+
+ std::thread thread_;
+};
+} // namespace security
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/security/pairing_handler_le_legacy.cc b/gd/security/pairing_handler_le_legacy.cc
new file mode 100644
index 0000000..0c3a73b
--- /dev/null
+++ b/gd/security/pairing_handler_le_legacy.cc
@@ -0,0 +1,234 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "security/pairing_handler_le.h"
+
+namespace bluetooth {
+namespace security {
+
+LegacyStage1ResultOrFailure PairingHandlerLe::DoLegacyStage1(const InitialInformations& i,
+ const PairingRequestView& pairing_request,
+ const PairingResponseView& pairing_response) {
+ if (((pairing_request.GetAuthReq() | pairing_response.GetAuthReq()) & AuthReqMaskMitm) == 0) {
+ // If both devices have not set MITM option, Just Works shall be used
+ return LegacyJustWorks();
+ }
+
+ if (pairing_request.GetOobDataFlag() == OobDataFlag::PRESENT &&
+ pairing_response.GetOobDataFlag() == OobDataFlag::PRESENT) {
+ // OobDataFlag remote_oob_flag = IAmMaster(i) ? pairing_response.GetOobDataFlag() :
+ // pairing_request.GetOobDataFlag(); OobDataFlag my_oob_flag = IAmMaster(i) ? pairing_request.GetOobDataFlag() :
+ // pairing_response.GetOobDataFlag();
+ return LegacyOutOfBand(i);
+ }
+
+ const auto& iom = pairing_request.GetIoCapability();
+ const auto& ios = pairing_response.GetIoCapability();
+
+ if (iom == IoCapability::NO_INPUT_NO_OUTPUT || ios == IoCapability::NO_INPUT_NO_OUTPUT) {
+ return LegacyJustWorks();
+ }
+
+ if ((iom == IoCapability::DISPLAY_ONLY || iom == IoCapability::DISPLAY_YES_NO) &&
+ (ios == IoCapability::DISPLAY_ONLY || ios == IoCapability::DISPLAY_YES_NO)) {
+ return LegacyJustWorks();
+ }
+
+ // This if() should not be needed, these are only combinations left.
+ if (iom == IoCapability::KEYBOARD_DISPLAY || iom == IoCapability::KEYBOARD_ONLY ||
+ ios == IoCapability::KEYBOARD_DISPLAY || ios == IoCapability::KEYBOARD_ONLY) {
+ IoCapability my_iocaps = IAmMaster(i) ? iom : ios;
+ IoCapability remote_iocaps = IAmMaster(i) ? ios : iom;
+ return LegacyPasskeyEntry(i, my_iocaps, remote_iocaps);
+ }
+
+ // We went through all possble combinations.
+ LOG_ALWAYS_FATAL("This should never happen");
+}
+
+LegacyStage1ResultOrFailure PairingHandlerLe::LegacyJustWorks() {
+ LOG_INFO("Legacy Just Works start");
+ return Octet16{0};
+}
+
+LegacyStage1ResultOrFailure PairingHandlerLe::LegacyPasskeyEntry(const InitialInformations& i,
+ const IoCapability& my_iocaps,
+ const IoCapability& remote_iocaps) {
+ bool i_am_displaying = false;
+ if (my_iocaps == IoCapability::DISPLAY_ONLY || my_iocaps == IoCapability::DISPLAY_YES_NO) {
+ i_am_displaying = true;
+ } else if (IAmMaster(i) && remote_iocaps == IoCapability::KEYBOARD_DISPLAY &&
+ my_iocaps == IoCapability::KEYBOARD_DISPLAY) {
+ i_am_displaying = true;
+ } else if (my_iocaps == IoCapability::KEYBOARD_DISPLAY && remote_iocaps == IoCapability::KEYBOARD_ONLY) {
+ i_am_displaying = true;
+ }
+
+ LOG_INFO("Passkey Entry start %s", i_am_displaying ? "displaying" : "accepting");
+
+ uint32_t passkey;
+ if (i_am_displaying) {
+ // generate passkey in a valid range
+ passkey = GenerateRandom();
+ passkey &= 0x0fffff; /* maximum 20 significant bits */
+ constexpr uint32_t PASSKEY_MAX = 999999;
+ if (passkey > PASSKEY_MAX) passkey >>= 1;
+
+ i.ui_handler->DisplayConfirmValue(passkey);
+ } else {
+ i.ui_handler->DisplayEnterPasskeyDialog();
+ std::optional<PairingEvent> response = WaitUiPasskey();
+ if (!response) return PairingFailure("Passkey did not arrive!");
+
+ passkey = response->ui_value;
+ }
+
+ Octet16 tk{0};
+ tk[0] = (uint8_t)(passkey);
+ tk[1] = (uint8_t)(passkey >> 8);
+ tk[2] = (uint8_t)(passkey >> 16);
+ tk[3] = (uint8_t)(passkey >> 24);
+
+ LOG_INFO("Passkey Entry finish");
+ return tk;
+}
+
+LegacyStage1ResultOrFailure PairingHandlerLe::LegacyOutOfBand(const InitialInformations& i) {
+ return i.remote_oob_data->security_manager_tk_value;
+}
+
+StkOrFailure PairingHandlerLe::DoLegacyStage2(const InitialInformations& i, const PairingRequestView& pairing_request,
+ const PairingResponseView& pairing_response, const Octet16& tk) {
+ LOG_INFO("Legacy Step 2 start");
+ std::vector<uint8_t> preq(pairing_request.begin(), pairing_request.end());
+ std::vector<uint8_t> pres(pairing_response.begin(), pairing_response.end());
+
+ Octet16 mrand, srand;
+ if (IAmMaster(i)) {
+ mrand = GenerateRandom<16>();
+
+ // LOG(INFO) << +(IAmMaster(i)) << " tk = " << base::HexEncode(tk.data(), tk.size());
+ // LOG(INFO) << +(IAmMaster(i)) << " mrand = " << base::HexEncode(mrand.data(), mrand.size());
+ // LOG(INFO) << +(IAmMaster(i)) << " preq = " << base::HexEncode(preq.data(), preq.size());
+ // LOG(INFO) << +(IAmMaster(i)) << " pres = " << base::HexEncode(pres.data(), pres.size());
+ // LOG(INFO) << +(IAmMaster(i)) << " i.remote_connection_address_type = " << +i.remote_connection_address_type;
+ // LOG(INFO) << +(IAmMaster(i)) << " i.i.remote_connection_address.address = " << i.remote_connection_address;
+ // LOG(INFO) << +(IAmMaster(i)) << " i.my_connection_address_type = " << +i.my_connection_address_type;
+ // LOG(INFO) << +(IAmMaster(i)) << " i.i.my_connection_address.address = " << i.my_connection_address;
+ Octet16 mconfirm = crypto_toolbox::c1(
+ tk, mrand, preq.data(), pres.data(), (uint8_t)i.my_connection_address.GetAddressType(),
+ i.my_connection_address.GetAddress().address, (uint8_t)i.remote_connection_address.GetAddressType(),
+ i.remote_connection_address.GetAddress().address);
+
+ LOG_INFO("Master sends Mconfirm");
+ SendL2capPacket(i, PairingConfirmBuilder::Create(mconfirm));
+
+ LOG_INFO("Master waits for the Sconfirm");
+ auto sconfirm_pkt = WaitPairingConfirm();
+ if (std::holds_alternative<PairingFailure>(sconfirm_pkt)) {
+ return std::get<PairingFailure>(sconfirm_pkt);
+ }
+ Octet16 sconfirm = std::get<PairingConfirmView>(sconfirm_pkt).GetConfirmValue();
+
+ LOG_INFO("Master sends Mrand");
+ SendL2capPacket(i, PairingRandomBuilder::Create(mrand));
+
+ LOG_INFO("Master waits for Srand");
+ auto random_pkt = WaitPairingRandom();
+ if (std::holds_alternative<PairingFailure>(random_pkt)) {
+ return std::get<PairingFailure>(random_pkt);
+ }
+ srand = std::get<PairingRandomView>(random_pkt).GetRandomValue();
+
+ // LOG(INFO) << +(IAmMaster(i)) << " tk = " << base::HexEncode(tk.data(), tk.size());
+ // LOG(INFO) << +(IAmMaster(i)) << " srand = " << base::HexEncode(srand.data(), srand.size());
+ // LOG(INFO) << +(IAmMaster(i)) << " preq = " << base::HexEncode(preq.data(), preq.size());
+ // LOG(INFO) << +(IAmMaster(i)) << " pres = " << base::HexEncode(pres.data(), pres.size());
+ // LOG(INFO) << +(IAmMaster(i)) << " i.my_connection_address_type = " << +i.my_connection_address_type;
+ // LOG(INFO) << +(IAmMaster(i)) << " i.i.my_connection_address.address = " << i.my_connection_address;
+ // LOG(INFO) << +(IAmMaster(i)) << " i.remote_connection_address_type = " << +i.remote_connection_address_type;
+ // LOG(INFO) << +(IAmMaster(i)) << " i.i.remote_connection_address.address = " << i.remote_connection_address;
+ Octet16 sconfirm_generated = crypto_toolbox::c1(
+ tk, srand, preq.data(), pres.data(), (uint8_t)i.my_connection_address.GetAddressType(),
+ i.my_connection_address.GetAddress().address, (uint8_t)i.remote_connection_address.GetAddressType(),
+ i.remote_connection_address.GetAddress().address);
+
+ if (sconfirm != sconfirm_generated) {
+ LOG_INFO("sconfirm does not match generated value");
+
+ SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::CONFIRM_VALUE_FAILED));
+ return PairingFailure("sconfirm does not match generated value");
+ }
+ } else {
+ srand = GenerateRandom<16>();
+
+ std::vector<uint8_t> preq(pairing_request.begin(), pairing_request.end());
+ std::vector<uint8_t> pres(pairing_response.begin(), pairing_response.end());
+
+ Octet16 sconfirm = crypto_toolbox::c1(
+ tk, srand, preq.data(), pres.data(), (uint8_t)i.remote_connection_address.GetAddressType(),
+ i.remote_connection_address.GetAddress().address, (uint8_t)i.my_connection_address.GetAddressType(),
+ i.my_connection_address.GetAddress().address);
+
+ LOG_INFO("Slave waits for the Mconfirm");
+ auto mconfirm_pkt = WaitPairingConfirm();
+ if (std::holds_alternative<PairingFailure>(mconfirm_pkt)) {
+ return std::get<PairingFailure>(mconfirm_pkt);
+ }
+ Octet16 mconfirm = std::get<PairingConfirmView>(mconfirm_pkt).GetConfirmValue();
+
+ LOG_INFO("Slave sends Sconfirm");
+ SendL2capPacket(i, PairingConfirmBuilder::Create(sconfirm));
+
+ LOG_INFO("Slave waits for Mrand");
+ auto random_pkt = WaitPairingRandom();
+ if (std::holds_alternative<PairingFailure>(random_pkt)) {
+ return std::get<PairingFailure>(random_pkt);
+ }
+ mrand = std::get<PairingRandomView>(random_pkt).GetRandomValue();
+
+ // LOG(INFO) << +(IAmMaster(i)) << " tk = " << base::HexEncode(tk.data(), tk.size());
+ // LOG(INFO) << +(IAmMaster(i)) << " mrand = " << base::HexEncode(mrand.data(), mrand.size());
+ // LOG(INFO) << +(IAmMaster(i)) << " preq = " << base::HexEncode(preq.data(), preq.size());
+ // LOG(INFO) << +(IAmMaster(i)) << " pres = " << base::HexEncode(pres.data(), pres.size());
+ // LOG(INFO) << +(IAmMaster(i)) << " i.my_connection_address_type = " << +i.my_connection_address_type;
+ // LOG(INFO) << +(IAmMaster(i)) << " i.i.my_connection_address.address = " << i.my_connection_address;
+ // LOG(INFO) << +(IAmMaster(i)) << " i.remote_connection_address_type = " << +i.remote_connection_address_type;
+ // LOG(INFO) << +(IAmMaster(i)) << " i.i.remote_connection_address.address = " << i.remote_connection_address;
+ Octet16 mconfirm_generated = crypto_toolbox::c1(
+ tk, mrand, preq.data(), pres.data(), (uint8_t)i.remote_connection_address.GetAddressType(),
+ i.remote_connection_address.GetAddress().address, (uint8_t)i.my_connection_address.GetAddressType(),
+ i.my_connection_address.GetAddress().address);
+
+ if (mconfirm != mconfirm_generated) {
+ LOG_INFO("mconfirm does not match generated value");
+ SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::CONFIRM_VALUE_FAILED));
+ return PairingFailure("mconfirm does not match generated value");
+ }
+
+ LOG_INFO("Slave sends Srand");
+ SendL2capPacket(i, PairingRandomBuilder::Create(srand));
+ }
+
+ LOG_INFO("Legacy stage 2 finish");
+
+ /* STK */
+ return crypto_toolbox::s1(tk, srand, mrand);
+}
+} // namespace security
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/security/pairing_handler_le_secure_connections.cc b/gd/security/pairing_handler_le_secure_connections.cc
new file mode 100644
index 0000000..f5b0a0f
--- /dev/null
+++ b/gd/security/pairing_handler_le_secure_connections.cc
@@ -0,0 +1,472 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "security/pairing_handler_le.h"
+
+namespace bluetooth {
+namespace security {
+
+std::variant<PairingFailure, KeyExchangeResult> PairingHandlerLe::ExchangePublicKeys(const InitialInformations& i,
+ OobDataFlag remote_have_oob_data) {
+ // Generate ECDH, or use one that was used for OOB data
+ const auto [private_key, public_key] = (remote_have_oob_data == OobDataFlag::NOT_PRESENT || !i.my_oob_data)
+ ? GenerateECDHKeyPair()
+ : std::make_pair(i.my_oob_data->private_key, i.my_oob_data->public_key);
+
+ LOG_INFO("Public key exchange start");
+ std::unique_ptr<PairingPublicKeyBuilder> myPublicKey = PairingPublicKeyBuilder::Create(public_key.x, public_key.y);
+
+ if (!ValidateECDHPoint(public_key)) {
+ LOG_ERROR("Can't validate my own public key!!!");
+ return PairingFailure("Can't validate my own public key");
+ }
+
+ if (IAmMaster(i)) {
+ // Send pairing public key
+ LOG_INFO("Master sends out public key");
+ SendL2capPacket(i, std::move(myPublicKey));
+ }
+
+ LOG_INFO(" Waiting for Public key...");
+ auto response = WaitPairingPublicKey();
+ LOG_INFO(" Received public key");
+ if (std::holds_alternative<PairingFailure>(response)) {
+ return std::get<PairingFailure>(response);
+ }
+
+ EcdhPublicKey remote_public_key;
+ auto ppkv = std::get<PairingPublicKeyView>(response);
+ remote_public_key.x = ppkv.GetPublicKeyX();
+ remote_public_key.y = ppkv.GetPublicKeyY();
+ LOG_INFO("Received Public key from remote");
+
+ // validate received public key
+ if (!ValidateECDHPoint(remote_public_key)) {
+ // TODO: Spec is unclear what should happend when the point is not on
+ // the correct curve: A device that detects an invalid public key from
+ // the peer at any point during the LE Secure Connections pairing
+ // process shall not use the resulting LTK, if any.
+ LOG_INFO("Can't validate remote public key");
+ return PairingFailure("Can't validate remote public key");
+ }
+
+ if (!IAmMaster(i)) {
+ LOG_INFO("Slave sends out public key");
+ // Send pairing public key
+ SendL2capPacket(i, std::move(myPublicKey));
+ }
+
+ LOG_INFO("Public key exchange finish");
+
+ std::array<uint8_t, 32> dhkey = ComputeDHKey(private_key, remote_public_key);
+
+ const EcdhPublicKey& PKa = IAmMaster(i) ? public_key : remote_public_key;
+ const EcdhPublicKey& PKb = IAmMaster(i) ? remote_public_key : public_key;
+
+ return KeyExchangeResult{PKa, PKb, dhkey};
+}
+
+Stage1ResultOrFailure PairingHandlerLe::DoSecureConnectionsStage1(const InitialInformations& i,
+ const EcdhPublicKey& PKa, const EcdhPublicKey& PKb,
+ const PairingRequestView& pairing_request,
+ const PairingResponseView& pairing_response) {
+ if ((pairing_request.GetAuthReq() & pairing_response.GetAuthReq() & AuthReqMaskMitm) == 0) {
+ // If both devices have not set MITM option, Just Works shall be used
+ return SecureConnectionsJustWorks(i, PKa, PKb);
+ }
+
+ if (pairing_request.GetOobDataFlag() == OobDataFlag::PRESENT ||
+ pairing_response.GetOobDataFlag() == OobDataFlag::PRESENT) {
+ OobDataFlag remote_oob_flag = IAmMaster(i) ? pairing_response.GetOobDataFlag() : pairing_request.GetOobDataFlag();
+ OobDataFlag my_oob_flag = IAmMaster(i) ? pairing_request.GetOobDataFlag() : pairing_response.GetOobDataFlag();
+ return SecureConnectionsOutOfBand(i, PKa, PKb, my_oob_flag, remote_oob_flag);
+ }
+
+ const auto& iom = pairing_request.GetIoCapability();
+ const auto& ios = pairing_response.GetIoCapability();
+
+ if ((iom == IoCapability::KEYBOARD_DISPLAY || iom == IoCapability::DISPLAY_YES_NO) &&
+ (ios == IoCapability::KEYBOARD_DISPLAY || ios == IoCapability::DISPLAY_YES_NO)) {
+ return SecureConnectionsNumericComparison(i, PKa, PKb);
+ }
+
+ if (iom == IoCapability::NO_INPUT_NO_OUTPUT || ios == IoCapability::NO_INPUT_NO_OUTPUT) {
+ return SecureConnectionsJustWorks(i, PKa, PKb);
+ }
+
+ if ((iom == IoCapability::DISPLAY_ONLY || iom == IoCapability::DISPLAY_YES_NO) &&
+ (ios == IoCapability::DISPLAY_ONLY || ios == IoCapability::DISPLAY_YES_NO)) {
+ return SecureConnectionsJustWorks(i, PKa, PKb);
+ }
+
+ IoCapability my_iocaps = IAmMaster(i) ? iom : ios;
+ IoCapability remote_iocaps = IAmMaster(i) ? ios : iom;
+ return SecureConnectionsPasskeyEntry(i, PKa, PKb, my_iocaps, remote_iocaps);
+}
+
+Stage2ResultOrFailure PairingHandlerLe::DoSecureConnectionsStage2(const InitialInformations& i,
+ const EcdhPublicKey& PKa, const EcdhPublicKey& PKb,
+ const PairingRequestView& pairing_request,
+ const PairingResponseView& pairing_response,
+ const Stage1Result stage1result,
+ const std::array<uint8_t, 32>& dhkey) {
+ LOG_INFO("Authentication stage 2 started");
+
+ auto [Na, Nb, ra, rb] = stage1result;
+
+ // 2.3.5.6.5 Authentication stage 2 long term key calculation
+ uint8_t a[7];
+ uint8_t b[7];
+
+ if (IAmMaster(i)) {
+ memcpy(a, i.my_connection_address.GetAddress().address, 6);
+ a[6] = (uint8_t)i.my_connection_address.GetAddressType();
+ memcpy(b, i.remote_connection_address.GetAddress().address, 6);
+ b[6] = (uint8_t)i.remote_connection_address.GetAddressType();
+ } else {
+ memcpy(a, i.remote_connection_address.GetAddress().address, 6);
+ a[6] = (uint8_t)i.remote_connection_address.GetAddressType();
+ memcpy(b, i.my_connection_address.GetAddress().address, 6);
+ b[6] = (uint8_t)i.my_connection_address.GetAddressType();
+ }
+
+ Octet16 ltk, mac_key;
+ crypto_toolbox::f5((uint8_t*)dhkey.data(), Na, Nb, a, b, &mac_key, <k);
+
+ // DHKey exchange and check
+
+ std::array<uint8_t, 3> iocapA{static_cast<uint8_t>(pairing_request.GetIoCapability()),
+ static_cast<uint8_t>(pairing_request.GetOobDataFlag()), pairing_request.GetAuthReq()};
+ std::array<uint8_t, 3> iocapB{static_cast<uint8_t>(pairing_response.GetIoCapability()),
+ static_cast<uint8_t>(pairing_response.GetOobDataFlag()), pairing_response.GetAuthReq()};
+
+ // LOG(INFO) << +(IAmMaster(i)) << " LTK = " << base::HexEncode(ltk.data(), ltk.size());
+ // LOG(INFO) << +(IAmMaster(i)) << " MAC_KEY = " << base::HexEncode(mac_key.data(), mac_key.size());
+ // LOG(INFO) << +(IAmMaster(i)) << " Na = " << base::HexEncode(Na.data(), Na.size());
+ // LOG(INFO) << +(IAmMaster(i)) << " Nb = " << base::HexEncode(Nb.data(), Nb.size());
+ // LOG(INFO) << +(IAmMaster(i)) << " ra = " << base::HexEncode(ra.data(), ra.size());
+ // LOG(INFO) << +(IAmMaster(i)) << " rb = " << base::HexEncode(rb.data(), rb.size());
+ // LOG(INFO) << +(IAmMaster(i)) << " iocapA = " << base::HexEncode(iocapA.data(), iocapA.size());
+ // LOG(INFO) << +(IAmMaster(i)) << " iocapB = " << base::HexEncode(iocapB.data(), iocapB.size());
+ // LOG(INFO) << +(IAmMaster(i)) << " a = " << base::HexEncode(a, 7);
+ // LOG(INFO) << +(IAmMaster(i)) << " b = " << base::HexEncode(b, 7);
+
+ Octet16 Ea = crypto_toolbox::f6(mac_key, Na, Nb, rb, iocapA.data(), a, b);
+
+ Octet16 Eb = crypto_toolbox::f6(mac_key, Nb, Na, ra, iocapB.data(), b, a);
+
+ if (IAmMaster(i)) {
+ // send Pairing DHKey Check
+ SendL2capPacket(i, PairingDhKeyCheckBuilder::Create(Ea));
+
+ auto response = WaitPairingDHKeyCheck();
+ if (std::holds_alternative<PairingFailure>(response)) {
+ return std::get<PairingFailure>(response);
+ }
+
+ if (std::get<PairingDhKeyCheckView>(response).GetDhKeyCheck() != Eb) {
+ LOG_INFO("Ea != Eb, aborting!");
+ SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::DHKEY_CHECK_FAILED));
+ return PairingFailure("Ea != Eb");
+ }
+ } else {
+ auto response = WaitPairingDHKeyCheck();
+ if (std::holds_alternative<PairingFailure>(response)) {
+ return std::get<PairingFailure>(response);
+ }
+
+ if (std::get<PairingDhKeyCheckView>(response).GetDhKeyCheck() != Ea) {
+ LOG_INFO("Ea != Eb, aborting!");
+ SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::DHKEY_CHECK_FAILED));
+ return PairingFailure("Ea != Eb");
+ }
+
+ // send Pairing DHKey Check
+ SendL2capPacket(i, PairingDhKeyCheckBuilder::Create(Eb));
+ }
+
+ LOG_INFO("Authentication stage 2 (DHKey checks) finished");
+ return ltk;
+}
+
+Stage1ResultOrFailure PairingHandlerLe::SecureConnectionsOutOfBand(const InitialInformations& i,
+ const EcdhPublicKey& Pka, const EcdhPublicKey& Pkb,
+ OobDataFlag my_oob_flag,
+ OobDataFlag remote_oob_flag) {
+ LOG_INFO("Out Of Band start");
+
+ Octet16 zeros{0};
+ Octet16 localR = (remote_oob_flag == OobDataFlag::PRESENT && i.my_oob_data) ? i.my_oob_data->r : zeros;
+ Octet16 remoteR;
+
+ if (my_oob_flag == OobDataFlag::NOT_PRESENT || (my_oob_flag == OobDataFlag::PRESENT && !i.remote_oob_data)) {
+ /* we have send the OOB data, but not received them. remote will check if
+ * C value is correct */
+ remoteR = zeros;
+ } else {
+ remoteR = i.remote_oob_data->le_sc_r;
+ Octet16 remoteC = i.remote_oob_data->le_sc_c;
+
+ Octet16 remoteC2;
+ if (IAmMaster(i)) {
+ remoteC2 = crypto_toolbox::f4((uint8_t*)Pkb.x.data(), (uint8_t*)Pkb.x.data(), remoteR, 0);
+ } else {
+ remoteC2 = crypto_toolbox::f4((uint8_t*)Pka.x.data(), (uint8_t*)Pka.x.data(), remoteR, 0);
+ }
+
+ if (remoteC2 != remoteC) {
+ LOG_ERROR("C_computed != C_from_remote, aborting!");
+ return PairingFailure("C_computed != C_from_remote, aborting");
+ }
+ }
+
+ Octet16 Na, Nb, ra, rb;
+ if (IAmMaster(i)) {
+ ra = localR;
+ rb = remoteR;
+ Na = GenerateRandom<16>();
+ // Send Pairing Random
+ SendL2capPacket(i, PairingRandomBuilder::Create(Na));
+
+ LOG_INFO("Master waits for Nb");
+ auto random = WaitPairingRandom();
+ if (std::holds_alternative<PairingFailure>(random)) {
+ return std::get<PairingFailure>(random);
+ }
+ Nb = std::get<PairingRandomView>(random).GetRandomValue();
+ } else {
+ ra = remoteR;
+ rb = localR;
+ Nb = GenerateRandom<16>();
+
+ LOG_INFO("Slave waits for random");
+ auto random = WaitPairingRandom();
+ if (std::holds_alternative<PairingFailure>(random)) {
+ return std::get<PairingFailure>(random);
+ }
+ Na = std::get<PairingRandomView>(random).GetRandomValue();
+
+ SendL2capPacket(i, PairingRandomBuilder::Create(Nb));
+ }
+
+ return Stage1Result{Na, Nb, ra, rb};
+}
+
+Stage1ResultOrFailure PairingHandlerLe::SecureConnectionsPasskeyEntry(const InitialInformations& i,
+ const EcdhPublicKey& PKa,
+ const EcdhPublicKey& PKb, IoCapability my_iocaps,
+ IoCapability remote_iocaps) {
+ LOG_INFO("Passkey Entry start");
+ Octet16 Na, Nb, ra{0}, rb{0};
+
+ uint32_t passkey;
+
+ if (my_iocaps == IoCapability::DISPLAY_ONLY || remote_iocaps == IoCapability::KEYBOARD_ONLY) {
+ // I display
+ passkey = GenerateRandom();
+ passkey &= 0x0fffff; /* maximum 20 significant bytes */
+ constexpr uint32_t PASSKEY_MAX = 999999;
+ while (passkey > PASSKEY_MAX) passkey >>= 1;
+
+ i.ui_handler->DisplayPasskey(passkey);
+
+ } else if (my_iocaps == IoCapability::KEYBOARD_ONLY || remote_iocaps == IoCapability::DISPLAY_ONLY) {
+ i.ui_handler->DisplayEnterPasskeyDialog();
+ std::optional<PairingEvent> response = WaitUiPasskey();
+ if (!response) return PairingFailure("Passkey did not arrive!");
+
+ passkey = response->ui_value;
+
+ /*TODO: shall we send "Keypress Notification" after each key ? This would
+ * have impact on the SMP timeout*/
+
+ } else {
+ LOG(FATAL) << "THIS SHOULD NEVER HAPPEN";
+ return PairingFailure("FATAL!");
+ }
+
+ uint32_t bitmask = 0x01;
+ for (int loop = 0; loop < 20; loop++, bitmask <<= 1) {
+ LOG_INFO("Iteration no %d", loop);
+ bool bit_set = ((bitmask & passkey) != 0);
+ uint8_t ri = bit_set ? 0x81 : 0x80;
+
+ Octet16 Cai, Cbi, Nai, Nbi;
+ if (IAmMaster(i)) {
+ Nai = GenerateRandom<16>();
+
+ Cai = crypto_toolbox::f4((uint8_t*)PKa.x.data(), (uint8_t*)PKb.x.data(), Nai, ri);
+
+ // Send Pairing Confirm
+ LOG_INFO("Master sends Cai");
+ SendL2capPacket(i, PairingConfirmBuilder::Create(Cai));
+
+ LOG_INFO("Master waits for the Cbi");
+ auto confirm = WaitPairingConfirm();
+ if (std::holds_alternative<PairingFailure>(confirm)) {
+ return std::get<PairingFailure>(confirm);
+ }
+ Cbi = std::get<PairingConfirmView>(confirm).GetConfirmValue();
+
+ // Send Pairing Random
+ SendL2capPacket(i, PairingRandomBuilder::Create(Nai));
+
+ LOG_INFO("Master waits for Nbi");
+ auto random = WaitPairingRandom();
+ if (std::holds_alternative<PairingFailure>(random)) {
+ return std::get<PairingFailure>(random);
+ }
+ Nbi = std::get<PairingRandomView>(random).GetRandomValue();
+
+ Octet16 Cbi2 = crypto_toolbox::f4((uint8_t*)PKb.x.data(), (uint8_t*)PKa.x.data(), Nbi, ri);
+ if (Cbi != Cbi2) {
+ LOG_INFO("Cai != Cbi, aborting!");
+ SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::CONFIRM_VALUE_FAILED));
+ return PairingFailure("Cai != Cbi");
+ }
+ } else {
+ Nbi = GenerateRandom<16>();
+ // Compute confirm
+ Cbi = crypto_toolbox::f4((uint8_t*)PKb.x.data(), (uint8_t*)PKa.x.data(), Nbi, ri);
+
+ LOG_INFO("Slave waits for the Cai");
+ auto confirm = WaitPairingConfirm();
+ if (std::holds_alternative<PairingFailure>(confirm)) {
+ return std::get<PairingFailure>(confirm);
+ }
+ Cai = std::get<PairingConfirmView>(confirm).GetConfirmValue();
+
+ // Send Pairing Confirm
+ LOG_INFO("Slave sends confirmation");
+ SendL2capPacket(i, PairingConfirmBuilder::Create(Cbi));
+
+ LOG_INFO("Slave waits for random");
+ auto random = WaitPairingRandom();
+ if (std::holds_alternative<PairingFailure>(random)) {
+ return std::get<PairingFailure>(random);
+ }
+ Nai = std::get<PairingRandomView>(random).GetRandomValue();
+
+ Octet16 Cai2 = crypto_toolbox::f4((uint8_t*)PKa.x.data(), (uint8_t*)PKb.x.data(), Nai, ri);
+ if (Cai != Cai2) {
+ LOG_INFO("Cai != Cai2, aborting!");
+ SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::CONFIRM_VALUE_FAILED));
+ return PairingFailure("Cai != Cai2");
+ }
+
+ // Send Pairing Random
+ SendL2capPacket(i, PairingRandomBuilder::Create(Nbi));
+ }
+
+ if (loop == 19) {
+ Na = Nai;
+ Nb = Nbi;
+ }
+ }
+
+ ra[0] = (uint8_t)(passkey);
+ ra[1] = (uint8_t)(passkey >> 8);
+ ra[2] = (uint8_t)(passkey >> 16);
+ ra[3] = (uint8_t)(passkey >> 24);
+ rb = ra;
+
+ return Stage1Result{Na, Nb, ra, rb};
+}
+
+Stage1ResultOrFailure PairingHandlerLe::SecureConnectionsNumericComparison(const InitialInformations& i,
+ const EcdhPublicKey& PKa,
+ const EcdhPublicKey& PKb) {
+ LOG_INFO("Numeric Comparison start");
+ Stage1ResultOrFailure result = SecureConnectionsJustWorks(i, PKa, PKb);
+ if (std::holds_alternative<PairingFailure>(result)) {
+ return std::get<PairingFailure>(result);
+ }
+
+ const auto [Na, Nb, ra, rb] = std::get<Stage1Result>(result);
+
+ uint32_t number_to_display = crypto_toolbox::g2((uint8_t*)PKa.x.data(), (uint8_t*)PKb.x.data(), Na, Nb);
+
+ i.ui_handler->DisplayConfirmValue(number_to_display);
+
+ std::optional<PairingEvent> confirmyesno = WaitUiConfirmYesNo();
+ if (!confirmyesno || confirmyesno->ui_value == 0) {
+ LOG_INFO("Was expecting the user value confirm");
+ return PairingFailure("Was expecting the user value confirm");
+ }
+
+ return result;
+}
+
+Stage1ResultOrFailure PairingHandlerLe::SecureConnectionsJustWorks(const InitialInformations& i,
+ const EcdhPublicKey& PKa, const EcdhPublicKey& PKb) {
+ Octet16 Ca, Cb, Na, Nb, ra, rb;
+
+ ra = rb = {0};
+
+ if (IAmMaster(i)) {
+ Na = GenerateRandom<16>();
+ LOG_INFO("Master waits for confirmation");
+ auto confirm = WaitPairingConfirm();
+ if (std::holds_alternative<PairingFailure>(confirm)) {
+ return std::get<PairingFailure>(confirm);
+ }
+ Cb = std::get<PairingConfirmView>(confirm).GetConfirmValue();
+
+ // Send Pairing Random
+ SendL2capPacket(i, PairingRandomBuilder::Create(Na));
+
+ LOG_INFO("Master waits for Random");
+ auto random = WaitPairingRandom();
+ if (std::holds_alternative<PairingFailure>(random)) {
+ return std::get<PairingFailure>(random);
+ }
+ Nb = std::get<PairingRandomView>(random).GetRandomValue();
+
+ // Compute confirm
+ Ca = crypto_toolbox::f4((uint8_t*)PKb.x.data(), (uint8_t*)PKa.x.data(), Nb, 0);
+
+ if (Ca != Cb) {
+ LOG_INFO("Ca != Cb, aborting!");
+ SendL2capPacket(i, PairingFailedBuilder::Create(PairingFailedReason::CONFIRM_VALUE_FAILED));
+ return PairingFailure("Ca != Cb");
+ }
+ } else {
+ Nb = GenerateRandom<16>();
+ // Compute confirm
+ Cb = crypto_toolbox::f4((uint8_t*)PKb.x.data(), (uint8_t*)PKa.x.data(), Nb, 0);
+
+ // Send Pairing Confirm
+ LOG_INFO("Slave sends confirmation");
+ SendL2capPacket(i, PairingConfirmBuilder::Create(Cb));
+
+ LOG_INFO("Slave waits for random");
+ auto random = WaitPairingRandom();
+ if (std::holds_alternative<PairingFailure>(random)) {
+ return std::get<PairingFailure>(random);
+ }
+ Na = std::get<PairingRandomView>(random).GetRandomValue();
+
+ // Send Pairing Random
+ SendL2capPacket(i, PairingRandomBuilder::Create(Nb));
+ }
+
+ return Stage1Result{Na, Nb, ra, rb};
+}
+
+} // namespace security
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/security/pairing_handler_le_unittest.cc b/gd/security/pairing_handler_le_unittest.cc
new file mode 100644
index 0000000..3610700
--- /dev/null
+++ b/gd/security/pairing_handler_le_unittest.cc
@@ -0,0 +1,335 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <memory>
+
+#include "os/log.h"
+#include "security/pairing_handler_le.h"
+#include "security/test/mocks.h"
+
+using ::testing::_;
+using ::testing::Eq;
+using ::testing::Field;
+using ::testing::VariantWith;
+
+using bluetooth::security::CommandView;
+
+namespace bluetooth {
+namespace security {
+
+namespace {
+
+CommandView BuilderToView(std::unique_ptr<BasePacketBuilder> builder) {
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ builder->Serialize(it);
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto temp_cmd_view = CommandView::Create(packet_bytes_view);
+ return CommandView::Create(temp_cmd_view);
+}
+
+std::condition_variable outgoing_l2cap_blocker_;
+std::optional<bluetooth::security::CommandView> outgoing_l2cap_packet_;
+
+bool WaitForOutgoingL2capPacket() {
+ std::mutex mutex;
+ std::unique_lock<std::mutex> lock(mutex);
+ if (outgoing_l2cap_blocker_.wait_for(lock, std::chrono::seconds(5)) == std::cv_status::timeout) {
+ return false;
+ }
+ return true;
+}
+
+class PairingResultHandlerMock {
+ public:
+ MOCK_CONST_METHOD1(OnPairingFinished, void(PairingResultOrFailure));
+};
+
+std::unique_ptr<PairingResultHandlerMock> pairingResult;
+LeSecurityInterfaceMock leSecurityMock;
+UIMock uiMock;
+
+void OnPairingFinished(PairingResultOrFailure r) {
+ if (std::holds_alternative<PairingResult>(r)) {
+ LOG(INFO) << "pairing with " << std::get<PairingResult>(r).connection_address << " finished successfully!";
+ } else {
+ LOG(INFO) << "pairing with ... failed!";
+ }
+ pairingResult->OnPairingFinished(r);
+}
+} // namespace
+
+class PairingHandlerUnitTest : public testing::Test {
+ protected:
+ void SetUp() {
+ thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+ handler_ = new os::Handler(thread_);
+
+ bidi_queue_ =
+ std::make_unique<common::BidiQueue<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>>(10);
+ up_buffer_ = std::make_unique<os::EnqueueBuffer<packet::BasePacketBuilder>>(bidi_queue_->GetUpEnd());
+
+ bidi_queue_->GetDownEnd()->RegisterDequeue(
+ handler_, common::Bind(&PairingHandlerUnitTest::L2CAP_SendSmp, common::Unretained(this)));
+
+ pairingResult.reset(new PairingResultHandlerMock);
+ }
+ void TearDown() {
+ pairingResult.reset();
+ bidi_queue_->GetDownEnd()->UnregisterDequeue();
+ handler_->Clear();
+ delete handler_;
+ delete thread_;
+
+ ::testing::Mock::VerifyAndClearExpectations(&leSecurityMock);
+ ::testing::Mock::VerifyAndClearExpectations(&uiMock);
+ }
+
+ void L2CAP_SendSmp() {
+ std::unique_ptr<packet::BasePacketBuilder> builder = bidi_queue_->GetDownEnd()->TryDequeue();
+
+ outgoing_l2cap_packet_ = BuilderToView(std::move(builder));
+ outgoing_l2cap_packet_->IsValid();
+
+ outgoing_l2cap_blocker_.notify_one();
+ }
+
+ public:
+ os::Thread* thread_;
+ os::Handler* handler_;
+ std::unique_ptr<common::BidiQueue<packet::PacketView<packet::kLittleEndian>, packet::BasePacketBuilder>> bidi_queue_;
+ std::unique_ptr<os::EnqueueBuffer<packet::BasePacketBuilder>> up_buffer_;
+};
+
+InitialInformations initial_informations{
+ .my_role = hci::Role::MASTER,
+ .my_connection_address = {{}, hci::AddressType::PUBLIC_DEVICE_ADDRESS},
+
+ .myPairingCapabilities = {.io_capability = IoCapability::NO_INPUT_NO_OUTPUT,
+ .oob_data_flag = OobDataFlag::NOT_PRESENT,
+ .auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+ .maximum_encryption_key_size = 16,
+ .initiator_key_distribution = 0x03,
+ .responder_key_distribution = 0x03},
+
+ .remotely_initiated = false,
+ .remote_connection_address = {{}, hci::AddressType::RANDOM_DEVICE_ADDRESS},
+ .ui_handler = &uiMock,
+ .le_security_interface = &leSecurityMock,
+ .OnPairingFinished = OnPairingFinished,
+};
+
+TEST_F(PairingHandlerUnitTest, test_phase_1_failure) {
+ initial_informations.proper_l2cap_interface = up_buffer_.get();
+ initial_informations.l2cap_handler = handler_;
+
+ std::unique_ptr<PairingHandlerLe> pairing_handler =
+ std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, initial_informations);
+
+ EXPECT_TRUE(WaitForOutgoingL2capPacket());
+ EXPECT_EQ(outgoing_l2cap_packet_->GetCode(), Code::PAIRING_REQUEST);
+
+ EXPECT_CALL(*pairingResult, OnPairingFinished(VariantWith<PairingFailure>(_))).Times(1);
+
+ // SMP will waith for Pairing Response, once bad packet is received, it should stop the Pairing
+ CommandView bad_pairing_response = BuilderToView(PairingRandomBuilder::Create({}));
+ bad_pairing_response.IsValid();
+ pairing_handler->OnCommandView(bad_pairing_response);
+
+ EXPECT_TRUE(WaitForOutgoingL2capPacket());
+ EXPECT_EQ(outgoing_l2cap_packet_->GetCode(), Code::PAIRING_FAILED);
+}
+
+TEST_F(PairingHandlerUnitTest, test_secure_connections_just_works) {
+ initial_informations.proper_l2cap_interface = up_buffer_.get();
+ initial_informations.l2cap_handler = handler_;
+
+ // we keep the pairing_handler as unique_ptr to better mimick how it's used
+ // in the real world
+ std::unique_ptr<PairingHandlerLe> pairing_handler =
+ std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, initial_informations);
+
+ EXPECT_TRUE(WaitForOutgoingL2capPacket());
+ EXPECT_EQ(outgoing_l2cap_packet_->GetCode(), Code::PAIRING_REQUEST);
+ CommandView pairing_request = outgoing_l2cap_packet_.value();
+
+ auto pairing_response = BuilderToView(
+ PairingResponseBuilder::Create(IoCapability::KEYBOARD_DISPLAY, OobDataFlag::NOT_PRESENT,
+ AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc, 16, 0x03, 0x03));
+ pairing_handler->OnCommandView(pairing_response);
+ // Phase 1 finished.
+
+ // pairing public key
+ EXPECT_TRUE(WaitForOutgoingL2capPacket());
+ EXPECT_EQ(Code::PAIRING_PUBLIC_KEY, outgoing_l2cap_packet_->GetCode());
+ EcdhPublicKey my_public_key;
+ auto ppkv = PairingPublicKeyView::Create(outgoing_l2cap_packet_.value());
+ ppkv.IsValid();
+ my_public_key.x = ppkv.GetPublicKeyX();
+ my_public_key.y = ppkv.GetPublicKeyY();
+
+ const auto [private_key, public_key] = GenerateECDHKeyPair();
+
+ pairing_handler->OnCommandView(BuilderToView(PairingPublicKeyBuilder::Create(public_key.x, public_key.y)));
+ // DHKey exchange finished
+ std::array<uint8_t, 32> dhkey = ComputeDHKey(private_key, my_public_key);
+
+ // Phasae 2 Stage 1 start
+ Octet16 ra, rb;
+ ra = rb = {0};
+
+ Octet16 Nb = PairingHandlerLe::GenerateRandom<16>();
+
+ // Compute confirm
+ Octet16 Cb = crypto_toolbox::f4((uint8_t*)my_public_key.x.data(), (uint8_t*)public_key.x.data(), Nb, 0);
+
+ pairing_handler->OnCommandView(BuilderToView(PairingConfirmBuilder::Create(Cb)));
+
+ // random
+ EXPECT_TRUE(WaitForOutgoingL2capPacket());
+ EXPECT_EQ(Code::PAIRING_RANDOM, outgoing_l2cap_packet_->GetCode());
+ auto prv = PairingRandomView::Create(outgoing_l2cap_packet_.value());
+ prv.IsValid();
+ Octet16 Na = prv.GetRandomValue();
+
+ // Compute Ca, compare
+ Octet16 Ca = crypto_toolbox::f4((uint8_t*)my_public_key.x.data(), (uint8_t*)public_key.x.data(), Na, 0);
+
+ EXPECT_EQ(Ca, Cb);
+
+ pairing_handler->OnCommandView(BuilderToView(PairingRandomBuilder::Create(Nb)));
+
+ // Start of authentication stage 2
+ uint8_t a[7];
+ uint8_t b[7];
+ memcpy(b, initial_informations.remote_connection_address.GetAddress().address, 6);
+ b[6] = (uint8_t)initial_informations.remote_connection_address.GetAddressType();
+ memcpy(a, initial_informations.my_connection_address.GetAddress().address, 6);
+ a[6] = (uint8_t)initial_informations.my_connection_address.GetAddressType();
+
+ Octet16 ltk, mac_key;
+ crypto_toolbox::f5(dhkey.data(), Na, Nb, a, b, &mac_key, <k);
+
+ PairingRequestView preqv = PairingRequestView::Create(pairing_request);
+ PairingResponseView prspv = PairingResponseView::Create(pairing_response);
+
+ preqv.IsValid();
+ prspv.IsValid();
+ std::array<uint8_t, 3> iocapA{static_cast<uint8_t>(preqv.GetIoCapability()),
+ static_cast<uint8_t>(preqv.GetOobDataFlag()), preqv.GetAuthReq()};
+ std::array<uint8_t, 3> iocapB{static_cast<uint8_t>(prspv.GetIoCapability()),
+ static_cast<uint8_t>(prspv.GetOobDataFlag()), prspv.GetAuthReq()};
+
+ Octet16 Ea = crypto_toolbox::f6(mac_key, Na, Nb, rb, iocapA.data(), a, b);
+ Octet16 Eb = crypto_toolbox::f6(mac_key, Nb, Na, ra, iocapB.data(), b, a);
+
+ EXPECT_TRUE(WaitForOutgoingL2capPacket());
+ EXPECT_EQ(Code::PAIRING_DH_KEY_CHECK, outgoing_l2cap_packet_->GetCode());
+ auto pdhkcv = PairingDhKeyCheckView::Create(outgoing_l2cap_packet_.value());
+ pdhkcv.IsValid();
+ EXPECT_EQ(pdhkcv.GetDhKeyCheck(), Ea);
+
+ pairing_handler->OnCommandView(BuilderToView(PairingDhKeyCheckBuilder::Create(Eb)));
+
+ // Phase 2 finished
+ // We don't care for the rest of the flow, let it die.
+}
+
+InitialInformations initial_informations_trsi{
+ .my_role = hci::Role::MASTER,
+ .my_connection_address = hci::AddressWithType(),
+
+ .myPairingCapabilities = {.io_capability = IoCapability::NO_INPUT_NO_OUTPUT,
+ .oob_data_flag = OobDataFlag::NOT_PRESENT,
+ .auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+ .maximum_encryption_key_size = 16,
+ .initiator_key_distribution = 0x03,
+ .responder_key_distribution = 0x03},
+
+ .remotely_initiated = true,
+ .remote_connection_address = hci::AddressWithType(),
+ .ui_handler = &uiMock,
+ .le_security_interface = &leSecurityMock,
+ .OnPairingFinished = OnPairingFinished,
+};
+
+/* This test verifies that when remote slave device sends security request , and user
+ * does accept the prompt, we do send pairing request */
+TEST_F(PairingHandlerUnitTest, test_remote_slave_initiating) {
+ initial_informations_trsi.proper_l2cap_interface = up_buffer_.get();
+ initial_informations_trsi.l2cap_handler = handler_;
+
+ std::unique_ptr<PairingHandlerLe> pairing_handler =
+ std::make_unique<PairingHandlerLe>(PairingHandlerLe::ACCEPT_PROMPT, initial_informations_trsi);
+
+ // Simulate user accepting the pairing in UI
+ pairing_handler->OnUiAction(PairingEvent::PAIRING_ACCEPTED, 0x01 /* Non-zero value means success */);
+
+ EXPECT_TRUE(WaitForOutgoingL2capPacket());
+ EXPECT_EQ(Code::PAIRING_REQUEST, outgoing_l2cap_packet_->GetCode());
+
+ // We don't care for the rest of the flow, let it die.
+ pairing_handler.reset();
+}
+
+InitialInformations initial_informations_trmi{
+ .my_role = hci::Role::SLAVE,
+ .my_connection_address = hci::AddressWithType(),
+
+ .myPairingCapabilities = {.io_capability = IoCapability::NO_INPUT_NO_OUTPUT,
+ .oob_data_flag = OobDataFlag::NOT_PRESENT,
+ .auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+ .maximum_encryption_key_size = 16,
+ .initiator_key_distribution = 0x03,
+ .responder_key_distribution = 0x03},
+
+ .remotely_initiated = true,
+ .remote_connection_address = hci::AddressWithType(),
+ .pairing_request = PairingRequestView::Create(BuilderToView(
+ PairingRequestBuilder::Create(IoCapability::NO_INPUT_NO_OUTPUT, OobDataFlag::NOT_PRESENT,
+ AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc, 16, 0x03, 0x03))),
+ .ui_handler = &uiMock,
+ .le_security_interface = &leSecurityMock,
+
+ .OnPairingFinished = OnPairingFinished,
+};
+
+/* This test verifies that when remote device sends pairing request, and user does accept the prompt, we do send proper
+ * reply back */
+TEST_F(PairingHandlerUnitTest, test_remote_master_initiating) {
+ initial_informations_trmi.proper_l2cap_interface = up_buffer_.get();
+ initial_informations_trmi.l2cap_handler = handler_;
+
+ std::unique_ptr<PairingHandlerLe> pairing_handler =
+ std::make_unique<PairingHandlerLe>(PairingHandlerLe::ACCEPT_PROMPT, initial_informations_trmi);
+
+ // Simulate user accepting the pairing in UI
+ pairing_handler->OnUiAction(PairingEvent::PAIRING_ACCEPTED, 0x01 /* Non-zero value means success */);
+
+ EXPECT_TRUE(WaitForOutgoingL2capPacket());
+ EXPECT_EQ(Code::PAIRING_RESPONSE, outgoing_l2cap_packet_->GetCode());
+ // Phase 1 finished.
+
+ // We don't care for the rest of the flow, it's handled in in other tests. let it die.
+ pairing_handler.reset();
+}
+
+} // namespace security
+} // namespace bluetooth
diff --git a/gd/security/record/security_record.h b/gd/security/record/security_record.h
new file mode 100644
index 0000000..0c78113
--- /dev/null
+++ b/gd/security/record/security_record.h
@@ -0,0 +1,60 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <memory>
+
+#include "hci/device.h"
+
+namespace bluetooth {
+namespace security {
+namespace record {
+
+enum BondState { NOT_BONDED, PAIRING, BONDED };
+
+class SecurityRecord {
+ public:
+ SecurityRecord(std::shared_ptr<hci::Device> device) : device_(device), state_(NOT_BONDED) {}
+
+ /**
+ * Returns true if the device is bonded to another device
+ */
+ bool IsBonded() {
+ return state_ == BONDED;
+ }
+
+ /**
+ * Returns true if a device is currently pairing to another device
+ */
+ bool IsPairing() {
+ return state_ == PAIRING;
+ }
+
+ std::shared_ptr<hci::Device> GetDevice() {
+ return device_;
+ }
+
+ private:
+ const std::shared_ptr<hci::Device> device_;
+ BondState state_;
+};
+
+} // namespace record
+} // namespace security
+} // namespace bluetooth
diff --git a/gd/security/security_manager.cc b/gd/security/security_manager.cc
new file mode 100644
index 0000000..40858a9
--- /dev/null
+++ b/gd/security/security_manager.cc
@@ -0,0 +1,58 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "security_manager.h"
+
+#include "os/log.h"
+
+using namespace bluetooth::security;
+
+// Definition of Pure Virtual Destructor
+ISecurityManagerListener::~ISecurityManagerListener() {}
+
+void SecurityManager::Init() {
+ security_handler_->Post(
+ common::BindOnce(&internal::SecurityManagerImpl::Init, common::Unretained(security_manager_impl_)));
+}
+
+void SecurityManager::CreateBond(std::shared_ptr<hci::ClassicDevice> device) {
+ security_handler_->Post(common::BindOnce(&internal::SecurityManagerImpl::CreateBond,
+ common::Unretained(security_manager_impl_),
+ std::forward<std::shared_ptr<hci::ClassicDevice>>(device)));
+}
+
+void SecurityManager::CancelBond(std::shared_ptr<hci::ClassicDevice> device) {
+ security_handler_->Post(common::BindOnce(&internal::SecurityManagerImpl::CancelBond,
+ common::Unretained(security_manager_impl_),
+ std::forward<std::shared_ptr<hci::ClassicDevice>>(device)));
+}
+
+void SecurityManager::RemoveBond(std::shared_ptr<hci::ClassicDevice> device) {
+ security_handler_->Post(common::BindOnce(&internal::SecurityManagerImpl::RemoveBond,
+ common::Unretained(security_manager_impl_),
+ std::forward<std::shared_ptr<hci::ClassicDevice>>(device)));
+}
+
+void SecurityManager::RegisterCallbackListener(ISecurityManagerListener* listener, os::Handler* handler) {
+ security_handler_->Post(common::BindOnce(&internal::SecurityManagerImpl::RegisterCallbackListener,
+ common::Unretained(security_manager_impl_), listener, handler));
+}
+
+void SecurityManager::UnregisterCallbackListener(ISecurityManagerListener* listener) {
+ security_handler_->Post(common::BindOnce(&internal::SecurityManagerImpl::UnregisterCallbackListener,
+ common::Unretained(security_manager_impl_), listener));
+}
diff --git a/gd/security/security_manager.h b/gd/security/security_manager.h
new file mode 100644
index 0000000..d83c8d3
--- /dev/null
+++ b/gd/security/security_manager.h
@@ -0,0 +1,119 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include "hci/address_with_type.h"
+#include "hci/device.h"
+#include "security/internal/security_manager_impl.h"
+
+namespace bluetooth {
+namespace security {
+
+/**
+ * Callback interface from SecurityManager.
+ */
+class ISecurityManagerListener {
+ public:
+ virtual ~ISecurityManagerListener() = 0;
+
+ /**
+ * Called when a device is successfully bonded.
+ *
+ * @param address of the newly bonded device
+ */
+ virtual void OnDeviceBonded(bluetooth::hci::AddressWithType device) = 0;
+
+ /**
+ * Called when a device is successfully un-bonded.
+ *
+ * @param address of device that is no longer bonded
+ */
+ virtual void OnDeviceUnbonded(bluetooth::hci::AddressWithType device) = 0;
+
+ /**
+ * Called as a result of a failure during the bonding process.
+ *
+ * @param address of the device that failed to bond
+ */
+ virtual void OnDeviceBondFailed(bluetooth::hci::AddressWithType device) = 0;
+};
+
+/**
+ * Manages the security attributes, pairing, bonding of devices, and the
+ * encryption/decryption of communications.
+ */
+class SecurityManager {
+ public:
+ friend class SecurityModule;
+
+ /**
+ * Initialize the security record map from an internal device database.
+ */
+ void Init();
+
+ /**
+ * Checks the device for existing bond, if not bonded, initiates pairing.
+ *
+ * @param device pointer to device we want to bond with
+ */
+ void CreateBond(std::shared_ptr<hci::ClassicDevice> device);
+
+ /**
+ * Cancels the pairing process for this device.
+ *
+ * @param device pointer to device with which we want to cancel our bond
+ */
+ void CancelBond(std::shared_ptr<bluetooth::hci::ClassicDevice> device);
+
+ /**
+ * Disassociates the device and removes the persistent LTK
+ *
+ * @param device pointer to device we want to forget
+ */
+ void RemoveBond(std::shared_ptr<bluetooth::hci::ClassicDevice> device);
+
+ /**
+ * Register to listen for callback events from SecurityManager
+ *
+ * @param listener ISecurityManagerListener instance to handle callbacks
+ */
+ void RegisterCallbackListener(ISecurityManagerListener* listener, os::Handler* handler);
+
+ /**
+ * Unregister listener for callback events from SecurityManager
+ *
+ * @param listener ISecurityManagerListener instance to unregister
+ */
+ void UnregisterCallbackListener(ISecurityManagerListener* listener);
+
+ protected:
+ SecurityManager(os::Handler* security_handler, internal::SecurityManagerImpl* security_manager_impl)
+ : security_handler_(security_handler), security_manager_impl_(security_manager_impl) {}
+
+ private:
+ os::Handler* security_handler_ = nullptr;
+ internal::SecurityManagerImpl* security_manager_impl_;
+ DISALLOW_COPY_AND_ASSIGN(SecurityManager);
+};
+
+} // namespace security
+} // namespace bluetooth
diff --git a/gd/security/security_module.cc b/gd/security/security_module.cc
new file mode 100644
index 0000000..58b1f8c
--- /dev/null
+++ b/gd/security/security_module.cc
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#define LOG_TAG "security"
+
+#include <memory>
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+
+#include "hci/hci_layer.h"
+#include "l2cap/le/l2cap_le_module.h"
+#include "security/channel/security_manager_channel.h"
+#include "security/internal/security_manager_impl.h"
+#include "security/security_module.h"
+
+namespace bluetooth {
+namespace security {
+
+const ModuleFactory SecurityModule::Factory = ModuleFactory([]() { return new SecurityModule(); });
+
+struct SecurityModule::impl {
+ impl(os::Handler* security_handler, l2cap::le::L2capLeModule* l2cap_le_module,
+ l2cap::classic::L2capClassicModule* l2cap_classic_module, hci::HciLayer* hci_layer)
+ : security_handler_(security_handler), l2cap_le_module_(l2cap_le_module),
+ l2cap_classic_module_(l2cap_classic_module),
+ security_manager_channel_(new channel::SecurityManagerChannel(security_handler_, hci_layer)) {}
+
+ os::Handler* security_handler_;
+ l2cap::le::L2capLeModule* l2cap_le_module_;
+ l2cap::classic::L2capClassicModule* l2cap_classic_module_;
+ channel::SecurityManagerChannel* security_manager_channel_;
+ internal::SecurityManagerImpl security_manager_impl{security_handler_, l2cap_le_module_, l2cap_classic_module_,
+ security_manager_channel_};
+};
+
+void SecurityModule::ListDependencies(ModuleList* list) {
+ list->add<l2cap::le::L2capLeModule>();
+ list->add<l2cap::classic::L2capClassicModule>();
+ list->add<hci::HciLayer>();
+}
+
+void SecurityModule::Start() {
+ pimpl_ = std::make_unique<impl>(GetHandler(), GetDependency<l2cap::le::L2capLeModule>(),
+ GetDependency<l2cap::classic::L2capClassicModule>(), GetDependency<hci::HciLayer>());
+}
+
+void SecurityModule::Stop() {
+ pimpl_.reset();
+}
+
+std::string SecurityModule::ToString() const {
+ return "Security Module";
+}
+
+std::unique_ptr<SecurityManager> SecurityModule::GetSecurityManager() {
+ return std::unique_ptr<SecurityManager>(
+ new SecurityManager(pimpl_->security_handler_, &pimpl_->security_manager_impl));
+}
+
+} // namespace security
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/security/security_module.h b/gd/security/security_module.h
new file mode 100644
index 0000000..2ec456d
--- /dev/null
+++ b/gd/security/security_module.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <memory>
+
+#include "module.h"
+#include "security/security_manager.h"
+
+namespace bluetooth {
+namespace security {
+
+class SecurityModule : public bluetooth::Module {
+ public:
+ SecurityModule() = default;
+ ~SecurityModule() = default;
+
+ /**
+ * Get the api to the SecurityManager
+ */
+ std::unique_ptr<SecurityManager> GetSecurityManager();
+
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override;
+
+ void Start() override;
+
+ void Stop() override;
+
+ std::string ToString() const override;
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+ DISALLOW_COPY_AND_ASSIGN(SecurityModule);
+};
+
+} // namespace security
+} // namespace bluetooth
diff --git a/gd/security/smp_packets.pdl b/gd/security/smp_packets.pdl
new file mode 100644
index 0000000..69269dd
--- /dev/null
+++ b/gd/security/smp_packets.pdl
@@ -0,0 +1,142 @@
+little_endian_packets
+
+custom_field Address : 48 "hci/"
+
+enum Code : 8 {
+ PAIRING_REQUEST = 0x01,
+ PAIRING_RESPONSE = 0x02,
+ PAIRING_CONFIRM = 0x03,
+ PAIRING_RANDOM = 0x04,
+ PAIRING_FAILED = 0x05,
+ ENCRYPTION_INFORMATION = 0x06,
+ MASTER_IDENTIFICATION = 0x07,
+ IDENTITY_INFORMATION = 0x08,
+ IDENTITY_ADDRESS_INFORMATION = 0x09,
+ SIGNING_INFORMATION = 0x0A,
+ SECURITY_REQUEST = 0x0B,
+ PAIRING_PUBLIC_KEY = 0x0C,
+ PAIRING_DH_KEY_CHECK = 0x0D,
+ PAIRING_KEYPRESS_NOTIFICATION = 0x0E,
+}
+
+packet Command {
+ code : Code,
+ _payload_,
+}
+
+enum IoCapability : 8 {
+ DISPLAY_ONLY = 0x00,
+ DISPLAY_YES_NO = 0x01,
+ KEYBOARD_ONLY = 0x02,
+ NO_INPUT_NO_OUTPUT = 0x03,
+ KEYBOARD_DISPLAY = 0x04,
+}
+
+enum OobDataFlag : 8 {
+ NOT_PRESENT = 0x00,
+ PRESENT = 0x01,
+}
+
+enum BondingFlags : 2 {
+ NO_BONDING = 0,
+ BONDING = 1,
+}
+
+group PairingInfo {
+ io_capability : IoCapability,
+ oob_data_flag : OobDataFlag,
+ auth_req: 8,
+ maximum_encryption_key_size : 5, // 7 - 16
+ _reserved_ : 3,
+ initiator_key_distribution : 8,
+ responder_key_distribution : 8,
+}
+
+packet PairingRequest : Command (code = PAIRING_REQUEST) {
+ PairingInfo,
+}
+
+packet PairingResponse : Command (code = PAIRING_RESPONSE) {
+ PairingInfo,
+}
+
+packet PairingConfirm : Command (code = PAIRING_CONFIRM) {
+ confirm_value : 8[16], // Initiating device sends Mconfirm, responding device sends Sconfirm
+}
+
+packet PairingRandom : Command (code = PAIRING_RANDOM) {
+ random_value : 8[16], // Initiating device sends Mrand, responding device sends Srand
+}
+
+enum PairingFailedReason : 8 {
+ PASSKEY_ENTRY_FAILED = 0x01,
+ OOB_NOT_AVAILABLE = 0x02,
+ AUTHENTICATION_REQUIREMENTS = 0x03,
+ CONFIRM_VALUE_FAILED = 0x04,
+ PAIRING_NOT_SUPPORTED = 0x05,
+ ENCRYPTION_KEY_SIZE = 0x06,
+ COMMAND_NOT_SUPPORTED = 0x07,
+ UNSPECIFIED_REASON = 0x08,
+ REPEATED_ATTEMPTS = 0x09,
+ INVALID_PARAMETERS = 0x0A,
+ DHKEY_CHECK_FAILED = 0x0B,
+ NUMERIC_COMPARISON_FAILED = 0x0C,
+ BR_EDR_PAIRING_IN_PROGRESS = 0x0D,
+ CROSS_TRANSPORT_KEY_DERIVATION_NOT_ALLOWED = 0x0E,
+}
+
+packet PairingFailed : Command (code = PAIRING_FAILED) {
+ reason : PairingFailedReason,
+}
+
+packet EncryptionInformation : Command (code = ENCRYPTION_INFORMATION) {
+ long_term_key : 8[16],
+}
+
+packet MasterIdentification : Command (code = MASTER_IDENTIFICATION) {
+ ediv : 16,
+ rand : 8[8],
+}
+
+packet IdentityInformation : Command (code = IDENTITY_INFORMATION) {
+ identity_resolving_key : 8[16],
+}
+
+enum AddrType : 8 {
+ PUBLIC = 0x00,
+ STATIC_RANDOM = 0x01,
+}
+
+packet IdentityAddressInformation : Command (code = IDENTITY_ADDRESS_INFORMATION) {
+ addr_type : AddrType,
+ bd_addr : Address,
+}
+
+packet SigningInformation : Command (code = SIGNING_INFORMATION) {
+ signature_key : 8[16],
+}
+
+packet SecurityRequest : Command (code = SECURITY_REQUEST) {
+ auth_req: 8,
+}
+
+packet PairingPublicKey : Command (code = PAIRING_PUBLIC_KEY) {
+ public_key_x : 8[32],
+ public_key_y : 8[32],
+}
+
+packet PairingDhKeyCheck : Command (code = PAIRING_DH_KEY_CHECK) {
+ dh_key_check : 8[16],
+}
+
+enum KeypressNotificationType : 8 {
+ ENTRY_STARTED = 0,
+ DIGIT_ENTERED = 1,
+ DIGIT_ERASED = 2,
+ CLEARED = 3,
+ ENTRY_COMPLETED = 4,
+}
+
+packet PairingKeypressNotification : Command (code = PAIRING_KEYPRESS_NOTIFICATION) {
+ notification_type : KeypressNotificationType,
+}
diff --git a/gd/security/test/fake_hci_layer.h b/gd/security/test/fake_hci_layer.h
new file mode 100644
index 0000000..84eff90
--- /dev/null
+++ b/gd/security/test/fake_hci_layer.h
@@ -0,0 +1,115 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 "common/bind.h"
+#include "hci/hci_layer.h"
+
+namespace bluetooth {
+namespace security {
+
+using common::OnceCallback;
+using hci::CommandCompleteView;
+using hci::CommandPacketBuilder;
+using hci::CommandStatusView;
+using hci::EventCode;
+using hci::EventPacketBuilder;
+using hci::EventPacketView;
+using hci::HciLayer;
+using os::Handler;
+
+namespace {
+
+PacketView<kLittleEndian> GetPacketView(std::unique_ptr<packet::BasePacketBuilder> packet) {
+ auto bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter i(*bytes);
+ bytes->reserve(packet->size());
+ packet->Serialize(i);
+ return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+class CommandQueueEntry {
+ public:
+ CommandQueueEntry(std::unique_ptr<CommandPacketBuilder> command_packet,
+ OnceCallback<void(CommandCompleteView)> on_complete_function, Handler* handler)
+ : command(std::move(command_packet)), waiting_for_status_(false), on_complete(std::move(on_complete_function)),
+ caller_handler(handler) {}
+
+ CommandQueueEntry(std::unique_ptr<CommandPacketBuilder> command_packet,
+ OnceCallback<void(CommandStatusView)> on_status_function, Handler* handler)
+ : command(std::move(command_packet)), waiting_for_status_(true), on_status(std::move(on_status_function)),
+ caller_handler(handler) {}
+
+ std::unique_ptr<CommandPacketBuilder> command;
+ bool waiting_for_status_;
+ OnceCallback<void(CommandStatusView)> on_status;
+ OnceCallback<void(CommandCompleteView)> on_complete;
+ Handler* caller_handler;
+};
+
+} // namespace
+
+class FakeHciLayer : public HciLayer {
+ public:
+ void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command, OnceCallback<void(CommandStatusView)> on_status,
+ Handler* handler) override {
+ auto command_queue_entry = std::make_unique<CommandQueueEntry>(std::move(command), std::move(on_status), handler);
+ command_queue_.push(std::move(command_queue_entry));
+ }
+
+ void EnqueueCommand(std::unique_ptr<CommandPacketBuilder> command,
+ OnceCallback<void(CommandCompleteView)> on_complete, Handler* handler) override {
+ auto command_queue_entry = std::make_unique<CommandQueueEntry>(std::move(command), std::move(on_complete), handler);
+ command_queue_.push(std::move(command_queue_entry));
+ }
+
+ std::unique_ptr<CommandQueueEntry> GetLastCommand() {
+ EXPECT_FALSE(command_queue_.empty());
+ auto last = std::move(command_queue_.front());
+ command_queue_.pop();
+ return last;
+ }
+
+ void RegisterEventHandler(EventCode event_code, common::Callback<void(EventPacketView)> event_handler,
+ Handler* handler) override {
+ registered_events_[event_code] = event_handler;
+ }
+
+ void UnregisterEventHandler(EventCode event_code) override {
+ registered_events_.erase(event_code);
+ }
+
+ void IncomingEvent(std::unique_ptr<EventPacketBuilder> event_builder) {
+ auto packet = GetPacketView(std::move(event_builder));
+ EventPacketView event = EventPacketView::Create(packet);
+ ASSERT_TRUE(event.IsValid());
+ EventCode event_code = event.GetEventCode();
+ EXPECT_TRUE(registered_events_.find(event_code) != registered_events_.end());
+ registered_events_[event_code].Run(event);
+ }
+
+ void ListDependencies(ModuleList* list) override {}
+ void Start() override {}
+ void Stop() override {}
+
+ private:
+ std::map<EventCode, common::Callback<void(EventPacketView)>> registered_events_;
+ std::queue<std::unique_ptr<CommandQueueEntry>> command_queue_;
+};
+
+} // namespace security
+} // namespace bluetooth
diff --git a/gd/security/test/fake_l2cap_test.cc b/gd/security/test/fake_l2cap_test.cc
new file mode 100644
index 0000000..2d885e7
--- /dev/null
+++ b/gd/security/test/fake_l2cap_test.cc
@@ -0,0 +1,131 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <memory>
+
+#include "hci/le_security_interface.h"
+#include "packet/raw_builder.h"
+#include "security/pairing_handler_le.h"
+#include "security/test/mocks.h"
+
+#include "os/handler.h"
+#include "os/queue.h"
+#include "os/thread.h"
+
+using namespace std::chrono_literals;
+using testing::_;
+using testing::Invoke;
+using testing::InvokeWithoutArgs;
+using testing::Matcher;
+using testing::SaveArg;
+
+using bluetooth::hci::CommandCompleteView;
+using bluetooth::hci::CommandStatusView;
+using bluetooth::hci::EncryptionChangeBuilder;
+using bluetooth::hci::EncryptionEnabled;
+using bluetooth::hci::ErrorCode;
+using bluetooth::hci::EventPacketBuilder;
+using bluetooth::hci::EventPacketView;
+using bluetooth::hci::LeSecurityCommandBuilder;
+
+namespace bluetooth {
+namespace security {
+
+namespace {
+
+template <class T>
+PacketView<kLittleEndian> GetPacketView(std::unique_ptr<T> packet) {
+ auto bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter i(*bytes);
+ bytes->reserve(packet->size());
+ packet->Serialize(i);
+ return packet::PacketView<packet::kLittleEndian>(bytes);
+}
+
+void sync_handler(os::Handler* handler) {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ handler->Post(common::BindOnce(&std::promise<void>::set_value, common::Unretained(&promise)));
+ auto status = future.wait_for(std::chrono::milliseconds(3));
+ EXPECT_EQ(status, std::future_status::ready);
+}
+} // namespace
+
+class FakeL2capTest : public testing::Test {
+ protected:
+ void SetUp() {}
+
+ void TearDown() {}
+
+ public:
+};
+
+void my_enqueue_callback() {
+ LOG_INFO("packet ready for dequeue!");
+}
+
+/* This test verifies that Just Works pairing flow works.
+ * Both simulated devices specify capabilities as NO_INPUT_NO_OUTPUT, and secure connecitons support */
+TEST_F(FakeL2capTest, test_bidi_queue_example) {
+ os::Thread* thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+ os::Handler* handler_ = new os::Handler(thread_);
+
+ common::BidiQueue<packet::BasePacketBuilder, packet::PacketView<packet::kLittleEndian>> bidi_queue{10};
+
+ os::EnqueueBuffer<packet::BasePacketBuilder> enqueue_buffer{bidi_queue.GetDownEnd()};
+
+ // This is test packet we are sending down the queue to the other end;
+ auto test_packet = EncryptionChangeBuilder::Create(ErrorCode::SUCCESS, 0x0020, EncryptionEnabled::ON);
+
+ // send the packet through the queue
+ enqueue_buffer.Enqueue(std::move(test_packet), handler_);
+
+ // give queue some time to push the packet through
+ sync_handler(handler_);
+
+ // packet is through the queue, receive it on the other end.
+ auto test_packet_from_other_end = bidi_queue.GetUpEnd()->TryDequeue();
+
+ EXPECT_TRUE(test_packet_from_other_end != nullptr);
+
+ // This is how we receive data
+ os::EnqueueBuffer<packet::PacketView<packet::kLittleEndian>> up_end_enqueue_buffer{bidi_queue.GetUpEnd()};
+ bidi_queue.GetDownEnd()->RegisterDequeue(handler_, common::Bind(&my_enqueue_callback));
+
+ auto packet_one = std::make_unique<packet::RawBuilder>();
+ packet_one->AddOctets({1, 2, 3});
+
+ up_end_enqueue_buffer.Enqueue(std::make_unique<PacketView<kLittleEndian>>(GetPacketView(std::move(packet_one))),
+ handler_);
+
+ sync_handler(handler_);
+
+ auto other_end_packet = bidi_queue.GetDownEnd()->TryDequeue();
+ EXPECT_TRUE(other_end_packet != nullptr);
+
+ bidi_queue.GetDownEnd()->UnregisterDequeue();
+ handler_->Clear();
+ delete handler_;
+ delete thread_;
+}
+
+} // namespace security
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/security/test/mocks.h b/gd/security/test/mocks.h
new file mode 100644
index 0000000..812c9a1
--- /dev/null
+++ b/gd/security/test/mocks.h
@@ -0,0 +1,56 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "hci/address.h"
+#include "hci/le_security_interface.h"
+#include "security/ui.h"
+
+namespace bluetooth {
+namespace security {
+
+class UIMock : public UI {
+ public:
+ UIMock() {}
+ ~UIMock() override = default;
+
+ MOCK_METHOD2(DisplayPairingPrompt, void(const bluetooth::hci::AddressWithType&, std::string&));
+ MOCK_METHOD1(CancelPairingPrompt, void(const bluetooth::hci::AddressWithType&));
+ MOCK_METHOD1(DisplayConfirmValue, void(uint32_t));
+ MOCK_METHOD0(DisplayEnterPasskeyDialog, void());
+ MOCK_METHOD1(DisplayPasskey, void(uint32_t));
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(UIMock);
+};
+
+class LeSecurityInterfaceMock : public hci::LeSecurityInterface {
+ public:
+ MOCK_METHOD3(EnqueueCommand,
+ void(std::unique_ptr<hci::LeSecurityCommandBuilder> command,
+ common::OnceCallback<void(hci::CommandCompleteView)> on_complete, os::Handler* handler));
+ MOCK_METHOD3(EnqueueCommand,
+ void(std::unique_ptr<hci::LeSecurityCommandBuilder> command,
+ common::OnceCallback<void(hci::CommandStatusView)> on_status, os::Handler* handler));
+};
+
+} // namespace security
+} // namespace bluetooth
\ No newline at end of file
diff --git a/gd/security/test/pairing_handler_le_pair_test.cc b/gd/security/test/pairing_handler_le_pair_test.cc
new file mode 100644
index 0000000..1bed89c
--- /dev/null
+++ b/gd/security/test/pairing_handler_le_pair_test.cc
@@ -0,0 +1,638 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <memory>
+
+#include "common/testing/wired_pair_of_bidi_queues.h"
+#include "hci/le_security_interface.h"
+#include "packet/raw_builder.h"
+#include "security/pairing_handler_le.h"
+#include "security/test/mocks.h"
+
+using namespace std::chrono_literals;
+using testing::_;
+using testing::Invoke;
+using testing::InvokeWithoutArgs;
+using testing::Matcher;
+using testing::SaveArg;
+
+using bluetooth::hci::Address;
+using bluetooth::hci::AddressType;
+using bluetooth::hci::CommandCompleteView;
+using bluetooth::hci::CommandStatusView;
+using bluetooth::hci::EncryptionChangeBuilder;
+using bluetooth::hci::EncryptionEnabled;
+using bluetooth::hci::ErrorCode;
+using bluetooth::hci::EventPacketBuilder;
+using bluetooth::hci::EventPacketView;
+using bluetooth::hci::LeSecurityCommandBuilder;
+
+// run:
+// out/host/linux-x86/nativetest/bluetooth_test_gd/bluetooth_test_gd --gtest_filter=Pairing*
+// adb shell /data/nativetest/bluetooth_test_gd/bluetooth_test_gd --gtest_filter=PairingHandlerPairTest.*
+// --gtest_repeat=10 --gtest_shuffle
+
+namespace bluetooth {
+namespace security {
+CommandView CommandBuilderToView(std::unique_ptr<BasePacketBuilder> builder) {
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ builder->Serialize(it);
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto temp_cmd_view = CommandView::Create(packet_bytes_view);
+ return CommandView::Create(temp_cmd_view);
+}
+
+EventPacketView EventBuilderToView(std::unique_ptr<EventPacketBuilder> builder) {
+ std::shared_ptr<std::vector<uint8_t>> packet_bytes = std::make_shared<std::vector<uint8_t>>();
+ BitInserter it(*packet_bytes);
+ builder->Serialize(it);
+ PacketView<kLittleEndian> packet_bytes_view(packet_bytes);
+ auto temp_evt_view = EventPacketView::Create(packet_bytes_view);
+ return EventPacketView::Create(temp_evt_view);
+}
+} // namespace security
+} // namespace bluetooth
+
+namespace {
+
+constexpr uint16_t CONN_HANDLE_MASTER = 0x31, CONN_HANDLE_SLAVE = 0x32;
+std::unique_ptr<bluetooth::security::PairingHandlerLe> pairing_handler_a, pairing_handler_b;
+
+} // namespace
+
+namespace bluetooth {
+namespace security {
+
+namespace {
+Address ADDRESS_MASTER{{0x26, 0x64, 0x76, 0x86, 0xab, 0xba}};
+AddressType ADDRESS_TYPE_MASTER = AddressType::RANDOM_DEVICE_ADDRESS;
+
+Address ADDRESS_SLAVE{{0x33, 0x58, 0x24, 0x76, 0x11, 0x89}};
+AddressType ADDRESS_TYPE_SLAVE = AddressType::RANDOM_DEVICE_ADDRESS;
+
+std::optional<PairingResultOrFailure> pairing_result_master;
+std::optional<PairingResultOrFailure> pairing_result_slave;
+
+void OnPairingFinishedMaster(PairingResultOrFailure r) {
+ pairing_result_master = r;
+ if (std::holds_alternative<PairingResult>(r)) {
+ LOG_INFO("pairing finished successfully with %s", std::get<PairingResult>(r).connection_address.ToString().c_str());
+ } else {
+ LOG_INFO("pairing with ... failed: %s", std::get<PairingFailure>(r).message.c_str());
+ }
+}
+
+void OnPairingFinishedSlave(PairingResultOrFailure r) {
+ pairing_result_slave = r;
+ if (std::holds_alternative<PairingResult>(r)) {
+ LOG_INFO("pairing finished successfully with %s", std::get<PairingResult>(r).connection_address.ToString().c_str());
+ } else {
+ LOG_INFO("pairing with ... failed: %s", std::get<PairingFailure>(r).message.c_str());
+ }
+}
+
+}; // namespace
+
+// We obtain this mutex when we start initializing the handlers, and relese it when both handlers are initialized
+std::mutex handlers_initialization_guard;
+
+class PairingHandlerPairTest : public testing::Test {
+ void dequeue_callback_master() {
+ auto packet_bytes_view = l2cap_->GetQueueAUpEnd()->TryDequeue();
+ if (!packet_bytes_view) LOG_ERROR("Received dequeue, but no data ready...");
+
+ auto temp_cmd_view = CommandView::Create(*packet_bytes_view);
+ if (!first_command_sent) {
+ first_command = std::make_unique<CommandView>(CommandView::Create(temp_cmd_view));
+ first_command_sent = true;
+ return;
+ }
+
+ if (!pairing_handler_a) LOG_ALWAYS_FATAL("Slave handler not initlized yet!");
+
+ pairing_handler_a->OnCommandView(CommandView::Create(temp_cmd_view));
+ }
+
+ void dequeue_callback_slave() {
+ auto packet_bytes_view = l2cap_->GetQueueBUpEnd()->TryDequeue();
+ if (!packet_bytes_view) LOG_ERROR("Received dequeue, but no data ready...");
+
+ auto temp_cmd_view = CommandView::Create(*packet_bytes_view);
+ if (!first_command_sent) {
+ first_command = std::make_unique<CommandView>(CommandView::Create(temp_cmd_view));
+ first_command_sent = true;
+ return;
+ }
+
+ if (!pairing_handler_b) LOG_ALWAYS_FATAL("Master handler not initlized yet!");
+
+ pairing_handler_b->OnCommandView(CommandView::Create(temp_cmd_view));
+ }
+
+ protected:
+ void SetUp() {
+ thread_ = new os::Thread("test_thread", os::Thread::Priority::NORMAL);
+ handler_ = new os::Handler(thread_);
+
+ l2cap_ = new common::testing::WiredPairOfL2capQueues(handler_);
+ // master sends it's packet into l2cap->down_buffer_b_
+ // slave sends it's packet into l2cap->down_buffer_a_
+ l2cap_->GetQueueAUpEnd()->RegisterDequeue(
+ handler_, common::Bind(&PairingHandlerPairTest::dequeue_callback_master, common::Unretained(this)));
+ l2cap_->GetQueueBUpEnd()->RegisterDequeue(
+ handler_, common::Bind(&PairingHandlerPairTest::dequeue_callback_slave, common::Unretained(this)));
+
+ up_buffer_a_ = std::make_unique<os::EnqueueBuffer<packet::BasePacketBuilder>>(l2cap_->GetQueueAUpEnd());
+ up_buffer_b_ = std::make_unique<os::EnqueueBuffer<packet::BasePacketBuilder>>(l2cap_->GetQueueBUpEnd());
+
+ master_setup = {
+ .my_role = hci::Role::MASTER,
+ .my_connection_address = {ADDRESS_MASTER, ADDRESS_TYPE_MASTER},
+
+ .myPairingCapabilities = {.io_capability = IoCapability::NO_INPUT_NO_OUTPUT,
+ .oob_data_flag = OobDataFlag::NOT_PRESENT,
+ .auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+ .maximum_encryption_key_size = 16,
+ .initiator_key_distribution = KeyMaskId | KeyMaskSign,
+ .responder_key_distribution = KeyMaskId | KeyMaskSign},
+
+ .remotely_initiated = false,
+ .connection_handle = CONN_HANDLE_MASTER,
+ .remote_connection_address = {ADDRESS_SLAVE, ADDRESS_TYPE_SLAVE},
+ .ui_handler = &master_ui_handler,
+ .le_security_interface = &master_le_security_mock,
+ .proper_l2cap_interface = up_buffer_a_.get(),
+ .l2cap_handler = handler_,
+ .OnPairingFinished = OnPairingFinishedMaster,
+ };
+
+ slave_setup = {
+ .my_role = hci::Role::SLAVE,
+
+ .my_connection_address = {ADDRESS_SLAVE, ADDRESS_TYPE_SLAVE},
+ .myPairingCapabilities = {.io_capability = IoCapability::NO_INPUT_NO_OUTPUT,
+ .oob_data_flag = OobDataFlag::NOT_PRESENT,
+ .auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+ .maximum_encryption_key_size = 16,
+ .initiator_key_distribution = KeyMaskId | KeyMaskSign,
+ .responder_key_distribution = KeyMaskId | KeyMaskSign},
+ .remotely_initiated = true,
+ .connection_handle = CONN_HANDLE_SLAVE,
+ .remote_connection_address = {ADDRESS_MASTER, ADDRESS_TYPE_MASTER},
+ .ui_handler = &slave_ui_handler,
+ .le_security_interface = &slave_le_security_mock,
+ .proper_l2cap_interface = up_buffer_b_.get(),
+ .l2cap_handler = handler_,
+ .OnPairingFinished = OnPairingFinishedSlave,
+ };
+
+ RecordSuccessfulEncryptionComplete();
+ }
+
+ void TearDown() {
+ ::testing::Mock::VerifyAndClearExpectations(&slave_ui_handler);
+ ::testing::Mock::VerifyAndClearExpectations(&master_ui_handler);
+ ::testing::Mock::VerifyAndClearExpectations(&slave_le_security_mock);
+ ::testing::Mock::VerifyAndClearExpectations(&master_le_security_mock);
+
+ pairing_handler_a.reset();
+ pairing_handler_b.reset();
+ pairing_result_master.reset();
+ pairing_result_slave.reset();
+
+ first_command_sent = false;
+ first_command.reset();
+
+ l2cap_->GetQueueAUpEnd()->UnregisterDequeue();
+ l2cap_->GetQueueBUpEnd()->UnregisterDequeue();
+
+ delete l2cap_;
+ handler_->Clear();
+ delete handler_;
+ delete thread_;
+ }
+
+ void RecordPairingPromptHandling(UIMock& ui_mock, std::unique_ptr<PairingHandlerLe>* handler) {
+ EXPECT_CALL(ui_mock, DisplayPairingPrompt(_, _)).Times(1).WillOnce(InvokeWithoutArgs([handler]() {
+ LOG_INFO("UI mock received pairing prompt");
+
+ {
+ // By grabbing the lock, we ensure initialization of both pairing handlers is finished.
+ std::lock_guard<std::mutex> lock(handlers_initialization_guard);
+ }
+
+ if (!(*handler)) LOG_ALWAYS_FATAL("handler not initalized yet!");
+ // Simulate user accepting the pairing in UI
+ (*handler)->OnUiAction(PairingEvent::PAIRING_ACCEPTED, 0x01 /* Non-zero value means success */);
+ }));
+ }
+
+ void RecordSuccessfulEncryptionComplete() {
+ // For now, all tests are succeeding to go through Encryption. Record that in the setup.
+ // Once we test failure cases, move this to each test
+ EXPECT_CALL(master_le_security_mock,
+ EnqueueCommand(_, Matcher<common::OnceCallback<void(CommandStatusView)>>(_), _))
+ .Times(1)
+ .WillOnce([](std::unique_ptr<LeSecurityCommandBuilder> command,
+ common::OnceCallback<void(CommandStatusView)> on_status, os::Handler* handler) {
+ // TODO: on_status.Run();
+
+ pairing_handler_a->OnHciEvent(EventBuilderToView(
+ EncryptionChangeBuilder::Create(ErrorCode::SUCCESS, CONN_HANDLE_MASTER, EncryptionEnabled::ON)));
+
+ pairing_handler_b->OnHciEvent(EventBuilderToView(
+ EncryptionChangeBuilder::Create(ErrorCode::SUCCESS, CONN_HANDLE_SLAVE, EncryptionEnabled::ON)));
+ });
+ }
+
+ public:
+ std::unique_ptr<bluetooth::security::CommandView> WaitFirstL2capCommand() {
+ while (!first_command_sent) {
+ std::this_thread::sleep_for(1ms);
+ LOG_INFO("waiting for first command...");
+ }
+
+ return std::move(first_command);
+ }
+
+ InitialInformations master_setup;
+ InitialInformations slave_setup;
+ UIMock master_ui_handler;
+ UIMock slave_ui_handler;
+ LeSecurityInterfaceMock master_le_security_mock;
+ LeSecurityInterfaceMock slave_le_security_mock;
+
+ uint16_t first_command_sent = false;
+ std::unique_ptr<bluetooth::security::CommandView> first_command;
+
+ os::Thread* thread_;
+ os::Handler* handler_;
+ common::testing::WiredPairOfL2capQueues* l2cap_;
+
+ std::unique_ptr<os::EnqueueBuffer<packet::BasePacketBuilder>> up_buffer_a_;
+ std::unique_ptr<os::EnqueueBuffer<packet::BasePacketBuilder>> up_buffer_b_;
+};
+
+/* This test verifies that Just Works pairing flow works.
+ * Both simulated devices specify capabilities as NO_INPUT_NO_OUTPUT, and secure connecitons support */
+TEST_F(PairingHandlerPairTest, test_secure_connections_just_works) {
+ master_setup.myPairingCapabilities.io_capability = IoCapability::NO_INPUT_NO_OUTPUT;
+ master_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+ slave_setup.myPairingCapabilities.io_capability = IoCapability::NO_INPUT_NO_OUTPUT;
+ slave_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+
+ {
+ std::unique_lock<std::mutex> lock(handlers_initialization_guard);
+
+ pairing_handler_a = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, master_setup);
+
+ auto first_pkt = WaitFirstL2capCommand();
+ slave_setup.pairing_request = PairingRequestView::Create(*first_pkt);
+
+ EXPECT_CALL(slave_ui_handler, DisplayPairingPrompt(_, _)).Times(1).WillOnce(InvokeWithoutArgs([] {
+ LOG_INFO("UI mock received pairing prompt");
+
+ {
+ // By grabbing the lock, we ensure initialization of both pairing handlers is finished.
+ std::lock_guard<std::mutex> lock(handlers_initialization_guard);
+ }
+
+ if (!pairing_handler_b) LOG_ALWAYS_FATAL("handler not initalized yet!");
+
+ // Simulate user accepting the pairing in UI
+ pairing_handler_b->OnUiAction(PairingEvent::PAIRING_ACCEPTED, 0x01 /* Non-zero value means success */);
+ }));
+
+ pairing_handler_b = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, slave_setup);
+ }
+
+ pairing_handler_a->WaitUntilPairingFinished();
+ pairing_handler_b->WaitUntilPairingFinished();
+
+ EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_master.value()));
+ EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_slave.value()));
+}
+
+TEST_F(PairingHandlerPairTest, test_secure_connections_just_works_slave_initiated) {
+ master_setup = {
+ .my_role = hci::Role::MASTER,
+ .my_connection_address = {ADDRESS_MASTER, ADDRESS_TYPE_MASTER},
+ .myPairingCapabilities = {.io_capability = IoCapability::NO_INPUT_NO_OUTPUT,
+ .oob_data_flag = OobDataFlag::NOT_PRESENT,
+ .auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+ .maximum_encryption_key_size = 16,
+ .initiator_key_distribution = KeyMaskId | KeyMaskSign,
+ .responder_key_distribution = KeyMaskId | KeyMaskSign},
+ .remotely_initiated = true,
+ .connection_handle = CONN_HANDLE_MASTER,
+ .remote_connection_address = {ADDRESS_SLAVE, ADDRESS_TYPE_SLAVE},
+ .ui_handler = &master_ui_handler,
+ .le_security_interface = &master_le_security_mock,
+ .proper_l2cap_interface = up_buffer_a_.get(),
+ .l2cap_handler = handler_,
+ .OnPairingFinished = OnPairingFinishedMaster,
+ };
+
+ slave_setup = {
+ .my_role = hci::Role::SLAVE,
+ .my_connection_address = {ADDRESS_SLAVE, ADDRESS_TYPE_SLAVE},
+ .myPairingCapabilities = {.io_capability = IoCapability::NO_INPUT_NO_OUTPUT,
+ .oob_data_flag = OobDataFlag::NOT_PRESENT,
+ .auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+ .maximum_encryption_key_size = 16,
+ .initiator_key_distribution = KeyMaskId | KeyMaskSign,
+ .responder_key_distribution = KeyMaskId | KeyMaskSign},
+ .remotely_initiated = false,
+ .connection_handle = CONN_HANDLE_SLAVE,
+ .remote_connection_address = {ADDRESS_MASTER, ADDRESS_TYPE_MASTER},
+ .ui_handler = &slave_ui_handler,
+ .le_security_interface = &slave_le_security_mock,
+ .proper_l2cap_interface = up_buffer_b_.get(),
+ .l2cap_handler = handler_,
+ .OnPairingFinished = OnPairingFinishedSlave,
+ };
+
+ std::unique_ptr<bluetooth::security::CommandView> first_pkt;
+ {
+ std::unique_lock<std::mutex> lock(handlers_initialization_guard);
+ pairing_handler_b = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, slave_setup);
+
+ first_pkt = WaitFirstL2capCommand();
+
+ EXPECT_CALL(master_ui_handler, DisplayPairingPrompt(_, _)).Times(1).WillOnce(InvokeWithoutArgs([&first_pkt, this] {
+ LOG_INFO("UI mock received pairing prompt");
+
+ {
+ // By grabbing the lock, we ensure initialization of both pairing handlers is finished.
+ std::lock_guard<std::mutex> lock(handlers_initialization_guard);
+ }
+ if (!pairing_handler_a) LOG_ALWAYS_FATAL("handler not initalized yet!");
+ // Simulate user accepting the pairing in UI
+ pairing_handler_a->OnUiAction(PairingEvent::PAIRING_ACCEPTED, 0x01 /* Non-zero value means success */);
+
+ // Send the first packet from the slave to master
+ auto view_to_packet = std::make_unique<packet::RawBuilder>();
+ view_to_packet->AddOctets(std::vector(first_pkt->begin(), first_pkt->end()));
+ up_buffer_b_->Enqueue(std::move(view_to_packet), handler_);
+ }));
+ pairing_handler_a = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, master_setup);
+ }
+
+ pairing_handler_a->WaitUntilPairingFinished();
+ pairing_handler_b->WaitUntilPairingFinished();
+
+ EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_master.value()));
+ EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_slave.value()));
+}
+
+TEST_F(PairingHandlerPairTest, test_secure_connections_numeric_comparison) {
+ master_setup.myPairingCapabilities.io_capability = IoCapability::DISPLAY_YES_NO;
+ master_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+ master_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc;
+
+ slave_setup.myPairingCapabilities.io_capability = IoCapability::DISPLAY_YES_NO;
+ slave_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+ slave_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc;
+
+ uint32_t num_value_slave = 0;
+ {
+ std::unique_lock<std::mutex> lock(handlers_initialization_guard);
+ // Initiator must be initialized after the responder.
+ pairing_handler_a = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, master_setup);
+
+ while (!first_command_sent) {
+ std::this_thread::sleep_for(1ms);
+ LOG_INFO("waiting for first command...");
+ }
+ slave_setup.pairing_request = PairingRequestView::Create(*first_command);
+
+ RecordPairingPromptHandling(slave_ui_handler, &pairing_handler_b);
+
+ EXPECT_CALL(slave_ui_handler, DisplayConfirmValue(_)).WillOnce(SaveArg<0>(&num_value_slave));
+ EXPECT_CALL(master_ui_handler, DisplayConfirmValue(_)).WillOnce(Invoke([&](uint32_t num_value) {
+ EXPECT_EQ(num_value_slave, num_value);
+ if (num_value_slave == num_value) {
+ pairing_handler_a->OnUiAction(PairingEvent::CONFIRM_YESNO, 0x01);
+ pairing_handler_b->OnUiAction(PairingEvent::CONFIRM_YESNO, 0x01);
+ }
+ }));
+
+ pairing_handler_b = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, slave_setup);
+ }
+ pairing_handler_a->WaitUntilPairingFinished();
+ pairing_handler_b->WaitUntilPairingFinished();
+
+ EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_master.value()));
+ EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_slave.value()));
+}
+
+TEST_F(PairingHandlerPairTest, test_secure_connections_passkey_entry) {
+ master_setup.myPairingCapabilities.io_capability = IoCapability::KEYBOARD_ONLY;
+ master_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+ master_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc;
+
+ slave_setup.myPairingCapabilities.io_capability = IoCapability::DISPLAY_ONLY;
+ slave_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+ slave_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc;
+
+ uint32_t passkey = std::numeric_limits<uint32_t>::max();
+ {
+ std::unique_lock<std::mutex> lock(handlers_initialization_guard);
+ pairing_handler_a = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, master_setup);
+
+ while (!first_command_sent) {
+ std::this_thread::sleep_for(1ms);
+ LOG_INFO("waiting for first command...");
+ }
+ slave_setup.pairing_request = PairingRequestView::Create(*first_command);
+
+ RecordPairingPromptHandling(slave_ui_handler, &pairing_handler_b);
+
+ EXPECT_CALL(slave_ui_handler, DisplayPasskey(_)).WillOnce(SaveArg<0>(&passkey));
+ EXPECT_CALL(master_ui_handler, DisplayEnterPasskeyDialog()).WillOnce(Invoke([&]() {
+ LOG_INFO("Passkey prompt displayed entering passkey: %08x", passkey);
+ std::this_thread::sleep_for(1ms);
+
+ // handle case where prompts are displayed in different order in the test!
+ if (passkey == std::numeric_limits<uint32_t>::max()) FAIL();
+
+ pairing_handler_a->OnUiAction(PairingEvent::PASSKEY, passkey);
+ }));
+
+ pairing_handler_b = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, slave_setup);
+ }
+ // Initiator must be initialized after the responder.
+ pairing_handler_a->WaitUntilPairingFinished();
+ pairing_handler_b->WaitUntilPairingFinished();
+
+ EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_master.value()));
+ EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_slave.value()));
+}
+
+TEST_F(PairingHandlerPairTest, test_secure_connections_out_of_band) {
+ master_setup.myPairingCapabilities.io_capability = IoCapability::KEYBOARD_ONLY;
+ master_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+ master_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+
+ slave_setup.myPairingCapabilities.io_capability = IoCapability::DISPLAY_ONLY;
+ slave_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::PRESENT;
+ slave_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+
+ master_setup.my_oob_data = std::make_optional<MyOobData>(PairingHandlerLe::GenerateOobData());
+ slave_setup.remote_oob_data =
+ std::make_optional<InitialInformations::out_of_band_data>(InitialInformations::out_of_band_data{
+ .le_sc_c = master_setup.my_oob_data->c,
+ .le_sc_r = master_setup.my_oob_data->r,
+ });
+
+ {
+ std::unique_lock<std::mutex> lock(handlers_initialization_guard);
+ pairing_handler_a = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, master_setup);
+ while (!first_command_sent) {
+ std::this_thread::sleep_for(1ms);
+ LOG_INFO("waiting for first command...");
+ }
+ slave_setup.pairing_request = PairingRequestView::Create(*first_command);
+
+ RecordPairingPromptHandling(slave_ui_handler, &pairing_handler_b);
+
+ pairing_handler_b = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, slave_setup);
+ }
+ pairing_handler_a->WaitUntilPairingFinished();
+ pairing_handler_b->WaitUntilPairingFinished();
+
+ EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_master.value()));
+ EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_slave.value()));
+}
+
+TEST_F(PairingHandlerPairTest, test_secure_connections_out_of_band_two_way) {
+ master_setup.myPairingCapabilities.io_capability = IoCapability::KEYBOARD_ONLY;
+ master_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::PRESENT;
+ master_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+
+ slave_setup.myPairingCapabilities.io_capability = IoCapability::DISPLAY_ONLY;
+ slave_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::PRESENT;
+ slave_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm | AuthReqMaskSc,
+
+ master_setup.my_oob_data = std::make_optional<MyOobData>(PairingHandlerLe::GenerateOobData());
+ slave_setup.remote_oob_data =
+ std::make_optional<InitialInformations::out_of_band_data>(InitialInformations::out_of_band_data{
+ .le_sc_c = master_setup.my_oob_data->c,
+ .le_sc_r = master_setup.my_oob_data->r,
+ });
+
+ slave_setup.my_oob_data = std::make_optional<MyOobData>(PairingHandlerLe::GenerateOobData());
+ master_setup.remote_oob_data =
+ std::make_optional<InitialInformations::out_of_band_data>(InitialInformations::out_of_band_data{
+ .le_sc_c = slave_setup.my_oob_data->c,
+ .le_sc_r = slave_setup.my_oob_data->r,
+ });
+
+ {
+ std::unique_lock<std::mutex> lock(handlers_initialization_guard);
+ pairing_handler_a = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, master_setup);
+ while (!first_command_sent) {
+ std::this_thread::sleep_for(1ms);
+ LOG_INFO("waiting for first command...");
+ }
+ slave_setup.pairing_request = PairingRequestView::Create(*first_command);
+
+ RecordPairingPromptHandling(slave_ui_handler, &pairing_handler_b);
+
+ pairing_handler_b = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, slave_setup);
+ }
+ pairing_handler_a->WaitUntilPairingFinished();
+ pairing_handler_b->WaitUntilPairingFinished();
+
+ EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_master.value()));
+ EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_slave.value()));
+}
+
+TEST_F(PairingHandlerPairTest, test_legacy_just_works) {
+ master_setup.myPairingCapabilities.io_capability = IoCapability::NO_INPUT_NO_OUTPUT;
+ master_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+ master_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm,
+
+ slave_setup.myPairingCapabilities.io_capability = IoCapability::NO_INPUT_NO_OUTPUT;
+ slave_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+ slave_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm;
+
+ {
+ std::unique_lock<std::mutex> lock(handlers_initialization_guard);
+ pairing_handler_a = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, master_setup);
+ while (!first_command_sent) {
+ std::this_thread::sleep_for(1ms);
+ LOG_INFO("waiting for first command...");
+ }
+ slave_setup.pairing_request = PairingRequestView::Create(*first_command);
+
+ RecordPairingPromptHandling(slave_ui_handler, &pairing_handler_b);
+
+ pairing_handler_b = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, slave_setup);
+ }
+ pairing_handler_a->WaitUntilPairingFinished();
+ pairing_handler_b->WaitUntilPairingFinished();
+
+ EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_master.value()));
+ EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_slave.value()));
+}
+
+TEST_F(PairingHandlerPairTest, test_legacy_passkey_entry) {
+ master_setup.myPairingCapabilities.io_capability = IoCapability::KEYBOARD_DISPLAY;
+ master_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+ master_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm,
+
+ slave_setup.myPairingCapabilities.io_capability = IoCapability::KEYBOARD_ONLY;
+ slave_setup.myPairingCapabilities.oob_data_flag = OobDataFlag::NOT_PRESENT;
+ slave_setup.myPairingCapabilities.auth_req = AuthReqMaskBondingFlag | AuthReqMaskMitm;
+
+ {
+ std::unique_lock<std::mutex> lock(handlers_initialization_guard);
+ pairing_handler_a = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, master_setup);
+ while (!first_command_sent) {
+ std::this_thread::sleep_for(1ms);
+ LOG_INFO("waiting for first command...");
+ }
+ slave_setup.pairing_request = PairingRequestView::Create(*first_command);
+
+ RecordPairingPromptHandling(slave_ui_handler, &pairing_handler_b);
+
+ EXPECT_CALL(slave_ui_handler, DisplayEnterPasskeyDialog());
+ EXPECT_CALL(master_ui_handler, DisplayConfirmValue(_)).WillOnce(Invoke([&](uint32_t passkey) {
+ LOG_INFO("Passkey prompt displayed entering passkey: %08x", passkey);
+ std::this_thread::sleep_for(1ms);
+
+ // TODO: handle case where prompts are displayed in different order in the test!
+ pairing_handler_b->OnUiAction(PairingEvent::PASSKEY, passkey);
+ }));
+
+ pairing_handler_b = std::make_unique<PairingHandlerLe>(PairingHandlerLe::PHASE1, slave_setup);
+ }
+ pairing_handler_a->WaitUntilPairingFinished();
+ pairing_handler_b->WaitUntilPairingFinished();
+
+ EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_master.value()));
+ EXPECT_TRUE(std::holds_alternative<PairingResult>(pairing_result_slave.value()));
+}
+
+} // namespace security
+} // namespace bluetooth
diff --git a/gd/security/ui.h b/gd/security/ui.h
new file mode 100644
index 0000000..83041de
--- /dev/null
+++ b/gd/security/ui.h
@@ -0,0 +1,58 @@
+/******************************************************************************
+ *
+ * Copyright 2019 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.
+ *
+ ******************************************************************************/
+
+#pragma once
+
+#include "hci/address_with_type.h"
+
+// Through this interface we talk to the user, asking for confirmations/acceptance.
+class UI {
+ public:
+ virtual ~UI(){};
+
+ /* Remote device tries to initiate pairing, ask user to confirm */
+ virtual void DisplayPairingPrompt(const bluetooth::hci::AddressWithType& address, std::string& name) = 0;
+
+ /* Remove the pairing prompt from DisplayPairingPrompt, i.e. remote device disconnected, or some application requested
+ * bond with this device */
+ virtual void CancelPairingPrompt(const bluetooth::hci::AddressWithType& address) = 0;
+
+ /* Display value for Comprision */
+ virtual void DisplayConfirmValue(uint32_t numeric_value) = 0;
+
+ /* Display a dialog box that will let user enter the Passkey */
+ virtual void DisplayEnterPasskeyDialog() = 0;
+
+ /* Present the passkey value to the user */
+ virtual void DisplayPasskey(uint32_t passkey) = 0;
+};
+
+/* Through this interface, UI provides us with user choices. */
+class UICallbacks {
+ public:
+ virtual ~UICallbacks() = 0;
+
+ /* User accepted pairing prompt */
+ virtual void OnPairingPromptAccepted(const bluetooth::hci::Address& address) = 0;
+
+ /* User confirmed that displayed value matches the value on the other device */
+ virtual void OnConfirmYesNo(const bluetooth::hci::Address& address, bool conformed) = 0;
+
+ /* User typed the value displayed on the other device. This is either Passkey or the Confirm value */
+ virtual void OnPasskeyEntry(const bluetooth::hci::Address& address, uint32_t passkey) = 0;
+};
diff --git a/gd/shim/Android.bp b/gd/shim/Android.bp
new file mode 100644
index 0000000..33c9b65
--- /dev/null
+++ b/gd/shim/Android.bp
@@ -0,0 +1,24 @@
+filegroup {
+ name: "BluetoothShimSources",
+ srcs: [
+ "advertising.cc",
+ "controller.cc",
+ "connectability.cc",
+ "discoverability.cc",
+ "hci_layer.cc",
+ "inquiry.cc",
+ "l2cap.cc",
+ "name.cc",
+ "page.cc",
+ "scanning.cc",
+ "stack.cc",
+ ],
+}
+
+filegroup {
+ name: "BluetoothShimTestSources",
+ srcs: [
+ ],
+}
+
+
diff --git a/gd/shim/advertising.cc b/gd/shim/advertising.cc
new file mode 100644
index 0000000..b7e0b4e
--- /dev/null
+++ b/gd/shim/advertising.cc
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2019 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.
+ */
+#define LOG_TAG "bt_gd_shim"
+
+#include <functional>
+#include <memory>
+
+#include "hci/address.h"
+#include "hci/hci_packets.h"
+#include "hci/le_advertising_manager.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "shim/advertising.h"
+
+namespace bluetooth {
+namespace shim {
+
+struct Advertising::impl {
+ hci::LeAdvertisingManager* module_{nullptr};
+
+ impl(hci::LeAdvertisingManager* module);
+ ~impl();
+};
+
+const ModuleFactory Advertising::Factory = ModuleFactory([]() { return new Advertising(); });
+
+Advertising::impl::impl(hci::LeAdvertisingManager* advertising_manager) : module_(advertising_manager) {}
+
+Advertising::impl::~impl() {}
+
+/**
+ * Module methods
+ */
+void Advertising::ListDependencies(ModuleList* list) {
+ list->add<hci::LeAdvertisingManager>();
+}
+
+void Advertising::Start() {
+ pimpl_ = std::make_unique<impl>(GetDependency<hci::LeAdvertisingManager>());
+}
+
+void Advertising::Stop() {
+ pimpl_.reset();
+}
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/advertising.h b/gd/shim/advertising.h
new file mode 100644
index 0000000..17c094a
--- /dev/null
+++ b/gd/shim/advertising.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include "module.h"
+#include "shim/iadvertising.h"
+
+namespace bluetooth {
+namespace shim {
+
+class Advertising : public bluetooth::Module, public bluetooth::shim::IAdvertising {
+ public:
+ Advertising() = default;
+ ~Advertising() = default;
+
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override; // Module
+ void Start() override; // Module
+ void Stop() override; // Module
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+ DISALLOW_COPY_AND_ASSIGN(Advertising);
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/connectability.cc b/gd/shim/connectability.cc
new file mode 100644
index 0000000..2b779fd
--- /dev/null
+++ b/gd/shim/connectability.cc
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2019 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.
+ */
+#define LOG_TAG "bt_gd_shim"
+
+#include <memory>
+
+#include "common/bidi_queue.h"
+#include "hci/address.h"
+#include "hci/controller.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "neighbor/connectability.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "shim/connectability.h"
+
+namespace bluetooth {
+namespace shim {
+
+const ModuleFactory Connectability::Factory = ModuleFactory([]() { return new Connectability(); });
+
+struct Connectability::impl {
+ impl(neighbor::ConnectabilityModule* module) : module_(module) {}
+
+ neighbor::ConnectabilityModule* module_{nullptr};
+};
+
+void Connectability::StartConnectability() {
+ pimpl_->module_->StartConnectability();
+}
+
+void Connectability::StopConnectability() {
+ pimpl_->module_->StopConnectability();
+}
+
+bool Connectability::IsConnectable() const {
+ return pimpl_->module_->IsConnectable();
+}
+
+/**
+ * Module methods
+ */
+void Connectability::ListDependencies(ModuleList* list) {
+ list->add<neighbor::ConnectabilityModule>();
+}
+
+void Connectability::Start() {
+ pimpl_ = std::make_unique<impl>(GetDependency<neighbor::ConnectabilityModule>());
+}
+
+void Connectability::Stop() {
+ pimpl_.reset();
+}
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/connectability.h b/gd/shim/connectability.h
new file mode 100644
index 0000000..780b5be
--- /dev/null
+++ b/gd/shim/connectability.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <memory>
+
+#include "module.h"
+#include "shim/iconnectability.h"
+
+namespace bluetooth {
+namespace shim {
+
+class Connectability : public bluetooth::Module, public bluetooth::shim::IConnectability {
+ public:
+ void StartConnectability() override;
+ void StopConnectability() override;
+ bool IsConnectable() const override;
+
+ Connectability() = default;
+ ~Connectability() = default;
+
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override; // Module
+ void Start() override; // Module
+ void Stop() override; // Module
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+ DISALLOW_COPY_AND_ASSIGN(Connectability);
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/controller.cc b/gd/shim/controller.cc
new file mode 100644
index 0000000..6b82bb6
--- /dev/null
+++ b/gd/shim/controller.cc
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2019 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.
+ */
+#define LOG_TAG "bt_gd_shim"
+
+#include <memory>
+
+#include "common/bidi_queue.h"
+#include "hci/address.h"
+#include "hci/controller.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "shim/controller.h"
+
+namespace bluetooth {
+namespace shim {
+
+const ModuleFactory Controller::Factory = ModuleFactory([]() { return new Controller(); });
+
+struct Controller::impl {
+ impl(hci::Controller* hci_controller) : hci_controller_(hci_controller) {}
+
+ hci::Controller* hci_controller_{nullptr};
+};
+
+bool Controller::IsCommandSupported(int op_code) const {
+ return pimpl_->hci_controller_->IsSupported((bluetooth::hci::OpCode)op_code);
+}
+
+uint16_t Controller::GetControllerAclPacketLength() const {
+ return pimpl_->hci_controller_->GetControllerAclPacketLength();
+}
+
+LeBufferSize Controller::GetControllerLeBufferSize() const {
+ LeBufferSize le_buffer_size;
+ hci::LeBufferSize hci_le_buffer_size = pimpl_->hci_controller_->GetControllerLeBufferSize();
+
+ le_buffer_size.le_data_packet_length = hci_le_buffer_size.le_data_packet_length_;
+ le_buffer_size.total_num_le_packets = hci_le_buffer_size.total_num_le_packets_;
+ return le_buffer_size;
+}
+
+LeMaximumDataLength Controller::GetControllerLeMaximumDataLength() const {
+ LeMaximumDataLength maximum_data_length;
+ hci::LeMaximumDataLength hci_maximum_data_length = pimpl_->hci_controller_->GetControllerLeMaximumDataLength();
+
+ maximum_data_length.supported_max_tx_octets = hci_maximum_data_length.supported_max_tx_octets_;
+ maximum_data_length.supported_max_tx_time = hci_maximum_data_length.supported_max_tx_time_;
+ maximum_data_length.supported_max_rx_octets = hci_maximum_data_length.supported_max_rx_octets_;
+ maximum_data_length.supported_max_rx_time = hci_maximum_data_length.supported_max_rx_time_;
+ return maximum_data_length;
+}
+
+uint16_t Controller::GetControllerNumAclPacketBuffers() const {
+ return pimpl_->hci_controller_->GetControllerNumAclPacketBuffers();
+}
+
+uint64_t Controller::GetControllerLeLocalSupportedFeatures() const {
+ return pimpl_->hci_controller_->GetControllerLeLocalSupportedFeatures();
+}
+
+uint64_t Controller::GetControllerLocalExtendedFeatures(uint8_t page_number) const {
+ return pimpl_->hci_controller_->GetControllerLocalExtendedFeatures(page_number);
+}
+
+std::string Controller::GetControllerMacAddress() const {
+ return pimpl_->hci_controller_->GetControllerMacAddress().ToString();
+}
+
+uint64_t Controller::GetControllerLeSupportedStates() const {
+ return pimpl_->hci_controller_->GetControllerLeSupportedStates();
+}
+
+uint8_t Controller::GetControllerLocalExtendedFeaturesMaxPageNumber() const {
+ return pimpl_->hci_controller_->GetControllerLocalExtendedFeaturesMaxPageNumber();
+}
+
+/**
+ * Module methods
+ */
+void Controller::ListDependencies(ModuleList* list) {
+ list->add<hci::Controller>();
+}
+
+void Controller::Start() {
+ LOG_INFO("%s Starting controller shim layer", __func__);
+ pimpl_ = std::make_unique<impl>(GetDependency<hci::Controller>());
+}
+
+void Controller::Stop() {
+ pimpl_.reset();
+}
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/controller.h b/gd/shim/controller.h
new file mode 100644
index 0000000..39bd440
--- /dev/null
+++ b/gd/shim/controller.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include "module.h"
+#include "shim/icontroller.h"
+
+/**
+ * Gd shim controller module that depends upon the Gd controller module.
+ *
+ * Wraps the Gd controller module to expose a sufficient API to allow
+ * proper operation of the legacy shim controller interface.
+ *
+ */
+namespace bluetooth {
+namespace shim {
+
+class Controller : public bluetooth::Module, public bluetooth::shim::IController {
+ public:
+ Controller() = default;
+ ~Controller() = default;
+
+ static const ModuleFactory Factory;
+
+ // Exported controller methods from IController for shim layer
+ bool IsCommandSupported(int op_code) const override;
+ LeBufferSize GetControllerLeBufferSize() const override;
+ LeMaximumDataLength GetControllerLeMaximumDataLength() const override;
+ std::string GetControllerMacAddress() const override;
+ uint16_t GetControllerAclPacketLength() const override;
+ uint16_t GetControllerNumAclPacketBuffers() const override;
+ uint64_t GetControllerLeLocalSupportedFeatures() const override;
+ uint64_t GetControllerLeSupportedStates() const override;
+ uint64_t GetControllerLocalExtendedFeatures(uint8_t page_number) const override;
+ uint8_t GetControllerLocalExtendedFeaturesMaxPageNumber() const override;
+
+ protected:
+ void ListDependencies(ModuleList* list) override; // Module
+ void Start() override; // Module
+ void Stop() override; // Module
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+ DISALLOW_COPY_AND_ASSIGN(Controller);
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/discoverability.cc b/gd/shim/discoverability.cc
new file mode 100644
index 0000000..5754882
--- /dev/null
+++ b/gd/shim/discoverability.cc
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2019 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.
+ */
+#define LOG_TAG "bt_gd_shim"
+
+#include <memory>
+
+#include "common/bidi_queue.h"
+#include "hci/address.h"
+#include "hci/controller.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "neighbor/discoverability.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "shim/discoverability.h"
+
+namespace bluetooth {
+namespace shim {
+
+const ModuleFactory Discoverability::Factory = ModuleFactory([]() { return new Discoverability(); });
+
+struct Discoverability::impl {
+ impl(neighbor::DiscoverabilityModule* module) : module_(module) {}
+
+ neighbor::DiscoverabilityModule* module_{nullptr};
+};
+
+void Discoverability::StopDiscoverability() {
+ return pimpl_->module_->StopDiscoverability();
+}
+
+void Discoverability::StartLimitedDiscoverability() {
+ return pimpl_->module_->StartLimitedDiscoverability();
+}
+
+void Discoverability::StartGeneralDiscoverability() {
+ return pimpl_->module_->StartGeneralDiscoverability();
+}
+
+bool Discoverability::IsGeneralDiscoverabilityEnabled() const {
+ return pimpl_->module_->IsGeneralDiscoverabilityEnabled();
+}
+
+bool Discoverability::IsLimitedDiscoverabilityEnabled() const {
+ return pimpl_->module_->IsLimitedDiscoverabilityEnabled();
+}
+
+/**
+ * Module methods
+ */
+void Discoverability::ListDependencies(ModuleList* list) {
+ list->add<neighbor::DiscoverabilityModule>();
+}
+
+void Discoverability::Start() {
+ pimpl_ = std::make_unique<impl>(GetDependency<neighbor::DiscoverabilityModule>());
+}
+
+void Discoverability::Stop() {
+ pimpl_.reset();
+}
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/discoverability.h b/gd/shim/discoverability.h
new file mode 100644
index 0000000..34ad49a
--- /dev/null
+++ b/gd/shim/discoverability.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <memory>
+
+#include "module.h"
+#include "shim/idiscoverability.h"
+
+namespace bluetooth {
+namespace shim {
+
+class Discoverability : public bluetooth::Module, public bluetooth::shim::IDiscoverability {
+ public:
+ void StartGeneralDiscoverability() override;
+ void StartLimitedDiscoverability() override;
+ void StopDiscoverability() override;
+
+ bool IsGeneralDiscoverabilityEnabled() const override;
+ bool IsLimitedDiscoverabilityEnabled() const override;
+
+ Discoverability() = default;
+ ~Discoverability() = default;
+
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override; // Module
+ void Start() override; // Module
+ void Stop() override; // Module
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+ DISALLOW_COPY_AND_ASSIGN(Discoverability);
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/hci_layer.cc b/gd/shim/hci_layer.cc
new file mode 100644
index 0000000..e11454b
--- /dev/null
+++ b/gd/shim/hci_layer.cc
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2019 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.
+ */
+#define LOG_TAG "bt_gd_shim"
+
+#include <cstdint>
+#include <memory>
+#include <queue>
+#include <unordered_map>
+#include <vector>
+
+#include "hci/hci_layer.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "packet/raw_builder.h"
+#include "shim/hci_layer.h"
+
+namespace bluetooth {
+namespace shim {
+
+using TokenQueue = std::queue<const void*>;
+using OpCodeTokenQueueMap = std::unordered_map<hci::OpCode, TokenQueue>;
+
+const ModuleFactory HciLayer::Factory = ModuleFactory([]() { return new HciLayer(); });
+
+struct HciLayer::impl {
+ impl(os::Handler* handler, hci::HciLayer* hci_layer) : handler_(handler), hci_layer_(hci_layer) {}
+
+ void OnTransmitPacketCommandComplete(hci::CommandCompleteView view) {
+ if (command_complete_callback_ == nullptr) {
+ LOG_WARN("%s Received packet complete with no complete callback registered", __func__);
+ return;
+ }
+
+ uint16_t command_op_code = static_cast<uint16_t>(view.GetCommandOpCode());
+ std::vector<const uint8_t> data(view.begin(), view.end());
+
+ if (op_code_token_queue_map_.count(view.GetCommandOpCode()) == 0) {
+ LOG_WARN("%s Received unexpected command complete for opcode:0x%04x", __func__, command_op_code);
+ return;
+ }
+ const void* token = op_code_token_queue_map_[view.GetCommandOpCode()].front();
+ if (token == nullptr) {
+ LOG_WARN("%s Received expected command status but no token for opcode:0x%04x", __func__, command_op_code);
+ return;
+ }
+
+ op_code_token_queue_map_[view.GetCommandOpCode()].pop();
+ command_complete_callback_(command_op_code, data, token);
+ }
+
+ void OnTransmitPacketStatus(hci::CommandStatusView view) {
+ if (command_status_callback_ == nullptr) {
+ LOG_WARN("%s Received packet complete with no status callback registered", __func__);
+ return;
+ }
+
+ uint16_t command_op_code = static_cast<uint16_t>(view.GetCommandOpCode());
+ std::vector<const uint8_t> data(view.begin(), view.end());
+
+ if (op_code_token_queue_map_.count(view.GetCommandOpCode()) == 0) {
+ LOG_WARN("%s Received unexpected command status for opcode:0x%04x", __func__, command_op_code);
+ return;
+ }
+ const void* token = op_code_token_queue_map_[view.GetCommandOpCode()].front();
+ if (token == nullptr) {
+ LOG_WARN("%s Received expected command status but no token for opcode:0x%04x", __func__, command_op_code);
+ return;
+ }
+
+ op_code_token_queue_map_[view.GetCommandOpCode()].pop();
+ uint8_t status = static_cast<uint8_t>(view.GetStatus());
+ command_status_callback_(command_op_code, data, token, status);
+ }
+
+ void TransmitCommand(uint16_t command, const uint8_t* data, size_t len, const void* token) {
+ ASSERT(data != nullptr);
+ ASSERT(token != nullptr);
+
+ const hci::OpCode op_code = static_cast<const hci::OpCode>(command);
+
+ auto payload = MakeUniquePacket(data, len);
+ auto packet = hci::CommandPacketBuilder::Create(op_code, std::move(payload));
+
+ op_code_token_queue_map_[op_code].push(token);
+ if (IsCommandStatusOpcode(op_code)) {
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::OnTransmitPacketStatus, common::Unretained(this)), handler_);
+ } else {
+ hci_layer_->EnqueueCommand(std::move(packet),
+ common::BindOnce(&impl::OnTransmitPacketCommandComplete, common::Unretained(this)),
+ handler_);
+ }
+ }
+
+ void RegisterCommandComplete(CommandCompleteCallback callback) {
+ ASSERT(command_complete_callback_ == nullptr);
+ command_complete_callback_ = callback;
+ }
+
+ void UnregisterCommandComplete() {
+ ASSERT(command_complete_callback_ != nullptr);
+ command_complete_callback_ = nullptr;
+ }
+
+ void RegisterCommandStatus(CommandStatusCallback callback) {
+ ASSERT(command_status_callback_ == nullptr);
+ command_status_callback_ = callback;
+ }
+
+ void UnregisterCommandStatus() {
+ ASSERT(command_status_callback_ != nullptr);
+ command_status_callback_ = nullptr;
+ }
+
+ private:
+ os::Handler* handler_{nullptr};
+ hci::HciLayer* hci_layer_{nullptr};
+
+ CommandCompleteCallback command_complete_callback_;
+ CommandStatusCallback command_status_callback_;
+
+ OpCodeTokenQueueMap op_code_token_queue_map_;
+
+ /**
+ * Returns true if expecting command complete, false otherwise
+ */
+ bool IsCommandStatusOpcode(hci::OpCode op_code) {
+ switch (op_code) {
+ case hci::OpCode::INQUIRY:
+ case hci::OpCode::CREATE_CONNECTION:
+ case hci::OpCode::DISCONNECT:
+ case hci::OpCode::ACCEPT_CONNECTION_REQUEST:
+ case hci::OpCode::REJECT_CONNECTION_REQUEST:
+ case hci::OpCode::CHANGE_CONNECTION_PACKET_TYPE:
+ case hci::OpCode::AUTHENTICATION_REQUESTED:
+ case hci::OpCode::SET_CONNECTION_ENCRYPTION:
+ case hci::OpCode::CHANGE_CONNECTION_LINK_KEY:
+ case hci::OpCode::MASTER_LINK_KEY:
+ case hci::OpCode::REMOTE_NAME_REQUEST:
+ case hci::OpCode::READ_REMOTE_SUPPORTED_FEATURES:
+ case hci::OpCode::READ_REMOTE_EXTENDED_FEATURES:
+ case hci::OpCode::READ_REMOTE_VERSION_INFORMATION:
+ case hci::OpCode::READ_CLOCK_OFFSET:
+ case hci::OpCode::SETUP_SYNCHRONOUS_CONNECTION:
+ case hci::OpCode::ACCEPT_SYNCHRONOUS_CONNECTION:
+ case hci::OpCode::REJECT_SYNCHRONOUS_CONNECTION:
+ case hci::OpCode::ENHANCED_SETUP_SYNCHRONOUS_CONNECTION:
+ case hci::OpCode::ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION:
+ case hci::OpCode::HOLD_MODE:
+ case hci::OpCode::SNIFF_MODE:
+ case hci::OpCode::EXIT_SNIFF_MODE:
+ case hci::OpCode::QOS_SETUP:
+ case hci::OpCode::SWITCH_ROLE:
+ case hci::OpCode::FLOW_SPECIFICATION:
+ case hci::OpCode::REFRESH_ENCRYPTION_KEY:
+ case hci::OpCode::LE_CREATE_CONNECTION:
+ case hci::OpCode::LE_CONNECTION_UPDATE:
+ case hci::OpCode::LE_READ_REMOTE_FEATURES:
+ case hci::OpCode::LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND:
+ case hci::OpCode::LE_GENERATE_DHKEY_COMMAND:
+ case hci::OpCode::LE_SET_PHY:
+ case hci::OpCode::LE_EXTENDED_CREATE_CONNECTION:
+ case hci::OpCode::LE_PERIODIC_ADVERTISING_CREATE_SYNC:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ std::unique_ptr<packet::RawBuilder> MakeUniquePacket(const uint8_t* data, size_t len) {
+ packet::RawBuilder builder;
+ std::vector<uint8_t> bytes(data, data + len);
+
+ auto payload = std::make_unique<packet::RawBuilder>();
+ payload->AddOctets(bytes);
+
+ return payload;
+ }
+};
+
+void HciLayer::TransmitCommand(uint16_t op_code, const uint8_t* data, size_t len, const void* token) {
+ pimpl_->TransmitCommand(op_code, data, len, std::move(token));
+}
+
+void HciLayer::RegisterCommandComplete(CommandCompleteCallback callback) {
+ pimpl_->RegisterCommandComplete(callback);
+}
+
+void HciLayer::UnregisterCommandComplete() {
+ pimpl_->UnregisterCommandComplete();
+}
+
+void HciLayer::RegisterCommandStatus(CommandStatusCallback callback) {
+ pimpl_->RegisterCommandStatus(callback);
+}
+
+void HciLayer::UnregisterCommandStatus() {
+ pimpl_->UnregisterCommandStatus();
+}
+
+/**
+ * Module methods
+ */
+void HciLayer::ListDependencies(ModuleList* list) {
+ list->add<hci::HciLayer>();
+}
+
+void HciLayer::Start() {
+ LOG_INFO("%s Starting controller shim layer", __func__);
+ pimpl_ = std::make_unique<impl>(GetHandler(), GetDependency<hci::HciLayer>());
+}
+
+void HciLayer::Stop() {
+ pimpl_.reset();
+}
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/hci_layer.h b/gd/shim/hci_layer.h
new file mode 100644
index 0000000..bcd7fed
--- /dev/null
+++ b/gd/shim/hci_layer.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <memory>
+#include <string>
+
+#include "module.h"
+#include "shim/ihci_layer.h"
+
+/**
+ * The hci layer shim module that depends on the Gd hci layer module.
+ */
+namespace bluetooth {
+namespace shim {
+
+class HciLayer : public ::bluetooth::Module, public ::bluetooth::shim::IHciLayer {
+ public:
+ HciLayer() = default;
+ ~HciLayer() = default;
+
+ void TransmitCommand(uint16_t op_code, const uint8_t* data, size_t len,
+ const void* token); // IHciLayer
+
+ void RegisterCommandComplete(CommandCompleteCallback callback); // IHciLayer
+ void UnregisterCommandComplete(); // IHciLayer
+
+ void RegisterCommandStatus(CommandStatusCallback callback); // IHciLayer
+ void UnregisterCommandStatus(); // IHciLayer
+
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override; // Module
+ void Start() override; // Module
+ void Stop() override; // Module
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+ DISALLOW_COPY_AND_ASSIGN(HciLayer);
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/iadvertising.h b/gd/shim/iadvertising.h
new file mode 100644
index 0000000..85a75c6
--- /dev/null
+++ b/gd/shim/iadvertising.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+/**
+ * The gd API exported to the legacy api
+ */
+namespace bluetooth {
+namespace shim {
+
+struct IAdvertising {
+ virtual ~IAdvertising() {}
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/iconnectability.h b/gd/shim/iconnectability.h
new file mode 100644
index 0000000..fbfaaa3
--- /dev/null
+++ b/gd/shim/iconnectability.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+/**
+ * The gd API exported to the legacy api
+ */
+namespace bluetooth {
+namespace shim {
+
+struct IConnectability {
+ virtual void StartConnectability() = 0;
+ virtual void StopConnectability() = 0;
+ virtual bool IsConnectable() const = 0;
+
+ virtual ~IConnectability() {}
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/icontroller.h b/gd/shim/icontroller.h
new file mode 100644
index 0000000..0accc66
--- /dev/null
+++ b/gd/shim/icontroller.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <cstdint>
+#include <string>
+
+/**
+ * The shim controller module that depends on the Gd controller module
+ */
+namespace bluetooth {
+namespace shim {
+
+typedef struct {
+ uint16_t le_data_packet_length;
+ uint8_t total_num_le_packets;
+} LeBufferSize;
+
+typedef struct {
+ uint16_t supported_max_tx_octets;
+ uint16_t supported_max_tx_time;
+ uint16_t supported_max_rx_octets;
+ uint16_t supported_max_rx_time;
+} LeMaximumDataLength;
+
+struct IController {
+ virtual bool IsCommandSupported(int op_code) const = 0;
+ virtual LeBufferSize GetControllerLeBufferSize() const = 0;
+ virtual LeMaximumDataLength GetControllerLeMaximumDataLength() const = 0;
+ virtual std::string GetControllerMacAddress() const = 0;
+ virtual uint16_t GetControllerAclPacketLength() const = 0;
+ virtual uint16_t GetControllerNumAclPacketBuffers() const = 0;
+ virtual uint64_t GetControllerLeLocalSupportedFeatures() const = 0;
+ virtual uint64_t GetControllerLeSupportedStates() const = 0;
+ virtual uint64_t GetControllerLocalExtendedFeatures(uint8_t page_number) const = 0;
+ virtual uint8_t GetControllerLocalExtendedFeaturesMaxPageNumber() const = 0;
+
+ virtual ~IController() {}
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/idiscoverability.h b/gd/shim/idiscoverability.h
new file mode 100644
index 0000000..2a2e4a8
--- /dev/null
+++ b/gd/shim/idiscoverability.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+/**
+ * The gd API exported to the legacy api
+ */
+namespace bluetooth {
+namespace shim {
+
+struct IDiscoverability {
+ virtual void StartGeneralDiscoverability() = 0;
+ virtual void StartLimitedDiscoverability() = 0;
+ virtual void StopDiscoverability() = 0;
+
+ virtual bool IsGeneralDiscoverabilityEnabled() const = 0;
+ virtual bool IsLimitedDiscoverabilityEnabled() const = 0;
+
+ virtual ~IDiscoverability() {}
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/ihci_layer.h b/gd/shim/ihci_layer.h
new file mode 100644
index 0000000..5bb8e8f
--- /dev/null
+++ b/gd/shim/ihci_layer.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <vector>
+
+/**
+ * Legacy interface and API into the Gd shim hci layer module.
+ */
+using CommandCompleteCallback =
+ std::function<void(uint16_t command_op_code, std::vector<const uint8_t> data, const void* token)>;
+using CommandStatusCallback =
+ std::function<void(uint16_t command_op_code, std::vector<const uint8_t> data, const void* token, uint8_t status)>;
+
+namespace bluetooth {
+namespace shim {
+
+struct IHciLayer {
+ virtual void TransmitCommand(uint16_t op_code, const uint8_t* data, size_t len, const void* token) = 0;
+
+ virtual void RegisterCommandComplete(CommandCompleteCallback callback) = 0;
+ virtual void UnregisterCommandComplete() = 0;
+
+ virtual void RegisterCommandStatus(CommandStatusCallback callback) = 0;
+ virtual void UnregisterCommandStatus() = 0;
+
+ virtual ~IHciLayer() {}
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/iinquiry.h b/gd/shim/iinquiry.h
new file mode 100644
index 0000000..97fd1b1
--- /dev/null
+++ b/gd/shim/iinquiry.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <cstdint>
+#include <functional>
+#include <vector>
+
+/**
+ * The gd API exported to the legacy api
+ */
+namespace bluetooth {
+namespace shim {
+
+using InquiryResultCallback = std::function<void(std::vector<const uint8_t> data)>;
+using InquiryResultWithRssiCallback = std::function<void(std::vector<const uint8_t> data)>;
+using ExtendedInquiryResultCallback = std::function<void(std::vector<const uint8_t> data)>;
+using InquiryCompleteCallback = std::function<void(uint16_t status)>;
+using InquiryCancelCompleteCallback = std::function<void(uint8_t mode)>;
+
+struct IInquiry {
+ virtual void StartGeneralInquiry(uint8_t duration, uint8_t max_responses) = 0;
+ virtual void StartLimitedInquiry(uint8_t duration, uint8_t max_responses) = 0;
+ virtual void StopInquiry() = 0;
+ virtual bool IsGeneralInquiryActive() const = 0;
+ virtual bool IsLimitedInquiryActive() const = 0;
+
+ virtual void StartGeneralPeriodicInquiry(uint8_t duration, uint8_t max_responses, uint16_t max_delay,
+ uint16_t min_delay) = 0;
+ virtual void StartLimitedPeriodicInquiry(uint8_t duration, uint8_t max_responses, uint16_t max_delay,
+ uint16_t min_delay) = 0;
+ virtual void StopPeriodicInquiry() = 0;
+ virtual bool IsGeneralPeriodicInquiryActive() const = 0;
+ virtual bool IsLimitedPeriodicInquiryActive() const = 0;
+
+ virtual void SetInterlacedScan() = 0;
+ virtual void SetStandardScan() = 0;
+
+ virtual void SetScanActivity(uint16_t interval, uint16_t window) = 0;
+ virtual void GetScanActivity(uint16_t& interval, uint16_t& window) const = 0;
+
+ virtual void SetStandardInquiryResultMode() = 0;
+ virtual void SetInquiryWithRssiResultMode() = 0;
+ virtual void SetExtendedInquiryResultMode() = 0;
+
+ virtual void RegisterInquiryResult(InquiryResultCallback callback) = 0;
+ virtual void UnregisterInquiryResult() = 0;
+ virtual void RegisterInquiryResultWithRssi(InquiryResultWithRssiCallback callback) = 0;
+ virtual void UnregisterInquiryResultWithRssi() = 0;
+ virtual void RegisterExtendedInquiryResult(ExtendedInquiryResultCallback callback) = 0;
+ virtual void UnregisterExtendedInquiryResult() = 0;
+ virtual void RegisterInquiryComplete(InquiryCompleteCallback callback) = 0;
+ virtual void UnregisterInquiryComplete() = 0;
+ virtual void RegisterInquiryCancelComplete(InquiryCancelCompleteCallback callback) = 0;
+ virtual void UnregisterInquiryCancelComplete() = 0;
+
+ virtual ~IInquiry() {}
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/il2cap.h b/gd/shim/il2cap.h
new file mode 100644
index 0000000..994953e
--- /dev/null
+++ b/gd/shim/il2cap.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <cstdint>
+#include <functional>
+#include <future>
+#include <string>
+#include <vector>
+
+/**
+ * The gd API exported to the legacy api
+ */
+namespace bluetooth {
+namespace shim {
+
+using ConnectionClosedCallback = std::function<void(uint16_t cid, int error_code)>;
+using ConnectionOpenCallback = std::function<void(std::string string_address, uint16_t psm, uint16_t cid)>;
+using ReadDataReadyCallback = std::function<void(uint16_t cid, std::vector<const uint8_t> data)>;
+
+struct IL2cap {
+ virtual void RegisterService(uint16_t psm, ConnectionOpenCallback on_open, std::promise<void> completed) = 0;
+ virtual void UnregisterService(uint16_t psm) = 0;
+
+ virtual void CreateConnection(uint16_t psm, const std::string address, ConnectionOpenCallback on_open,
+ std::promise<uint16_t> completed) = 0;
+ virtual void CloseConnection(uint16_t cid) = 0;
+
+ virtual void SetReadDataReadyCallback(uint16_t cid, ReadDataReadyCallback on_data_ready) = 0;
+ virtual void SetConnectionClosedCallback(uint16_t cid, ConnectionClosedCallback on_closed) = 0;
+
+ virtual void Write(uint16_t cid, const uint8_t* data, size_t len) = 0;
+ virtual void WriteFlushable(uint16_t cid, const uint8_t* data, size_t len) = 0;
+ virtual void WriteNonFlushable(uint16_t cid, const uint8_t* data, size_t len) = 0;
+
+ virtual void SendLoopbackResponse(std::function<void()>) = 0;
+ virtual ~IL2cap() {}
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/iname.h b/gd/shim/iname.h
new file mode 100644
index 0000000..c99ba37
--- /dev/null
+++ b/gd/shim/iname.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <cstdint>
+#include <functional>
+#include <string>
+
+/**
+ * The gd API exported to the legacy api
+ */
+using ReadRemoteNameCallback =
+ std::function<void(std::string address_string, uint8_t hci_status, std::array<uint8_t, 248> remote_name)>;
+using CancelRemoteNameCallback = std::function<void(std::string address_string, uint8_t hci_status)>;
+
+namespace bluetooth {
+namespace shim {
+
+struct IName {
+ virtual void ReadRemoteNameRequest(std::string remote_address, ReadRemoteNameCallback callback) = 0;
+ virtual void CancelRemoteNameRequest(std::string remote_address, CancelRemoteNameCallback callback) = 0;
+
+ virtual ~IName() {}
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/inquiry.cc b/gd/shim/inquiry.cc
new file mode 100644
index 0000000..4c3a174
--- /dev/null
+++ b/gd/shim/inquiry.cc
@@ -0,0 +1,309 @@
+/*
+ * Copyright 2019 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.
+ */
+#define LOG_TAG "bt_gd_shim"
+
+#include <functional>
+#include <memory>
+
+#include "common/bidi_queue.h"
+#include "hci/address.h"
+#include "hci/controller.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "neighbor/inquiry.h"
+#include "neighbor/scan_parameters.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "shim/inquiry.h"
+
+namespace bluetooth {
+namespace shim {
+
+struct Inquiry::impl {
+ void Result(hci::InquiryResultView view);
+ void ResultWithRssi(hci::InquiryResultWithRssiView view);
+ void ExtendedResult(hci::ExtendedInquiryResultView view);
+ void Complete(hci::ErrorCode status);
+
+ void RegisterInquiryResult(InquiryResultCallback callback);
+ void UnregisterInquiryResult();
+ void RegisterInquiryResultWithRssi(InquiryResultWithRssiCallback callback);
+ void UnregisterInquiryResultWithRssi();
+ void RegisterExtendedInquiryResult(ExtendedInquiryResultCallback callback);
+ void UnregisterExtendedInquiryResult();
+ void RegisterInquiryComplete(InquiryCompleteCallback callback);
+ void UnregisterInquiryComplete();
+ void RegisterInquiryCancelComplete(InquiryCancelCompleteCallback callback);
+ void UnregisterInquiryCancelComplete();
+
+ InquiryResultCallback shim_result_callback_;
+ InquiryResultWithRssiCallback shim_result_with_rssi_callback_;
+ ExtendedInquiryResultCallback shim_extended_result_callback_;
+ InquiryCompleteCallback shim_complete_callback_;
+ InquiryCancelCompleteCallback shim_cancel_complete_callback_;
+
+ neighbor::InquiryModule* module_{nullptr};
+
+ impl(neighbor::InquiryModule* module);
+ ~impl();
+};
+
+const ModuleFactory Inquiry::Factory = ModuleFactory([]() { return new Inquiry(); });
+
+void Inquiry::impl::Result(hci::InquiryResultView view) {
+ ASSERT(view.size() >= sizeof(uint16_t));
+ ASSERT(shim_result_callback_ != nullptr);
+ std::vector<const uint8_t> v(view.begin() + sizeof(uint16_t), view.end());
+ shim_result_callback_(v);
+}
+
+void Inquiry::impl::ResultWithRssi(hci::InquiryResultWithRssiView view) {
+ ASSERT(view.size() >= sizeof(uint16_t));
+ ASSERT(shim_result_with_rssi_callback_ != nullptr);
+ std::vector<const uint8_t> v(view.begin() + sizeof(uint16_t), view.end());
+ shim_result_with_rssi_callback_(v);
+}
+
+void Inquiry::impl::ExtendedResult(hci::ExtendedInquiryResultView view) {
+ ASSERT(view.size() >= sizeof(uint16_t));
+ ASSERT(shim_extended_result_callback_ != nullptr);
+ std::vector<const uint8_t> v(view.begin() + sizeof(uint16_t), view.end());
+ shim_extended_result_callback_(v);
+}
+
+void Inquiry::impl::Complete(hci::ErrorCode status) {
+ ASSERT(shim_complete_callback_ != nullptr);
+ shim_complete_callback_(static_cast<uint16_t>(status));
+}
+
+void Inquiry::impl::RegisterInquiryResult(shim::InquiryResultCallback callback) {
+ if (shim_result_callback_ != nullptr) {
+ LOG_WARN("Registering inquiry result without unregistering");
+ }
+ shim_result_callback_ = callback;
+}
+
+void Inquiry::impl::UnregisterInquiryResult() {
+ if (shim_result_callback_ == nullptr) {
+ LOG_WARN("Unregistering inquiry result without registering");
+ }
+ shim_result_callback_ = nullptr;
+}
+
+void Inquiry::impl::RegisterInquiryResultWithRssi(shim::InquiryResultWithRssiCallback callback) {
+ if (shim_result_with_rssi_callback_ != nullptr) {
+ LOG_WARN("Registering inquiry result with rssi without unregistering");
+ }
+ shim_result_with_rssi_callback_ = callback;
+}
+
+void Inquiry::impl::UnregisterInquiryResultWithRssi() {
+ if (shim_result_with_rssi_callback_ == nullptr) {
+ LOG_WARN("Unregistering inquiry result with rssi without registering");
+ }
+ shim_result_with_rssi_callback_ = nullptr;
+}
+
+void Inquiry::impl::RegisterExtendedInquiryResult(shim::ExtendedInquiryResultCallback callback) {
+ if (shim_result_with_rssi_callback_ != nullptr) {
+ LOG_WARN("Registering extended inquiry result without unregistering");
+ }
+ shim_extended_result_callback_ = callback;
+}
+
+void Inquiry::impl::UnregisterExtendedInquiryResult() {
+ if (shim_extended_result_callback_ == nullptr) {
+ LOG_WARN("Unregistering extended inquiry result without registering");
+ }
+ shim_extended_result_callback_ = nullptr;
+}
+
+void Inquiry::impl::RegisterInquiryComplete(shim::InquiryCompleteCallback callback) {
+ if (shim_result_with_rssi_callback_ != nullptr) {
+ LOG_WARN("Registering inquiry complete without unregistering");
+ }
+ shim_complete_callback_ = callback;
+}
+
+void Inquiry::impl::UnregisterInquiryComplete() {
+ if (shim_result_with_rssi_callback_ == nullptr) {
+ LOG_WARN("Unregistering inquiry complete without registering");
+ }
+ shim_complete_callback_ = nullptr;
+}
+
+void Inquiry::impl::RegisterInquiryCancelComplete(shim::InquiryCancelCompleteCallback callback) {
+ if (shim_cancel_complete_callback_ != nullptr) {
+ LOG_WARN("Registering inquiry cancel complete without unregistering");
+ }
+ shim_cancel_complete_callback_ = callback;
+}
+
+void Inquiry::impl::UnregisterInquiryCancelComplete() {
+ if (shim_cancel_complete_callback_ == nullptr) {
+ LOG_WARN("Unregistering inquiry cancel complete without registering");
+ }
+ shim_cancel_complete_callback_ = nullptr;
+}
+
+Inquiry::impl::impl(neighbor::InquiryModule* inquiry_module) : module_(inquiry_module) {
+ neighbor::InquiryCallbacks inquiry_callbacks;
+ inquiry_callbacks.result = std::bind(&Inquiry::impl::Result, this, std::placeholders::_1);
+ inquiry_callbacks.result_with_rssi = std::bind(&Inquiry::impl::ResultWithRssi, this, std::placeholders::_1);
+ inquiry_callbacks.extended_result = std::bind(&Inquiry::impl::ExtendedResult, this, std::placeholders::_1);
+ inquiry_callbacks.complete = std::bind(&Inquiry::impl::Complete, this, std::placeholders::_1);
+
+ module_->RegisterCallbacks(inquiry_callbacks);
+}
+
+Inquiry::impl::~impl() {
+ module_->UnregisterCallbacks();
+}
+
+void Inquiry::StartGeneralInquiry(uint8_t inquiry_length, uint8_t num_responses) {
+ return pimpl_->module_->StartGeneralInquiry(inquiry_length, num_responses);
+}
+
+void Inquiry::StartLimitedInquiry(uint8_t inquiry_length, uint8_t num_responses) {
+ return pimpl_->module_->StartLimitedInquiry(inquiry_length, num_responses);
+}
+
+void Inquiry::StopInquiry() {
+ return pimpl_->module_->StopInquiry();
+}
+
+bool Inquiry::IsGeneralInquiryActive() const {
+ return pimpl_->module_->IsGeneralInquiryActive();
+}
+
+bool Inquiry::IsLimitedInquiryActive() const {
+ return pimpl_->module_->IsLimitedInquiryActive();
+}
+
+void Inquiry::StartGeneralPeriodicInquiry(uint8_t inquiry_length, uint8_t num_responses, uint16_t max_delay,
+ uint16_t min_delay) {
+ return pimpl_->module_->StartGeneralPeriodicInquiry(inquiry_length, num_responses, max_delay, min_delay);
+}
+
+void Inquiry::StartLimitedPeriodicInquiry(uint8_t inquiry_length, uint8_t num_responses, uint16_t max_delay,
+ uint16_t min_delay) {
+ return pimpl_->module_->StartLimitedPeriodicInquiry(inquiry_length, num_responses, max_delay, min_delay);
+}
+
+void Inquiry::StopPeriodicInquiry() {
+ return pimpl_->module_->StopPeriodicInquiry();
+}
+
+bool Inquiry::IsGeneralPeriodicInquiryActive() const {
+ return pimpl_->module_->IsGeneralPeriodicInquiryActive();
+}
+
+bool Inquiry::IsLimitedPeriodicInquiryActive() const {
+ return pimpl_->module_->IsLimitedPeriodicInquiryActive();
+}
+
+void Inquiry::SetInterlacedScan() {
+ pimpl_->module_->SetInterlacedScan();
+}
+
+void Inquiry::SetStandardScan() {
+ pimpl_->module_->SetStandardScan();
+}
+
+void Inquiry::SetScanActivity(uint16_t interval, uint16_t window) {
+ neighbor::ScanParameters params{
+ .interval = static_cast<neighbor::ScanInterval>(interval),
+ .window = static_cast<neighbor::ScanWindow>(window),
+ };
+ pimpl_->module_->SetScanActivity(params);
+}
+
+void Inquiry::GetScanActivity(uint16_t& interval, uint16_t& window) const {
+ neighbor::ScanParameters params = pimpl_->module_->GetScanActivity();
+
+ interval = static_cast<uint16_t>(params.interval);
+ window = static_cast<uint16_t>(params.window);
+}
+
+void Inquiry::SetStandardInquiryResultMode() {
+ pimpl_->module_->SetStandardInquiryResultMode();
+}
+
+void Inquiry::SetInquiryWithRssiResultMode() {
+ pimpl_->module_->SetInquiryWithRssiResultMode();
+}
+
+void Inquiry::SetExtendedInquiryResultMode() {
+ pimpl_->module_->SetExtendedInquiryResultMode();
+}
+
+void Inquiry::RegisterInquiryResult(shim::InquiryResultCallback callback) {
+ pimpl_->RegisterInquiryResult(callback);
+}
+
+void Inquiry::UnregisterInquiryResult() {
+ pimpl_->UnregisterInquiryResult();
+}
+
+void Inquiry::RegisterInquiryResultWithRssi(shim::InquiryResultWithRssiCallback callback) {
+ pimpl_->RegisterInquiryResultWithRssi(callback);
+}
+
+void Inquiry::UnregisterInquiryResultWithRssi() {
+ pimpl_->UnregisterInquiryResultWithRssi();
+}
+
+void Inquiry::RegisterExtendedInquiryResult(shim::ExtendedInquiryResultCallback callback) {
+ pimpl_->RegisterExtendedInquiryResult(callback);
+}
+
+void Inquiry::UnregisterExtendedInquiryResult() {
+ pimpl_->UnregisterExtendedInquiryResult();
+}
+
+void Inquiry::RegisterInquiryComplete(InquiryCompleteCallback callback) {
+ pimpl_->RegisterInquiryComplete(callback);
+}
+
+void Inquiry::UnregisterInquiryComplete() {
+ pimpl_->UnregisterInquiryComplete();
+}
+
+void Inquiry::RegisterInquiryCancelComplete(InquiryCancelCompleteCallback callback) {
+ pimpl_->RegisterInquiryCancelComplete(callback);
+}
+
+void Inquiry::UnregisterInquiryCancelComplete() {
+ pimpl_->UnregisterInquiryCancelComplete();
+}
+
+/**
+ * Module methods
+ */
+void Inquiry::ListDependencies(ModuleList* list) {
+ list->add<neighbor::InquiryModule>();
+}
+
+void Inquiry::Start() {
+ pimpl_ = std::make_unique<impl>(GetDependency<neighbor::InquiryModule>());
+}
+
+void Inquiry::Stop() {
+ pimpl_.reset();
+}
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/inquiry.h b/gd/shim/inquiry.h
new file mode 100644
index 0000000..9051d70
--- /dev/null
+++ b/gd/shim/inquiry.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include "module.h"
+#include "shim/iinquiry.h"
+
+namespace bluetooth {
+namespace shim {
+
+class Inquiry : public bluetooth::Module, public bluetooth::shim::IInquiry {
+ public:
+ void StartGeneralInquiry(uint8_t duration, uint8_t max_responses) override;
+ void StartLimitedInquiry(uint8_t duration, uint8_t max_responses) override;
+ void StopInquiry() override;
+ bool IsGeneralInquiryActive() const override;
+ bool IsLimitedInquiryActive() const override;
+
+ void StartGeneralPeriodicInquiry(uint8_t duration, uint8_t max_responses, uint16_t max_delay,
+ uint16_t min_delay) override;
+ void StartLimitedPeriodicInquiry(uint8_t duration, uint8_t max_responses, uint16_t max_delay,
+ uint16_t min_delay) override;
+ void StopPeriodicInquiry() override;
+ bool IsGeneralPeriodicInquiryActive() const override;
+ bool IsLimitedPeriodicInquiryActive() const override;
+
+ void SetInterlacedScan() override;
+ void SetStandardScan() override;
+
+ void SetScanActivity(uint16_t interval, uint16_t window) override;
+ void GetScanActivity(uint16_t& interval, uint16_t& window) const override;
+
+ void SetStandardInquiryResultMode() override;
+ void SetInquiryWithRssiResultMode() override;
+ void SetExtendedInquiryResultMode() override;
+
+ void RegisterInquiryResult(InquiryResultCallback callback) override;
+ void UnregisterInquiryResult() override;
+ void RegisterInquiryResultWithRssi(InquiryResultWithRssiCallback callback) override;
+ void UnregisterInquiryResultWithRssi() override;
+ void RegisterExtendedInquiryResult(ExtendedInquiryResultCallback callback) override;
+ void UnregisterExtendedInquiryResult() override;
+ void RegisterInquiryComplete(InquiryCompleteCallback callback) override;
+ void UnregisterInquiryComplete() override;
+ void RegisterInquiryCancelComplete(InquiryCancelCompleteCallback callback) override;
+ void UnregisterInquiryCancelComplete() override;
+
+ Inquiry() = default;
+ ~Inquiry() = default;
+
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override; // Module
+ void Start() override; // Module
+ void Stop() override; // Module
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+ DISALLOW_COPY_AND_ASSIGN(Inquiry);
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/ipage.h b/gd/shim/ipage.h
new file mode 100644
index 0000000..28c2762
--- /dev/null
+++ b/gd/shim/ipage.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <cstdint>
+
+/**
+ * The gd API exported to the legacy api
+ */
+namespace bluetooth {
+namespace shim {
+
+struct IPage {
+ virtual void SetScanActivity(uint16_t interval, uint16_t window) = 0;
+ virtual void GetScanActivity(uint16_t& interval, uint16_t& window) const = 0;
+
+ virtual void SetInterlacedScan() = 0;
+ virtual void SetStandardScan() = 0;
+
+ virtual ~IPage() {}
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/iscanning.h b/gd/shim/iscanning.h
new file mode 100644
index 0000000..ddaabb6
--- /dev/null
+++ b/gd/shim/iscanning.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+/**
+ * The gd API exported to the legacy api
+ */
+namespace bluetooth {
+namespace shim {
+
+struct IScanning {
+ virtual ~IScanning() {}
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/istack.h b/gd/shim/istack.h
new file mode 100644
index 0000000..f432dac
--- /dev/null
+++ b/gd/shim/istack.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+/**
+ * Legacy stack manipulation methods to allow the legacy stack to start
+ * and stop the stack, and to provide Gd shim stack module API access.
+ */
+namespace bluetooth {
+namespace shim {
+
+struct IAdvertising;
+struct IController;
+struct IConnectability;
+struct IDiscoverability;
+struct IHciLayer;
+struct IInquiry;
+struct IName;
+struct IL2cap;
+struct IPage;
+struct IScanning;
+
+struct IStack {
+ virtual void Start() = 0;
+ virtual void Stop() = 0;
+
+ virtual IAdvertising* GetAdvertising() = 0;
+ virtual IController* GetController() = 0;
+ virtual IConnectability* GetConnectability() = 0;
+ virtual IDiscoverability* GetDiscoverability() = 0;
+ virtual IHciLayer* GetHciLayer() = 0;
+ virtual IInquiry* GetInquiry() = 0;
+ virtual IName* GetName() = 0;
+ virtual IL2cap* GetL2cap() = 0;
+ virtual IPage* GetPage() = 0;
+ virtual IScanning* GetScanning() = 0;
+
+ virtual ~IStack() {}
+};
+
+IStack* GetGabeldorscheStack();
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/l2cap.cc b/gd/shim/l2cap.cc
new file mode 100644
index 0000000..d703972
--- /dev/null
+++ b/gd/shim/l2cap.cc
@@ -0,0 +1,526 @@
+/*
+ * Copyright 2019 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.
+ */
+#define LOG_TAG "bt_gd_shim"
+
+#include <cstdint>
+#include <functional>
+#include <future>
+#include <memory>
+#include <mutex>
+#include <queue>
+#include <unordered_map>
+#include <vector>
+
+#include "common/bind.h"
+#include "hci/address.h"
+#include "hci/hci_packets.h"
+#include "l2cap/classic/dynamic_channel_manager.h"
+#include "l2cap/classic/l2cap_classic_module.h"
+#include "l2cap/psm.h"
+#include "l2cap/security_policy.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "packet/packet_view.h"
+#include "packet/raw_builder.h"
+#include "shim/l2cap.h"
+
+namespace bluetooth {
+namespace shim {
+
+const ModuleFactory L2cap::Factory = ModuleFactory([]() { return new L2cap(); });
+
+using ConnectionInterfaceDescriptor = uint16_t;
+static const ConnectionInterfaceDescriptor kInvalidConnectionInterfaceDescriptor = 0;
+static const ConnectionInterfaceDescriptor kStartConnectionInterfaceDescriptor = 64;
+static const ConnectionInterfaceDescriptor kMaxConnections = UINT16_MAX - kStartConnectionInterfaceDescriptor - 1;
+
+using ServiceInterfaceCallback =
+ std::function<void(l2cap::Psm psm, l2cap::classic::DynamicChannelManager::RegistrationResult result)>;
+using ConnectionInterfaceCallback =
+ std::function<void(l2cap::Psm psm, std::unique_ptr<l2cap::classic::DynamicChannel>)>;
+
+std::unique_ptr<packet::RawBuilder> MakeUniquePacket(const uint8_t* data, size_t len) {
+ packet::RawBuilder builder;
+ std::vector<uint8_t> bytes(data, data + len);
+ auto payload = std::make_unique<packet::RawBuilder>();
+ payload->AddOctets(bytes);
+ return payload;
+}
+
+class ConnectionInterface {
+ public:
+ ConnectionInterface(ConnectionInterfaceDescriptor cid, std::unique_ptr<l2cap::classic::DynamicChannel> channel,
+ os::Handler* handler)
+ : cid_(cid), channel_(std::move(channel)), handler_(handler), on_data_ready_callback_(nullptr),
+ on_connection_closed_callback_(nullptr), address_(channel_->GetDevice()) {
+ channel_->RegisterOnCloseCallback(
+ handler_, common::BindOnce(&ConnectionInterface::OnConnectionClosed, common::Unretained(this)));
+ channel_->GetQueueUpEnd()->RegisterDequeue(
+ handler_, common::Bind(&ConnectionInterface::OnReadReady, common::Unretained(this)));
+ dequeue_registered_ = true;
+ }
+
+ ~ConnectionInterface() {
+ ASSERT(!dequeue_registered_);
+ }
+
+ void OnReadReady() {
+ std::unique_ptr<packet::PacketView<packet::kLittleEndian>> packet = channel_->GetQueueUpEnd()->TryDequeue();
+ if (packet == nullptr) {
+ LOG_WARN("Got read ready from gd l2cap but no packet is ready");
+ return;
+ }
+ std::vector<const uint8_t> data(packet->begin(), packet->end());
+ ASSERT(on_data_ready_callback_ != nullptr);
+ on_data_ready_callback_(cid_, data);
+ }
+
+ void SetReadDataReadyCallback(ReadDataReadyCallback on_data_ready) {
+ ASSERT(on_data_ready != nullptr);
+ ASSERT(on_data_ready_callback_ == nullptr);
+ on_data_ready_callback_ = on_data_ready;
+ }
+
+ std::unique_ptr<packet::BasePacketBuilder> WriteReady() {
+ auto data = std::move(write_queue_.front());
+ write_queue_.pop();
+ if (write_queue_.empty()) {
+ channel_->GetQueueUpEnd()->UnregisterEnqueue();
+ enqueue_registered_ = false;
+ }
+ return data;
+ }
+
+ void Write(std::unique_ptr<packet::RawBuilder> packet) {
+ LOG_DEBUG("Writing packet cid:%hd size:%zd", cid_, packet->size());
+ write_queue_.push(std::move(packet));
+ if (!enqueue_registered_) {
+ enqueue_registered_ = true;
+ channel_->GetQueueUpEnd()->RegisterEnqueue(
+ handler_, common::Bind(&ConnectionInterface::WriteReady, common::Unretained(this)));
+ }
+ }
+
+ void Close() {
+ if (dequeue_registered_) {
+ channel_->GetQueueUpEnd()->UnregisterDequeue();
+ dequeue_registered_ = false;
+ }
+ ASSERT(write_queue_.empty());
+ channel_->Close();
+ }
+
+ void OnConnectionClosed(hci::ErrorCode error_code) {
+ LOG_DEBUG("Channel interface closed reason:%s cid:%hd device:%s", hci::ErrorCodeText(error_code).c_str(), cid_,
+ address_.ToString().c_str());
+ ASSERT(on_connection_closed_callback_ != nullptr);
+ on_connection_closed_callback_(cid_, static_cast<int>(error_code));
+ }
+
+ void SetConnectionClosedCallback(::bluetooth::shim::ConnectionClosedCallback on_connection_closed) {
+ ASSERT(on_connection_closed != nullptr);
+ ASSERT(on_connection_closed_callback_ == nullptr);
+ on_connection_closed_callback_ = std::move(on_connection_closed);
+ }
+
+ private:
+ const ConnectionInterfaceDescriptor cid_;
+ const std::unique_ptr<l2cap::classic::DynamicChannel> channel_;
+ os::Handler* handler_;
+
+ ReadDataReadyCallback on_data_ready_callback_;
+ ConnectionClosedCallback on_connection_closed_callback_;
+
+ const hci::Address address_;
+
+ std::queue<std::unique_ptr<packet::PacketBuilder<hci::kLittleEndian>>> write_queue_;
+
+ bool enqueue_registered_{false};
+ bool dequeue_registered_{false};
+};
+
+struct ConnectionInterfaceManager {
+ public:
+ ConnectionInterfaceDescriptor AddChannel(std::unique_ptr<l2cap::classic::DynamicChannel> channel);
+ void RemoveConnection(ConnectionInterfaceDescriptor cid);
+
+ void SetReadDataReadyCallback(ConnectionInterfaceDescriptor cid, ReadDataReadyCallback on_data_ready);
+ void SetConnectionClosedCallback(ConnectionInterfaceDescriptor cid, ConnectionClosedCallback on_closed);
+
+ bool Write(ConnectionInterfaceDescriptor cid, std::unique_ptr<packet::RawBuilder> packet);
+
+ size_t NumberOfActiveConnections() const {
+ return cid_to_interface_map_.size();
+ }
+
+ void GeneralCallback(ConnectionOpenCallback on_open, hci::Address address, l2cap::Psm psm,
+ ConnectionInterfaceDescriptor cid) {
+ on_open(address.ToString(), static_cast<uint16_t>(psm), static_cast<uint16_t>(cid));
+ }
+
+ void ConnectionOpened(ConnectionOpenCallback on_open, hci::Address address, l2cap::Psm psm,
+ ConnectionInterfaceDescriptor cid) {
+ LOG_DEBUG("%s address:%s psm:%hd cid:%hd", __func__, address.ToString().c_str(), psm, cid);
+ handler_->Post(common::BindOnce(&ConnectionInterfaceManager::GeneralCallback, common::Unretained(this), on_open,
+ address, psm, cid));
+ // TODO(cmanton) queue this pending connection address/psm tuple up for deletion
+ // There may be multiple, so only remove one
+ }
+
+ void ConnectionFailed(hci::Address address, l2cap::Psm psm) {
+ LOG_DEBUG("%s Connection Failed", __func__);
+ // TODO(cmanton) queue this pending connection address/psm tuple up for deletion
+ // There may be multiple, so only remove one
+ }
+
+ ConnectionInterfaceManager(os::Handler* handler);
+
+ private:
+ os::Handler* handler_;
+ ConnectionInterfaceDescriptor current_connection_interface_descriptor_;
+
+ bool HasResources() const;
+ bool Exists(ConnectionInterfaceDescriptor id) const;
+
+ std::unordered_map<ConnectionInterfaceDescriptor, std::unique_ptr<ConnectionInterface>> cid_to_interface_map_;
+ ConnectionInterfaceDescriptor AllocateConnectionInterfaceDescriptor();
+ ConnectionInterfaceManager() = delete;
+};
+
+ConnectionInterfaceManager::ConnectionInterfaceManager(os::Handler* handler)
+ : handler_(handler), current_connection_interface_descriptor_(kStartConnectionInterfaceDescriptor) {}
+
+bool ConnectionInterfaceManager::Exists(ConnectionInterfaceDescriptor cid) const {
+ return cid_to_interface_map_.find(cid) != cid_to_interface_map_.end();
+}
+
+ConnectionInterfaceDescriptor ConnectionInterfaceManager::AllocateConnectionInterfaceDescriptor() {
+ ASSERT(HasResources());
+ while (Exists(current_connection_interface_descriptor_)) {
+ if (++current_connection_interface_descriptor_ == kInvalidConnectionInterfaceDescriptor) {
+ current_connection_interface_descriptor_ = kStartConnectionInterfaceDescriptor;
+ }
+ }
+ return current_connection_interface_descriptor_++;
+}
+
+ConnectionInterfaceDescriptor ConnectionInterfaceManager::AddChannel(
+ std::unique_ptr<l2cap::classic::DynamicChannel> channel) {
+ if (!HasResources()) {
+ return kInvalidConnectionInterfaceDescriptor;
+ }
+ ConnectionInterfaceDescriptor cid = AllocateConnectionInterfaceDescriptor();
+
+ auto channel_interface = std::make_unique<ConnectionInterface>(cid, std::move(channel), handler_);
+ cid_to_interface_map_[cid] = std::move(channel_interface);
+ return cid;
+}
+
+void ConnectionInterfaceManager::RemoveConnection(ConnectionInterfaceDescriptor cid) {
+ ASSERT(cid_to_interface_map_.count(cid) == 1);
+ cid_to_interface_map_.find(cid)->second->Close();
+ cid_to_interface_map_.erase(cid);
+}
+
+bool ConnectionInterfaceManager::HasResources() const {
+ return cid_to_interface_map_.size() < kMaxConnections;
+}
+
+void ConnectionInterfaceManager::SetReadDataReadyCallback(ConnectionInterfaceDescriptor cid,
+ ReadDataReadyCallback on_data_ready) {
+ ASSERT(Exists(cid));
+ return cid_to_interface_map_[cid]->SetReadDataReadyCallback(on_data_ready);
+}
+
+void ConnectionInterfaceManager::SetConnectionClosedCallback(ConnectionInterfaceDescriptor cid,
+ ConnectionClosedCallback on_closed) {
+ ASSERT(Exists(cid));
+ return cid_to_interface_map_[cid]->SetConnectionClosedCallback(on_closed);
+}
+
+bool ConnectionInterfaceManager::Write(ConnectionInterfaceDescriptor cid, std::unique_ptr<packet::RawBuilder> packet) {
+ if (!Exists(cid)) {
+ return false;
+ }
+ cid_to_interface_map_[cid]->Write(std::move(packet));
+ return true;
+}
+
+class PendingConnection {
+ public:
+ PendingConnection(ConnectionInterfaceManager* connection_interface_manager, l2cap::Psm psm, hci::Address address,
+ ConnectionOpenCallback on_open, std::promise<uint16_t> completed)
+ : connection_interface_manager_(connection_interface_manager), psm_(psm), address_(address),
+ on_open_(std::move(on_open)), completed_(std::move(completed)) {}
+
+ void OnConnectionOpen(std::unique_ptr<l2cap::classic::DynamicChannel> channel) {
+ LOG_DEBUG("Local initiated connection is open to device:%s for psm:%hd", address_.ToString().c_str(), psm_);
+ ConnectionInterfaceDescriptor cid = connection_interface_manager_->AddChannel(std::move(channel));
+ completed_.set_value(cid);
+ // Attempt to avoid async race condition with upper stack
+ std::this_thread::yield();
+ connection_interface_manager_->ConnectionOpened(std::move(on_open_), address_, psm_, cid);
+ }
+
+ void OnConnectionFailure(l2cap::classic::DynamicChannelManager::ConnectionResult result) {
+ LOG_DEBUG("Connection failed to device:%s for psm:%hd", address_.ToString().c_str(), psm_);
+ switch (result.connection_result_code) {
+ case l2cap::classic::DynamicChannelManager::ConnectionResultCode::SUCCESS:
+ LOG_WARN("Connection failed result:success hci:%s", hci::ErrorCodeText(result.hci_error).c_str());
+ break;
+ case l2cap::classic::DynamicChannelManager::ConnectionResultCode::FAIL_NO_SERVICE_REGISTERED:
+ LOG_DEBUG("Connection failed result:no service registered hci:%s",
+ hci::ErrorCodeText(result.hci_error).c_str());
+ break;
+ case l2cap::classic::DynamicChannelManager::ConnectionResultCode::FAIL_HCI_ERROR:
+ LOG_DEBUG("Connection failed result:hci error hci:%s", hci::ErrorCodeText(result.hci_error).c_str());
+ break;
+ case l2cap::classic::DynamicChannelManager::ConnectionResultCode::FAIL_L2CAP_ERROR:
+ LOG_DEBUG("Connection failed result:l2cap error hci:%s l2cap:%s", hci::ErrorCodeText(result.hci_error).c_str(),
+ l2cap::ConnectionResponseResultText(result.l2cap_connection_response_result).c_str());
+ break;
+ }
+ completed_.set_value(kInvalidConnectionInterfaceDescriptor);
+ connection_interface_manager_->ConnectionFailed(address_, psm_);
+ }
+
+ private:
+ ConnectionInterfaceManager* connection_interface_manager_;
+ const l2cap::Psm psm_;
+ const hci::Address address_;
+ ConnectionOpenCallback on_open_;
+ std::promise<uint16_t> completed_;
+};
+
+class ServiceInterface {
+ public:
+ ServiceInterface(ConnectionInterfaceManager* connection_interface_manager, l2cap::Psm psm,
+ ConnectionOpenCallback on_open, std::promise<void> completed)
+ : connection_interface_manager_(connection_interface_manager), psm_(psm), on_open_(on_open),
+ completed_(std::move(completed)) {}
+
+ void OnRegistrationComplete(l2cap::classic::DynamicChannelManager::RegistrationResult result,
+ std::unique_ptr<l2cap::classic::DynamicChannelService> service) {
+ ASSERT(service_ == nullptr);
+ ASSERT(psm_ == service->GetPsm());
+ LOG_DEBUG("Registration is complete for psm:%hd", psm_);
+ service_ = std::move(service);
+ completed_.set_value();
+ }
+
+ void OnConnectionOpen(std::unique_ptr<l2cap::classic::DynamicChannel> channel) {
+ LOG_DEBUG("Remote initiated connection is open from device:%s for psm:%hd", channel->GetDevice().ToString().c_str(),
+ psm_);
+ hci::Address address = channel->GetDevice();
+ ConnectionInterfaceDescriptor cid = connection_interface_manager_->AddChannel(std::move(channel));
+ connection_interface_manager_->ConnectionOpened(on_open_, address, psm_, cid);
+ }
+
+ l2cap::SecurityPolicy GetSecurityPolicy() const {
+ return security_policy_;
+ }
+
+ void RegisterService(
+ std::function<void(l2cap::Psm, l2cap::SecurityPolicy security_policy,
+ l2cap::classic::DynamicChannelManager::OnRegistrationCompleteCallback on_registration_complete,
+ l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_connection_open)>
+ func) {
+ func(psm_, security_policy_, common::BindOnce(&ServiceInterface::OnRegistrationComplete, common::Unretained(this)),
+ common::Bind(&ServiceInterface::OnConnectionOpen, common::Unretained(this)));
+ }
+
+ private:
+ ConnectionInterfaceManager* connection_interface_manager_;
+ const l2cap::Psm psm_;
+ ConnectionOpenCallback on_open_;
+ std::promise<void> completed_;
+
+ std::unique_ptr<l2cap::classic::DynamicChannelService> service_;
+
+ const l2cap::SecurityPolicy security_policy_;
+};
+
+struct L2cap::impl {
+ void RegisterService(l2cap::Psm psm, ConnectionOpenCallback on_open, std::promise<void> completed);
+ void UnregisterService(l2cap::Psm psm);
+
+ void CreateConnection(l2cap::Psm psm, hci::Address address, ConnectionOpenCallback on_open,
+ std::promise<uint16_t> completed);
+ void CloseConnection(ConnectionInterfaceDescriptor cid);
+
+ void SetReadDataReadyCallback(ConnectionInterfaceDescriptor cid, ReadDataReadyCallback on_data_ready);
+ void SetConnectionClosedCallback(ConnectionInterfaceDescriptor cid, ConnectionClosedCallback on_closed);
+
+ void Write(ConnectionInterfaceDescriptor cid, std::unique_ptr<packet::RawBuilder> packet);
+
+ void SendLoopbackResponse(std::function<void()> function);
+
+ impl(L2cap& module, l2cap::classic::L2capClassicModule* l2cap_module);
+
+ private:
+ L2cap& module_;
+ l2cap::classic::L2capClassicModule* l2cap_module_;
+ os::Handler* handler_;
+ ConnectionInterfaceManager connection_interface_manager_;
+
+ std::unique_ptr<l2cap::classic::DynamicChannelManager> dynamic_channel_manager_;
+
+ std::unordered_map<l2cap::Psm, std::shared_ptr<ServiceInterface>> psm_to_service_interface_map_;
+ std::unordered_map<l2cap::Psm, std::shared_ptr<PendingConnection>> psm_to_pending_connection_map_;
+};
+
+L2cap::impl::impl(L2cap& module, l2cap::classic::L2capClassicModule* l2cap_module)
+ : module_(module), l2cap_module_(l2cap_module), handler_(module_.GetHandler()),
+ connection_interface_manager_(handler_) {
+ dynamic_channel_manager_ = l2cap_module_->GetDynamicChannelManager();
+}
+
+void L2cap::impl::RegisterService(l2cap::Psm psm, ConnectionOpenCallback on_open, std::promise<void> completed) {
+ ASSERT(psm_to_service_interface_map_.find(psm) == psm_to_service_interface_map_.end());
+
+ auto service_interface =
+ std::make_shared<ServiceInterface>(&connection_interface_manager_, psm, on_open, std::move(completed));
+ psm_to_service_interface_map_.emplace(psm, service_interface);
+
+ // TODO(cmanton): Use the configuration option from user
+ service_interface->RegisterService(
+ [this](l2cap::Psm psm, l2cap::SecurityPolicy security_policy,
+ l2cap::classic::DynamicChannelManager::OnRegistrationCompleteCallback on_registration_complete,
+ l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_connection_open) {
+ bool rc = dynamic_channel_manager_->RegisterService(psm, l2cap::classic::DynamicChannelConfigurationOption(),
+ security_policy, std::move(on_registration_complete),
+ on_connection_open, handler_);
+ ASSERT_LOG(rc == true, "Failed to register classic service");
+ });
+}
+
+void L2cap::impl::UnregisterService(l2cap::Psm psm) {
+ psm_to_service_interface_map_.erase(psm);
+}
+
+void L2cap::impl::CreateConnection(l2cap::Psm psm, hci::Address address, ConnectionOpenCallback on_open,
+ std::promise<uint16_t> completed) {
+ LOG_DEBUG("Initiating classic connection to psm:%hd device:%s", psm, address.ToString().c_str());
+ auto pending_connection = std::make_shared<PendingConnection>(&connection_interface_manager_, psm, address,
+ std::move(on_open), std::move(completed));
+ // TODO(cmanton) hash psm/address pair into unordered map for pending_connection
+ // This is ok for now
+ psm_to_pending_connection_map_[psm] = pending_connection;
+ // TODO(cmanton): Add ERTM mode support by changing configuratio_option in ConnectChannel()
+ bool rc = dynamic_channel_manager_->ConnectChannel(
+ address, l2cap::classic::DynamicChannelConfigurationOption(), psm,
+ common::Bind(&PendingConnection::OnConnectionOpen, common::Unretained(pending_connection.get())),
+ common::BindOnce(&PendingConnection::OnConnectionFailure, common::Unretained(pending_connection.get())),
+ handler_);
+ ASSERT_LOG(rc == true, "Failed to create classic connection");
+}
+
+void L2cap::impl::CloseConnection(ConnectionInterfaceDescriptor cid) {
+ connection_interface_manager_.RemoveConnection(cid);
+}
+
+void L2cap::impl::SetReadDataReadyCallback(ConnectionInterfaceDescriptor cid, ReadDataReadyCallback on_data_ready) {
+ connection_interface_manager_.SetReadDataReadyCallback(cid, on_data_ready);
+}
+
+void L2cap::impl::SetConnectionClosedCallback(ConnectionInterfaceDescriptor cid, ConnectionClosedCallback on_closed) {
+ connection_interface_manager_.SetConnectionClosedCallback(cid, std::move(on_closed));
+}
+
+void L2cap::impl::Write(ConnectionInterfaceDescriptor cid, std::unique_ptr<packet::RawBuilder> packet) {
+ connection_interface_manager_.Write(cid, std::move(packet));
+}
+
+void L2cap::impl::SendLoopbackResponse(std::function<void()> function) {
+ function();
+}
+
+void L2cap::RegisterService(uint16_t raw_psm, ConnectionOpenCallback on_open, std::promise<void> completed) {
+ l2cap::Psm psm{raw_psm};
+ GetHandler()->Post(common::BindOnce(&L2cap::impl::RegisterService, common::Unretained(pimpl_.get()), psm, on_open,
+ std::move(completed)));
+}
+
+void L2cap::UnregisterService(uint16_t raw_psm) {
+ l2cap::Psm psm{raw_psm};
+ GetHandler()->Post(common::Bind(&L2cap::impl::UnregisterService, common::Unretained(pimpl_.get()), psm));
+}
+
+void L2cap::CreateConnection(uint16_t raw_psm, const std::string address_string, ConnectionOpenCallback on_open,
+ std::promise<uint16_t> completed) {
+ l2cap::Psm psm{raw_psm};
+ hci::Address address;
+ hci::Address::FromString(address_string, address);
+
+ GetHandler()->Post(common::BindOnce(&L2cap::impl::CreateConnection, common::Unretained(pimpl_.get()), psm, address,
+ on_open, std::move(completed)));
+}
+
+void L2cap::CloseConnection(uint16_t raw_cid) {
+ ConnectionInterfaceDescriptor cid(raw_cid);
+ GetHandler()->Post(common::Bind(&L2cap::impl::CloseConnection, common::Unretained(pimpl_.get()), cid));
+}
+
+void L2cap::SetReadDataReadyCallback(uint16_t raw_cid, ReadDataReadyCallback on_data_ready) {
+ ConnectionInterfaceDescriptor cid(raw_cid);
+ GetHandler()->Post(
+ common::Bind(&L2cap::impl::SetReadDataReadyCallback, common::Unretained(pimpl_.get()), cid, on_data_ready));
+}
+
+void L2cap::SetConnectionClosedCallback(uint16_t raw_cid, ConnectionClosedCallback on_closed) {
+ ConnectionInterfaceDescriptor cid(raw_cid);
+ GetHandler()->Post(common::Bind(&L2cap::impl::SetConnectionClosedCallback, common::Unretained(pimpl_.get()), cid,
+ std::move(on_closed)));
+}
+
+void L2cap::Write(uint16_t raw_cid, const uint8_t* data, size_t len) {
+ ConnectionInterfaceDescriptor cid(raw_cid);
+ auto packet = MakeUniquePacket(data, len);
+ GetHandler()->Post(common::BindOnce(&L2cap::impl::Write, common::Unretained(pimpl_.get()), cid, std::move(packet)));
+}
+
+void L2cap::WriteFlushable(uint16_t raw_cid, const uint8_t* data, size_t len) {
+ LOG_WARN("UNIMPLEMENTED Write flushable");
+ return Write(raw_cid, data, len);
+}
+
+void L2cap::WriteNonFlushable(uint16_t raw_cid, const uint8_t* data, size_t len) {
+ LOG_WARN("UNIMPLEMENTED Write non flushable");
+ return Write(raw_cid, data, len);
+}
+
+void L2cap::SendLoopbackResponse(std::function<void()> function) {
+ GetHandler()->Post(common::BindOnce(&L2cap::impl::SendLoopbackResponse, common::Unretained(pimpl_.get()), function));
+}
+
+/**
+ * Module methods
+ */
+void L2cap::ListDependencies(ModuleList* list) {
+ list->add<l2cap::classic::L2capClassicModule>();
+}
+
+void L2cap::Start() {
+ pimpl_ = std::make_unique<impl>(*this, GetDependency<l2cap::classic::L2capClassicModule>());
+}
+
+void L2cap::Stop() {
+ pimpl_.reset();
+}
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/l2cap.h b/gd/shim/l2cap.h
new file mode 100644
index 0000000..955d20c
--- /dev/null
+++ b/gd/shim/l2cap.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <cstdint>
+#include <functional>
+#include <future>
+#include <memory>
+#include <string>
+
+#include "module.h"
+#include "shim/il2cap.h"
+
+namespace bluetooth {
+namespace shim {
+
+class L2cap : public bluetooth::Module, public bluetooth::shim::IL2cap {
+ public:
+ void RegisterService(uint16_t psm, ConnectionOpenCallback on_open, std::promise<void> completed) override;
+ void UnregisterService(uint16_t psm) override;
+
+ void CreateConnection(uint16_t psm, const std::string address_string, ConnectionOpenCallback on_open,
+ std::promise<uint16_t> completed) override;
+ void CloseConnection(uint16_t cid) override;
+
+ void SetReadDataReadyCallback(uint16_t cid, ReadDataReadyCallback on_data_ready) override;
+ void SetConnectionClosedCallback(uint16_t cid, ConnectionClosedCallback on_closed) override;
+
+ void Write(uint16_t cid, const uint8_t* data, size_t len) override;
+ void WriteFlushable(uint16_t cid, const uint8_t* data, size_t len) override;
+ void WriteNonFlushable(uint16_t cid, const uint8_t* data, size_t len) override;
+
+ void SendLoopbackResponse(std::function<void()>) override;
+
+ L2cap() = default;
+ ~L2cap() = default;
+
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override; // Module
+ void Start() override; // Module
+ void Stop() override; // Module
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+ DISALLOW_COPY_AND_ASSIGN(L2cap);
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/name.cc b/gd/shim/name.cc
new file mode 100644
index 0000000..582d1ed
--- /dev/null
+++ b/gd/shim/name.cc
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2019 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.
+ */
+#define LOG_TAG "bt_gd_shim"
+
+#include <functional>
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include "hci/address.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "neighbor/name.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "shim/name.h"
+
+namespace bluetooth {
+namespace shim {
+
+struct Name::impl {
+ void ReadRemoteNameRequest(const hci::Address address, hci::PageScanRepetitionMode page_scan_repetition_mode,
+ uint16_t clock_offset, hci::ClockOffsetValid clock_offset_valid,
+ ReadRemoteNameCallback callback);
+ void CancelRemoteNameRequest(const hci::Address address, CancelRemoteNameCallback callback);
+
+ void OnReadRemoteName(hci::ErrorCode status, hci::Address address, std::array<uint8_t, 248> name);
+ void OnCancelRemoteName(hci::ErrorCode status, hci::Address address);
+
+ impl(neighbor::NameModule* module, os::Handler* handler);
+ ~impl();
+
+ private:
+ std::unordered_map<hci::Address, ReadRemoteNameCallback> address_to_read_remote_callback_map_;
+ std::unordered_map<hci::Address, CancelRemoteNameCallback> address_to_cancel_remote_callback_map_;
+
+ neighbor::NameModule* module_{nullptr};
+ os::Handler* handler_;
+};
+
+const ModuleFactory Name::Factory = ModuleFactory([]() { return new Name(); });
+
+void Name::impl::OnReadRemoteName(hci::ErrorCode status, hci::Address address, std::array<uint8_t, 248> name) {
+ LOG_DEBUG("%s from %s", __func__, address.ToString().c_str());
+ ASSERT(address_to_read_remote_callback_map_.find(address) != address_to_read_remote_callback_map_.end());
+ ReadRemoteNameCallback callback = address_to_read_remote_callback_map_[address];
+ address_to_read_remote_callback_map_.erase(address);
+ callback(address.ToString(), static_cast<uint8_t>(status), name);
+}
+
+void Name::impl::OnCancelRemoteName(hci::ErrorCode status, hci::Address address) {
+ LOG_DEBUG("%s from %s", __func__, address.ToString().c_str());
+ ASSERT(address_to_cancel_remote_callback_map_.find(address) != address_to_cancel_remote_callback_map_.end());
+ CancelRemoteNameCallback callback = address_to_cancel_remote_callback_map_[address];
+ address_to_cancel_remote_callback_map_.erase(address);
+ callback(address.ToString(), static_cast<uint8_t>(status));
+}
+
+void Name::impl::ReadRemoteNameRequest(const hci::Address address,
+ hci::PageScanRepetitionMode page_scan_repetition_mode, uint16_t clock_offset,
+ hci::ClockOffsetValid clock_offset_valid, ReadRemoteNameCallback callback) {
+ ASSERT(address_to_read_remote_callback_map_.find(address) == address_to_read_remote_callback_map_.end());
+ address_to_read_remote_callback_map_[address] = callback;
+ module_->ReadRemoteNameRequest(address, page_scan_repetition_mode, clock_offset, clock_offset_valid,
+ common::BindOnce(&Name::impl::OnReadRemoteName, common::Unretained(this)), handler_);
+}
+
+void Name::impl::CancelRemoteNameRequest(const hci::Address address, CancelRemoteNameCallback callback) {
+ ASSERT(address_to_cancel_remote_callback_map_.find(address) == address_to_cancel_remote_callback_map_.end());
+ address_to_cancel_remote_callback_map_[address] = callback;
+ module_->CancelRemoteNameRequest(address, common::BindOnce(&Name::impl::OnCancelRemoteName, common::Unretained(this)),
+ handler_);
+}
+
+Name::impl::impl(neighbor::NameModule* module, os::Handler* handler) : module_(module), handler_(handler) {}
+
+Name::impl::~impl() {}
+
+void Name::ReadRemoteNameRequest(std::string remote_address, ReadRemoteNameCallback callback) {
+ hci::Address address;
+ hci::Address::FromString(remote_address, address);
+
+ // TODO(cmanton) Use remote name request defaults for now
+ hci::PageScanRepetitionMode page_scan_repetition_mode = hci::PageScanRepetitionMode::R1;
+ uint16_t clock_offset = 0;
+ hci::ClockOffsetValid clock_offset_valid = hci::ClockOffsetValid::INVALID;
+ pimpl_->ReadRemoteNameRequest(address, page_scan_repetition_mode, clock_offset, clock_offset_valid, callback);
+}
+
+void Name::CancelRemoteNameRequest(std::string remote_address, CancelRemoteNameCallback callback) {
+ hci::Address address;
+ hci::Address::FromString(remote_address, address);
+ pimpl_->CancelRemoteNameRequest(address, callback);
+}
+
+/**
+ * Module methods
+ */
+void Name::ListDependencies(ModuleList* list) {
+ list->add<neighbor::NameModule>();
+}
+
+void Name::Start() {
+ pimpl_ = std::make_unique<impl>(GetDependency<neighbor::NameModule>(), GetHandler());
+}
+
+void Name::Stop() {
+ pimpl_.reset();
+}
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/name.h b/gd/shim/name.h
new file mode 100644
index 0000000..7d8233f
--- /dev/null
+++ b/gd/shim/name.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <memory>
+
+#include "module.h"
+#include "shim/iname.h"
+
+namespace bluetooth {
+namespace shim {
+
+class Name : public bluetooth::Module, public bluetooth::shim::IName {
+ public:
+ void ReadRemoteNameRequest(std::string remote_address, ReadRemoteNameCallback callback) override;
+ void CancelRemoteNameRequest(std::string remote_address, CancelRemoteNameCallback callback) override;
+
+ Name() = default;
+ ~Name() = default;
+
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override; // Module
+ void Start() override; // Module
+ void Stop() override; // Module
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+ DISALLOW_COPY_AND_ASSIGN(Name);
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/only_include_this_file_into_legacy_stack___ever.h b/gd/shim/only_include_this_file_into_legacy_stack___ever.h
new file mode 100644
index 0000000..335778a
--- /dev/null
+++ b/gd/shim/only_include_this_file_into_legacy_stack___ever.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+/**
+ * This common file provides the only visibility from the legacy stack into GD stack.
+ *
+ * Only interfaces or APIs should be exported.
+ *
+ * Only common data structures should be used to pass data between the stacks.
+ *
+ */
+#include "gd/shim/iadvertising.h"
+#include "gd/shim/iconnectability.h"
+#include "gd/shim/icontroller.h"
+#include "gd/shim/idiscoverability.h"
+#include "gd/shim/ihci_layer.h"
+#include "gd/shim/iinquiry.h"
+#include "gd/shim/il2cap.h"
+#include "gd/shim/iname.h"
+#include "gd/shim/ipage.h"
+#include "gd/shim/iscanning.h"
+#include "gd/shim/istack.h"
diff --git a/gd/shim/page.cc b/gd/shim/page.cc
new file mode 100644
index 0000000..aa79d29
--- /dev/null
+++ b/gd/shim/page.cc
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2019 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.
+ */
+#define LOG_TAG "bt_gd_shim"
+
+#include <functional>
+#include <memory>
+
+#include "common/bidi_queue.h"
+#include "hci/address.h"
+#include "hci/controller.h"
+#include "hci/hci_packets.h"
+#include "module.h"
+#include "neighbor/page.h"
+#include "neighbor/scan_parameters.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "shim/page.h"
+
+namespace bluetooth {
+namespace shim {
+
+const ModuleFactory Page::Factory = ModuleFactory([]() { return new Page(); });
+
+struct Page::impl {
+ impl(neighbor::PageModule* module);
+ ~impl();
+
+ neighbor::PageModule* module_{nullptr};
+};
+
+Page::impl::impl(neighbor::PageModule* module) : module_(module) {}
+
+Page::impl::~impl() {}
+
+void Page::SetScanActivity(uint16_t interval, uint16_t window) {
+ neighbor::ScanParameters params{.interval = static_cast<neighbor::ScanInterval>(interval),
+ .window = static_cast<neighbor::ScanWindow>(window)};
+ return pimpl_->module_->SetScanActivity(params);
+}
+
+void Page::GetScanActivity(uint16_t& interval, uint16_t& window) const {
+ neighbor::ScanParameters params = pimpl_->module_->GetScanActivity();
+
+ interval = static_cast<uint16_t>(params.interval);
+ window = static_cast<uint16_t>(params.window);
+}
+
+void Page::SetInterlacedScan() {
+ return pimpl_->module_->SetInterlacedScan();
+}
+void Page::SetStandardScan() {
+ return pimpl_->module_->SetStandardScan();
+}
+
+/**
+ * Module methods
+ */
+void Page::ListDependencies(ModuleList* list) {
+ list->add<neighbor::PageModule>();
+}
+
+void Page::Start() {
+ pimpl_ = std::make_unique<impl>(GetDependency<neighbor::PageModule>());
+}
+
+void Page::Stop() {
+ pimpl_.reset();
+}
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/page.h b/gd/shim/page.h
new file mode 100644
index 0000000..b4e71cd
--- /dev/null
+++ b/gd/shim/page.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <memory>
+
+#include "module.h"
+#include "shim/ipage.h"
+
+namespace bluetooth {
+namespace shim {
+
+class Page : public bluetooth::Module, public bluetooth::shim::IPage {
+ public:
+ void SetScanActivity(uint16_t interval, uint16_t window) override;
+ void GetScanActivity(uint16_t& interval, uint16_t& window) const override;
+
+ void SetInterlacedScan() override;
+ void SetStandardScan() override;
+
+ Page() = default;
+ ~Page() = default;
+
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override; // Module
+ void Start() override; // Module
+ void Stop() override; // Module
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+ DISALLOW_COPY_AND_ASSIGN(Page);
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/scanning.cc b/gd/shim/scanning.cc
new file mode 100644
index 0000000..5216937
--- /dev/null
+++ b/gd/shim/scanning.cc
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2019 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.
+ */
+#define LOG_TAG "bt_gd_shim"
+
+#include <functional>
+#include <memory>
+
+#include "hci/address.h"
+#include "hci/hci_packets.h"
+#include "hci/le_scanning_manager.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "shim/scanning.h"
+
+namespace bluetooth {
+namespace shim {
+
+struct Scanning::impl {
+ hci::LeScanningManager* module_{nullptr};
+
+ impl(hci::LeScanningManager* module);
+ ~impl();
+};
+
+const ModuleFactory Scanning::Factory = ModuleFactory([]() { return new Scanning(); });
+
+Scanning::impl::impl(hci::LeScanningManager* scanning_manager) : module_(scanning_manager) {}
+
+Scanning::impl::~impl() {}
+
+/**
+ * Module methods
+ */
+void Scanning::ListDependencies(ModuleList* list) {
+ list->add<hci::LeScanningManager>();
+}
+
+void Scanning::Start() {
+ pimpl_ = std::make_unique<impl>(GetDependency<hci::LeScanningManager>());
+}
+
+void Scanning::Stop() {
+ pimpl_.reset();
+}
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/scanning.h b/gd/shim/scanning.h
new file mode 100644
index 0000000..8768ead
--- /dev/null
+++ b/gd/shim/scanning.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019 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.
+ */
+#pragma once
+
+#include <memory>
+#include <string>
+
+#include "module.h"
+#include "shim/iscanning.h"
+
+namespace bluetooth {
+namespace shim {
+
+class Scanning : public bluetooth::Module, public bluetooth::shim::IScanning {
+ public:
+ Scanning() = default;
+ ~Scanning() = default;
+
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override; // Module
+ void Start() override; // Module
+ void Stop() override; // Module
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+ DISALLOW_COPY_AND_ASSIGN(Scanning);
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/shim/stack.cc b/gd/shim/stack.cc
new file mode 100644
index 0000000..7822a35
--- /dev/null
+++ b/gd/shim/stack.cc
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#define LOG_TAG "bt_gd_shim"
+
+#include "shim/stack.h"
+#include "hal/hci_hal.h"
+#include "hci/acl_manager.h"
+#include "hci/classic_security_manager.h"
+#include "hci/le_advertising_manager.h"
+#include "hci/le_scanning_manager.h"
+#include "l2cap/classic/l2cap_classic_module.h"
+#include "l2cap/le/l2cap_le_module.h"
+#include "neighbor/connectability.h"
+#include "neighbor/discoverability.h"
+#include "neighbor/inquiry.h"
+#include "neighbor/name.h"
+#include "neighbor/page.h"
+#include "neighbor/scan.h"
+#include "os/log.h"
+#include "os/thread.h"
+#include "security/security_module.h"
+#include "shim/advertising.h"
+#include "shim/connectability.h"
+#include "shim/controller.h"
+#include "shim/discoverability.h"
+#include "shim/hci_layer.h"
+#include "shim/inquiry.h"
+#include "shim/l2cap.h"
+#include "shim/name.h"
+#include "shim/page.h"
+#include "shim/scanning.h"
+#include "stack_manager.h"
+
+using ::bluetooth::os::Thread;
+
+struct bluetooth::shim::Stack::impl {
+ void Start() {
+ if (is_running_) {
+ LOG_ERROR("%s Gd stack already running", __func__);
+ return;
+ }
+
+ LOG_INFO("%s Starting Gd stack", __func__);
+ ModuleList modules;
+ modules.add<::bluetooth::hal::HciHal>();
+ modules.add<::bluetooth::hci::AclManager>();
+ modules.add<::bluetooth::hci::LeAdvertisingManager>();
+ modules.add<::bluetooth::hci::LeScanningManager>();
+ modules.add<::bluetooth::l2cap::classic::L2capClassicModule>();
+ modules.add<::bluetooth::l2cap::le::L2capLeModule>();
+ modules.add<::bluetooth::neighbor::ConnectabilityModule>();
+ modules.add<::bluetooth::neighbor::DiscoverabilityModule>();
+ modules.add<::bluetooth::neighbor::InquiryModule>();
+ modules.add<::bluetooth::neighbor::NameModule>();
+ modules.add<::bluetooth::neighbor::PageModule>();
+ modules.add<::bluetooth::neighbor::ScanModule>();
+ modules.add<::bluetooth::shim::Controller>();
+ modules.add<::bluetooth::shim::HciLayer>();
+ modules.add<::bluetooth::security::SecurityModule>();
+ modules.add<::bluetooth::shim::Advertising>();
+ modules.add<::bluetooth::shim::Connectability>();
+ modules.add<::bluetooth::shim::Discoverability>();
+ modules.add<::bluetooth::shim::Inquiry>();
+ modules.add<::bluetooth::shim::Name>();
+ modules.add<::bluetooth::shim::L2cap>();
+ modules.add<::bluetooth::shim::Page>();
+ modules.add<::bluetooth::shim::Scanning>();
+
+ stack_thread_ = new Thread("gd_stack_thread", Thread::Priority::NORMAL);
+ stack_manager_.StartUp(&modules, stack_thread_);
+ // TODO(cmanton) Gd stack has spun up another thread with no
+ // ability to ascertain the completion
+ is_running_ = true;
+ LOG_INFO("%s Successfully toggled Gd stack", __func__);
+ }
+
+ void Stop() {
+ if (!is_running_) {
+ LOG_ERROR("%s Gd stack not running", __func__);
+ return;
+ }
+
+ stack_manager_.ShutDown();
+ delete stack_thread_;
+ is_running_ = false;
+ LOG_INFO("%s Successfully shut down Gd stack", __func__);
+ }
+
+ IAdvertising* GetAdvertising() {
+ return stack_manager_.GetInstance<bluetooth::shim::Advertising>();
+ }
+
+ IController* GetController() {
+ return stack_manager_.GetInstance<bluetooth::shim::Controller>();
+ }
+
+ IConnectability* GetConnectability() {
+ return stack_manager_.GetInstance<bluetooth::shim::Connectability>();
+ }
+
+ IDiscoverability* GetDiscoverability() {
+ return stack_manager_.GetInstance<bluetooth::shim::Discoverability>();
+ }
+
+ IHciLayer* GetHciLayer() {
+ return stack_manager_.GetInstance<bluetooth::shim::HciLayer>();
+ }
+
+ IInquiry* GetInquiry() {
+ return stack_manager_.GetInstance<bluetooth::shim::Inquiry>();
+ }
+
+ IL2cap* GetL2cap() {
+ return stack_manager_.GetInstance<bluetooth::shim::L2cap>();
+ }
+
+ IName* GetName() {
+ return stack_manager_.GetInstance<bluetooth::shim::Name>();
+ }
+
+ IPage* GetPage() {
+ return stack_manager_.GetInstance<bluetooth::shim::Page>();
+ }
+
+ IScanning* GetScanning() {
+ return stack_manager_.GetInstance<bluetooth::shim::Scanning>();
+ }
+
+ private:
+ os::Thread* stack_thread_ = nullptr;
+ bool is_running_ = false;
+ StackManager stack_manager_;
+};
+
+bluetooth::shim::Stack::Stack() {
+ pimpl_ = std::make_unique<impl>();
+ LOG_INFO("%s Created gd stack", __func__);
+}
+
+void bluetooth::shim::Stack::Start() {
+ pimpl_->Start();
+}
+
+void bluetooth::shim::Stack::Stop() {
+ pimpl_->Stop();
+}
+
+bluetooth::shim::IAdvertising* bluetooth::shim::Stack::GetAdvertising() {
+ return pimpl_->GetAdvertising();
+}
+
+bluetooth::shim::IConnectability* bluetooth::shim::Stack::GetConnectability() {
+ return pimpl_->GetConnectability();
+}
+
+bluetooth::shim::IController* bluetooth::shim::Stack::GetController() {
+ return pimpl_->GetController();
+}
+
+bluetooth::shim::IDiscoverability* bluetooth::shim::Stack::GetDiscoverability() {
+ return pimpl_->GetDiscoverability();
+}
+
+bluetooth::shim::IHciLayer* bluetooth::shim::Stack::GetHciLayer() {
+ return pimpl_->GetHciLayer();
+}
+
+bluetooth::shim::IInquiry* bluetooth::shim::Stack::GetInquiry() {
+ return pimpl_->GetInquiry();
+}
+
+bluetooth::shim::IL2cap* bluetooth::shim::Stack::GetL2cap() {
+ return pimpl_->GetL2cap();
+}
+
+bluetooth::shim::IName* bluetooth::shim::Stack::GetName() {
+ return pimpl_->GetName();
+}
+
+bluetooth::shim::IPage* bluetooth::shim::Stack::GetPage() {
+ return pimpl_->GetPage();
+}
+
+bluetooth::shim::IScanning* bluetooth::shim::Stack::GetScanning() {
+ return pimpl_->GetScanning();
+}
+
+bluetooth::shim::IStack* bluetooth::shim::GetGabeldorscheStack() {
+ static IStack* instance = new Stack();
+ return instance;
+}
diff --git a/gd/shim/stack.h b/gd/shim/stack.h
new file mode 100644
index 0000000..f4a51fc
--- /dev/null
+++ b/gd/shim/stack.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <memory>
+
+#include "shim/iadvertising.h"
+#include "shim/iconnectability.h"
+#include "shim/icontroller.h"
+#include "shim/idiscoverability.h"
+#include "shim/ihci_layer.h"
+#include "shim/iinquiry.h"
+#include "shim/il2cap.h"
+#include "shim/iname.h"
+#include "shim/ipage.h"
+#include "shim/iscanning.h"
+#include "shim/istack.h"
+
+/**
+ * The shim layer implementation on the Gd stack side.
+ */
+namespace bluetooth {
+namespace shim {
+
+class Stack : public IStack {
+ public:
+ Stack();
+ ~Stack() = default;
+
+ void Start() override; // IStack
+ void Stop() override; // IStack
+
+ IAdvertising* GetAdvertising() override; // IStack
+ IController* GetController() override; // IStack
+ IConnectability* GetConnectability() override; // IStack
+ IHciLayer* GetHciLayer() override; // IStack
+ IDiscoverability* GetDiscoverability() override; // IStack
+ IInquiry* GetInquiry() override; // IStack
+ IName* GetName() override; // IStack
+ IL2cap* GetL2cap() override; // IStack
+ IPage* GetPage() override; // IStack
+ IScanning* GetScanning() override; // IStack
+
+ private:
+ struct impl;
+ std::unique_ptr<impl> pimpl_;
+
+ Stack(const Stack&) = delete;
+ void operator=(const Stack&) = delete;
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/gd/stack_manager.cc b/gd/stack_manager.cc
new file mode 100644
index 0000000..9c01d56
--- /dev/null
+++ b/gd/stack_manager.cc
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2019 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 "stack_manager.h"
+
+#include <chrono>
+#include <future>
+#include <queue>
+
+#include "common/bind.h"
+#include "hal/hci_hal.h"
+#include "module.h"
+#include "os/handler.h"
+#include "os/log.h"
+#include "os/thread.h"
+
+using ::bluetooth::os::Handler;
+using ::bluetooth::os::Thread;
+
+namespace bluetooth {
+
+void StackManager::StartUp(ModuleList* modules, Thread* stack_thread) {
+ management_thread_ = new Thread("management_thread", Thread::Priority::NORMAL);
+ handler_ = new Handler(management_thread_);
+
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ handler_->Post(common::BindOnce(&StackManager::handle_start_up, common::Unretained(this), modules, stack_thread,
+ std::move(promise)));
+
+ auto init_status = future.wait_for(std::chrono::seconds(3));
+ ASSERT_LOG(init_status == std::future_status::ready, "Can't start stack");
+
+ LOG_INFO("init complete");
+}
+
+void StackManager::handle_start_up(ModuleList* modules, Thread* stack_thread, std::promise<void> promise) {
+ registry_.Start(modules, stack_thread);
+ promise.set_value();
+}
+
+void StackManager::ShutDown() {
+ std::promise<void> promise;
+ auto future = promise.get_future();
+ handler_->Post(common::BindOnce(&StackManager::handle_shut_down, common::Unretained(this), std::move(promise)));
+
+ auto stop_status = future.wait_for(std::chrono::seconds(3));
+ ASSERT_LOG(stop_status == std::future_status::ready, "Can't stop stack");
+
+ handler_->Clear();
+ handler_->WaitUntilStopped(std::chrono::milliseconds(20));
+ delete handler_;
+ delete management_thread_;
+}
+
+void StackManager::handle_shut_down(std::promise<void> promise) {
+ registry_.StopAll();
+ promise.set_value();
+}
+
+} // namespace bluetooth
diff --git a/gd/stack_manager.h b/gd/stack_manager.h
new file mode 100644
index 0000000..9a86480
--- /dev/null
+++ b/gd/stack_manager.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "module.h"
+#include "os/thread.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+
+class StackManager {
+ public:
+ void StartUp(ModuleList *modules, os::Thread* stack_thread);
+ void ShutDown();
+
+ template <class T>
+ T* GetInstance() const {
+ return static_cast<T*>(registry_.Get(&T::Factory));
+ }
+
+ private:
+ os::Thread* management_thread_ = nullptr;
+ os::Handler* handler_ = nullptr;
+ ModuleRegistry registry_;
+
+ void handle_start_up(ModuleList* modules, os::Thread* stack_thread, std::promise<void> promise);
+ void handle_shut_down(std::promise<void> promise);
+};
+
+} // namespace bluetooth
diff --git a/gd/stack_manager_unittest.cc b/gd/stack_manager_unittest.cc
new file mode 100644
index 0000000..e79a94f
--- /dev/null
+++ b/gd/stack_manager_unittest.cc
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2019 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 "stack_manager.h"
+
+#include "gtest/gtest.h"
+#include "os/thread.h"
+
+namespace bluetooth {
+namespace {
+
+TEST(StackManagerTest, start_and_shutdown_no_module) {
+ StackManager stack_manager;
+ ModuleList module_list;
+ os::Thread thread{"test_thread", os::Thread::Priority::NORMAL};
+ stack_manager.StartUp(&module_list, &thread);
+ stack_manager.ShutDown();
+}
+
+class TestModuleNoDependency : public Module {
+ public:
+ static const ModuleFactory Factory;
+
+ protected:
+ void ListDependencies(ModuleList* list) override {}
+ void Start() override {}
+ void Stop() override {}
+};
+
+const ModuleFactory TestModuleNoDependency::Factory = ModuleFactory([]() { return new TestModuleNoDependency(); });
+
+TEST(StackManagerTest, get_module_instance) {
+ StackManager stack_manager;
+ ModuleList module_list;
+ module_list.add<TestModuleNoDependency>();
+ os::Thread thread{"test_thread", os::Thread::Priority::NORMAL};
+ stack_manager.StartUp(&module_list, &thread);
+ EXPECT_NE(stack_manager.GetInstance<TestModuleNoDependency>(), nullptr);
+ stack_manager.ShutDown();
+}
+
+} // namespace
+} // namespace bluetooth
diff --git a/hci/Android.bp b/hci/Android.bp
index 635d939..ddfef504 100644
--- a/hci/Android.bp
+++ b/hci/Android.bp
@@ -3,9 +3,8 @@
defaults: ["fluoride_defaults"],
shared_libs: [
"android.hardware.bluetooth@1.0",
+ "android.hardware.bluetooth@1.1",
"libhidlbase",
- "libhidltransport",
- "libhwbinder",
],
}
diff --git a/hci/include/bt_hci_bdroid.h b/hci/include/bt_hci_bdroid.h
index cf2c113..110354f 100644
--- a/hci/include/bt_hci_bdroid.h
+++ b/hci/include/bt_hci_bdroid.h
@@ -53,15 +53,17 @@
#define MSG_SUB_EVT_MASK 0x00FF /* eq. BT_SUB_EVT_MASK */
/* Message event ID passed from Host/Controller lib to stack */
-#define MSG_HC_TO_STACK_HCI_ERR 0x1300 /* eq. BT_EVT_TO_BTU_HCIT_ERR */
#define MSG_HC_TO_STACK_HCI_ACL 0x1100 /* eq. BT_EVT_TO_BTU_HCI_ACL */
#define MSG_HC_TO_STACK_HCI_SCO 0x1200 /* eq. BT_EVT_TO_BTU_HCI_SCO */
+#define MSG_HC_TO_STACK_HCI_ERR 0x1300 /* eq. BT_EVT_TO_BTU_HCIT_ERR */
+#define MSG_HC_TO_STACK_HCI_ISO 0x1700 /* eq. BT_EVT_TO_BTU_HCI_ISO */
#define MSG_HC_TO_STACK_HCI_EVT 0x1000 /* eq. BT_EVT_TO_BTU_HCI_EVT */
#define MSG_HC_TO_STACK_L2C_SEG_XMIT 0x1900 /* BT_EVT_TO_BTU_L2C_SEG_XMIT */
/* Message event ID passed from stack to vendor lib */
#define MSG_STACK_TO_HC_HCI_ACL 0x2100 /* eq. BT_EVT_TO_LM_HCI_ACL */
#define MSG_STACK_TO_HC_HCI_SCO 0x2200 /* eq. BT_EVT_TO_LM_HCI_SCO */
+#define MSG_STACK_TO_HC_HCI_ISO 0x2d00 /* eq. BT_EVT_TO_LM_HCI_ISO */
#define MSG_STACK_TO_HC_HCI_CMD 0x2000 /* eq. BT_EVT_TO_LM_HCI_CMD */
/* Local Bluetooth Controller ID for BR/EDR */
diff --git a/hci/include/hci_hal.h b/hci/include/hci_hal.h
index f73e116..6fbb13e 100644
--- a/hci/include/hci_hal.h
+++ b/hci/include/hci_hal.h
@@ -29,7 +29,8 @@
DATA_TYPE_COMMAND = 1,
DATA_TYPE_ACL = 2,
DATA_TYPE_SCO = 3,
- DATA_TYPE_EVENT = 4
+ DATA_TYPE_EVENT = 4,
+ DATA_TYPE_ISO = 5
} serial_data_type_t;
typedef void (*data_ready_cb)(serial_data_type_t type);
diff --git a/hci/include/hci_internals.h b/hci/include/hci_internals.h
index 8fe0041..bf9430f 100644
--- a/hci/include/hci_internals.h
+++ b/hci/include/hci_internals.h
@@ -26,3 +26,5 @@
#define HCI_SCO_PREAMBLE_SIZE 3
// 1 byte for event code, 1 byte for parameter length (Volume 2, Part E, 5.4.4)
#define HCI_EVENT_PREAMBLE_SIZE 2
+// 2 bytes for handle, 2 bytes for data length (Volume 2, Part E, 5.4.5)
+#define HCI_ISO_PREAMBLE_SIZE 4
\ No newline at end of file
diff --git a/hci/include/hci_layer.h b/hci/include/hci_layer.h
index 5eb2bd5..bf4efee 100644
--- a/hci/include/hci_layer.h
+++ b/hci/include/hci_layer.h
@@ -37,15 +37,17 @@
#define MSG_SUB_EVT_MASK 0x00FF /* eq. BT_SUB_EVT_MASK */
/* Message event ID passed from Host/Controller lib to stack */
-#define MSG_HC_TO_STACK_HCI_ERR 0x1300 /* eq. BT_EVT_TO_BTU_HCIT_ERR */
#define MSG_HC_TO_STACK_HCI_ACL 0x1100 /* eq. BT_EVT_TO_BTU_HCI_ACL */
#define MSG_HC_TO_STACK_HCI_SCO 0x1200 /* eq. BT_EVT_TO_BTU_HCI_SCO */
+#define MSG_HC_TO_STACK_HCI_ERR 0x1300 /* eq. BT_EVT_TO_BTU_HCIT_ERR */
+#define MSG_HC_TO_STACK_HCI_ISO 0x1700 /* eq. BT_EVT_TO_BTU_HCI_ISO */
#define MSG_HC_TO_STACK_HCI_EVT 0x1000 /* eq. BT_EVT_TO_BTU_HCI_EVT */
#define MSG_HC_TO_STACK_L2C_SEG_XMIT 0x1900 /* BT_EVT_TO_BTU_L2C_SEG_XMIT */
/* Message event ID passed from stack to vendor lib */
#define MSG_STACK_TO_HC_HCI_ACL 0x2100 /* eq. BT_EVT_TO_LM_HCI_ACL */
#define MSG_STACK_TO_HC_HCI_SCO 0x2200 /* eq. BT_EVT_TO_LM_HCI_SCO */
+#define MSG_STACK_TO_HC_HCI_ISO 0x2d00 /* eq. BT_EVT_TO_LM_HCI_ISO */
#define MSG_STACK_TO_HC_HCI_CMD 0x2000 /* eq. BT_EVT_TO_LM_HCI_CMD */
/* Local Bluetooth Controller ID for BR/EDR */
@@ -83,6 +85,11 @@
void (*transmit_downward)(uint16_t type, void* data);
} hci_t;
+namespace bluetooth {
+namespace legacy {
+const hci_t* hci_layer_get_interface();
+} // namespace legacy
+} // namespace bluetooth
const hci_t* hci_layer_get_interface();
const hci_t* hci_layer_get_test_interface(
diff --git a/hci/src/hci_inject.cc b/hci/src/hci_inject.cc
index 01b8cfd..6d3e8e0 100644
--- a/hci/src/hci_inject.cc
+++ b/hci/src/hci_inject.cc
@@ -39,6 +39,7 @@
HCI_PACKET_ACL_DATA = 2,
HCI_PACKET_SCO_DATA = 3,
HCI_PACKET_EVENT = 4,
+ HCI_PACKET_ISO_DATA = 5,
} hci_packet_t;
typedef struct {
@@ -118,6 +119,8 @@
return MSG_STACK_TO_HC_HCI_ACL;
case HCI_PACKET_SCO_DATA:
return MSG_STACK_TO_HC_HCI_SCO;
+ case HCI_PACKET_ISO_DATA:
+ return MSG_STACK_TO_HC_HCI_ISO;
default:
LOG_ERROR(LOG_TAG, "%s unsupported packet type: %d", __func__, packet);
return -1;
diff --git a/hci/src/hci_layer.cc b/hci/src/hci_layer.cc
index ed2908c..da6054b 100644
--- a/hci/src/hci_layer.cc
+++ b/hci/src/hci_layer.cc
@@ -44,6 +44,7 @@
#include "hci_internals.h"
#include "hcidefs.h"
#include "hcimsgs.h"
+#include "main/shim/shim.h"
#include "osi/include/alarm.h"
#include "osi/include/list.h"
#include "osi/include/log.h"
@@ -160,6 +161,11 @@
packet_fragmenter->reassemble_and_dispatch(packet);
}
+void iso_data_received(BT_HDR* packet) {
+ btsnoop->capture(packet, true);
+ packet_fragmenter->reassemble_and_dispatch(packet);
+}
+
// Module lifecycle functions
static future_t* hci_module_shut_down();
@@ -510,8 +516,7 @@
uint8_t* hci_packet = reinterpret_cast<uint8_t*>(bt_hdr + 1);
- UINT16_TO_STREAM(hci_packet,
- HCI_GRP_VENDOR_SPECIFIC | HCI_CONTROLLER_DEBUG_INFO_OCF);
+ UINT16_TO_STREAM(hci_packet, HCI_CONTROLLER_DEBUG_INFO);
UINT8_TO_STREAM(hci_packet, 0); // No parameters
hci_firmware_log_fd = hci_open_firmware_log_file();
@@ -720,7 +725,21 @@
}
}
+namespace bluetooth {
+namespace shim {
+const hci_t* hci_layer_get_interface();
+} // namespace shim
+} // namespace bluetooth
+
const hci_t* hci_layer_get_interface() {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::hci_layer_get_interface();
+ } else {
+ return bluetooth::legacy::hci_layer_get_interface();
+ }
+}
+
+const hci_t* bluetooth::legacy::hci_layer_get_interface() {
buffer_allocator = buffer_allocator_get_interface();
btsnoop = btsnoop_get_interface();
packet_fragmenter = packet_fragmenter_get_interface();
diff --git a/hci/src/hci_layer_android.cc b/hci/src/hci_layer_android.cc
index 92be0df..c4aded1 100644
--- a/hci/src/hci_layer_android.cc
+++ b/hci/src/hci_layer_android.cc
@@ -32,6 +32,8 @@
#include <android/hardware/bluetooth/1.0/IBluetoothHci.h>
#include <android/hardware/bluetooth/1.0/IBluetoothHciCallbacks.h>
#include <android/hardware/bluetooth/1.0/types.h>
+#include <android/hardware/bluetooth/1.1/IBluetoothHci.h>
+#include <android/hardware/bluetooth/1.1/IBluetoothHciCallbacks.h>
#include <hwbinder/ProcessState.h>
#define LOG_PATH "/data/misc/bluetooth/logs/firmware_events.log"
@@ -43,16 +45,18 @@
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::bluetooth::V1_0::HciPacket;
-using ::android::hardware::bluetooth::V1_0::IBluetoothHci;
-using ::android::hardware::bluetooth::V1_0::IBluetoothHciCallbacks;
using ::android::hardware::bluetooth::V1_0::Status;
+using namespace ::android::hardware::bluetooth;
+
extern void initialization_complete();
extern void hci_event_received(const base::Location& from_here, BT_HDR* packet);
extern void acl_event_received(BT_HDR* packet);
extern void sco_data_received(BT_HDR* packet);
+extern void iso_data_received(BT_HDR* packet);
-android::sp<IBluetoothHci> btHci;
+android::sp<V1_0::IBluetoothHci> btHci;
+android::sp<V1_1::IBluetoothHci> btHci_1_1;
class BluetoothHciDeathRecipient : public hidl_death_recipient {
public:
@@ -63,7 +67,7 @@
};
android::sp<BluetoothHciDeathRecipient> bluetoothHciDeathRecipient = new BluetoothHciDeathRecipient();
-class BluetoothHciCallbacks : public IBluetoothHciCallbacks {
+class BluetoothHciCallbacks : public V1_1::IBluetoothHciCallbacks {
public:
BluetoothHciCallbacks() {
buffer_allocator = buffer_allocator_get_interface();
@@ -83,37 +87,50 @@
return packet;
}
- Return<void> initializationComplete(Status status) {
+ Return<void> initializationComplete(Status status) override {
CHECK(status == Status::SUCCESS);
initialization_complete();
return Void();
}
- Return<void> hciEventReceived(const hidl_vec<uint8_t>& event) {
+ Return<void> hciEventReceived(const hidl_vec<uint8_t>& event) override {
BT_HDR* packet = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_EVT, event);
hci_event_received(FROM_HERE, packet);
return Void();
}
- Return<void> aclDataReceived(const hidl_vec<uint8_t>& data) {
+ Return<void> aclDataReceived(const hidl_vec<uint8_t>& data) override {
BT_HDR* packet = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_ACL, data);
acl_event_received(packet);
return Void();
}
- Return<void> scoDataReceived(const hidl_vec<uint8_t>& data) {
+ Return<void> scoDataReceived(const hidl_vec<uint8_t>& data) override {
BT_HDR* packet = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_SCO, data);
sco_data_received(packet);
return Void();
}
+ Return<void> isoDataReceived(const hidl_vec<uint8_t>& data) override {
+ BT_HDR* packet = WrapPacketAndCopy(MSG_HC_TO_STACK_HCI_ISO, data);
+ iso_data_received(packet);
+ return Void();
+ }
+
const allocator_t* buffer_allocator;
};
void hci_initialize() {
LOG_INFO(LOG_TAG, "%s", __func__);
- btHci = IBluetoothHci::getService();
+ btHci_1_1 = V1_1::IBluetoothHci::getService();
+
+ if (btHci_1_1 != nullptr) {
+ btHci = btHci_1_1;
+ } else {
+ btHci = V1_0::IBluetoothHci::getService();
+ }
+
// If android.hardware.bluetooth* is not found, Bluetooth can not continue.
CHECK(btHci != nullptr);
auto death_link = btHci->linkToDeath(bluetoothHciDeathRecipient, 0);
@@ -126,8 +143,13 @@
// Block allows allocation of a variable that might be bypassed by goto.
{
- android::sp<IBluetoothHciCallbacks> callbacks = new BluetoothHciCallbacks();
- btHci->initialize(callbacks);
+ android::sp<V1_1::IBluetoothHciCallbacks> callbacks =
+ new BluetoothHciCallbacks();
+ if (btHci_1_1 != nullptr) {
+ btHci_1_1->initialize(callbacks);
+ } else {
+ btHci->initialize(callbacks);
+ }
}
}
@@ -157,6 +179,13 @@
case MSG_STACK_TO_HC_HCI_SCO:
btHci->sendScoData(data);
break;
+ case MSG_STACK_TO_HC_HCI_ISO:
+ if (btHci_1_1 != nullptr) {
+ btHci_1_1->sendIsoData(data);
+ } else {
+ LOG_ERROR(LOG_TAG, "ISO is not supported in HAL v1.0");
+ }
+ break;
default:
LOG_ERROR(LOG_TAG, "Unknown packet type (%d)", event);
break;
diff --git a/hci/src/packet_fragmenter.cc b/hci/src/packet_fragmenter.cc
index 5036ed5..f688982 100644
--- a/hci/src/packet_fragmenter.cc
+++ b/hci/src/packet_fragmenter.cc
@@ -221,7 +221,7 @@
"%s got packet which would exceed expected length of %d. "
"Truncating.",
__func__, partial_packet->len);
- packet->len = partial_packet->len - partial_packet->offset;
+ packet->len = (partial_packet->len - partial_packet->offset) + packet->offset;
projected_offset = partial_packet->len;
}
diff --git a/hci/test/packet_fragmenter_test.cc b/hci/test/packet_fragmenter_test.cc
index 483a66d..ca83dfa 100644
--- a/hci/test/packet_fragmenter_test.cc
+++ b/hci/test/packet_fragmenter_test.cc
@@ -291,7 +291,7 @@
class PacketFragmenterTest : public AllocationTestHarness {
protected:
- virtual void SetUp() {
+ void SetUp() override {
AllocationTestHarness::SetUp();
fragmenter =
packet_fragmenter_get_test_interface(&controller, &allocator_malloc);
@@ -309,7 +309,7 @@
fragmenter->init(&callbacks);
}
- virtual void TearDown() {
+ void TearDown() override {
fragmenter->cleanup();
AllocationTestHarness::TearDown();
}
diff --git a/include/Android.bp b/include/Android.bp
index 01a01b5..1f35206 100644
--- a/include/Android.bp
+++ b/include/Android.bp
@@ -1,7 +1,6 @@
cc_library_headers {
name: "avrcp_headers",
defaults: ["libchrome_support_defaults"],
- include_dirs: ["system/bt/internal_include"],
export_include_dirs: ["./hardware/avrcp/"],
header_libs: ["internal_include_headers"],
export_header_lib_headers: ["internal_include_headers"],
diff --git a/include/hardware/bt_hf_client.h b/include/hardware/bt_hf_client.h
index a31de0f..d8f3a50 100644
--- a/include/hardware/bt_hf_client.h
+++ b/include/hardware/bt_hf_client.h
@@ -292,6 +292,12 @@
*/
typedef void (*bthf_client_ring_indication_callback)(const RawAddress* bd_addr);
+/**
+ * Callback for sending unknown (vendor specific) event
+ */
+typedef void (*bthf_client_unknown_event_callback)(const RawAddress* bd_addr,
+ const char* unknow_event);
+
/** BT-HF callback structure. */
typedef struct {
/** set to sizeof(BtHfClientCallbacks) */
@@ -317,6 +323,7 @@
bthf_client_in_band_ring_tone_callback in_band_ring_tone_cb;
bthf_client_last_voice_tag_number_callback last_voice_tag_number_callback;
bthf_client_ring_indication_callback ring_indication_cb;
+ bthf_client_unknown_event_callback unknown_event_cb;
} bthf_client_callbacks_t;
/** Represents the standard BT-HF interface. */
diff --git a/internal_include/Android.bp b/internal_include/Android.bp
index 3ef202b..e550660 100644
--- a/internal_include/Android.bp
+++ b/internal_include/Android.bp
@@ -3,4 +3,4 @@
export_include_dirs: ["./"],
vendor_available: true,
host_supported: true,
-}
\ No newline at end of file
+}
diff --git a/internal_include/bt_target.h b/internal_include/bt_target.h
index 67a67c5..1356d2e 100644
--- a/internal_include/bt_target.h
+++ b/internal_include/bt_target.h
@@ -108,7 +108,7 @@
#endif
#ifndef BTA_DM_SDP_DB_SIZE
-#define BTA_DM_SDP_DB_SIZE 8000
+#define BTA_DM_SDP_DB_SIZE 20000
#endif
#ifndef HL_INCLUDED
@@ -534,7 +534,7 @@
/* Whether link wants to be the master or the slave. */
#ifndef L2CAP_DESIRED_LINK_ROLE
-#define L2CAP_DESIRED_LINK_ROLE HCI_ROLE_SLAVE
+#define L2CAP_DESIRED_LINK_ROLE HCI_ROLE_MASTER
#endif
/* Include Non-Flushable Packet Boundary Flag feature of Lisbon */
diff --git a/main/Android.bp b/main/Android.bp
index f787e9e..2a5b8cf 100644
--- a/main/Android.bp
+++ b/main/Android.bp
@@ -1,19 +1,32 @@
-
// Bluetooth main HW module / shared library for target
// ========================================================
+filegroup {
+ name: "LibBluetoothSources",
+ srcs: [
+ "bte_conf.cc",
+ "bte_init.cc",
+ "bte_init_cpp_logging.cc",
+ "bte_logmsg.cc",
+ "bte_main.cc",
+ "shim/btm.cc",
+ "shim/btm_api.cc",
+ "shim/controller.cc",
+ "shim/entry.cc",
+ "shim/hci_layer.cc",
+ "shim/l2c_api.cc",
+ "shim/l2cap.cc",
+ "shim/shim.cc",
+ "stack_config.cc",
+ ]
+}
+
cc_library_shared {
name: "libbluetooth",
defaults: ["fluoride_defaults"],
header_libs: ["libbluetooth_headers"],
export_header_lib_headers: ["libbluetooth_headers"],
srcs: [
- // platform specific
- "bte_conf.cc",
- "bte_init.cc",
- "bte_init_cpp_logging.cc",
- "bte_logmsg.cc",
- "bte_main.cc",
- "stack_config.cc",
+ ":LibBluetoothSources",
],
include_dirs: [
"system/bt",
@@ -41,6 +54,7 @@
logtags: ["../EventLogTags.logtags"],
shared_libs: [
"android.hardware.bluetooth@1.0",
+ "android.hardware.bluetooth@1.1",
"android.hardware.bluetooth.a2dp@1.0",
"android.hardware.bluetooth.audio@2.0",
"libaudioclient",
@@ -48,8 +62,6 @@
"libdl",
"libfmq",
"libhidlbase",
- "libhidltransport",
- "libhwbinder",
"liblog",
"libprocessgroup",
"libprotobuf-cpp-lite",
@@ -57,12 +69,9 @@
"libtinyxml2",
"libz",
"libcrypto",
- "android.hardware.keymaster@4.0",
- "android.hardware.keymaster@3.0",
- "libkeymaster4support",
- "libkeystore_aidl",
- "libkeystore_binder",
- "libkeystore_parcelables",
+ //"android.hardware.keymaster@4.0",
+ //"libkeymaster4support",
+ //"libkeystore_binder",
],
static_libs: [
"libbt-sbc-decoder",
@@ -70,6 +79,7 @@
"libFraunhoferAAC",
"libg722codec",
"libudrv-uipc",
+ "libbluetooth_gd", // Gabeldorsche
],
whole_static_libs: [
"libbt-bta",
@@ -108,13 +118,10 @@
defaults: ["fluoride_defaults"],
srcs: [
- "bte_conf.cc",
- "bte_init.cc",
- "bte_init_cpp_logging.cc",
- "bte_logmsg.cc",
- "bte_main.cc",
- "stack_config.cc",
+ ":LibBluetoothSources",
+ "shim/entry_for_test.cc",
],
+ host_supported: true,
include_dirs: [
"system/bt",
"system/bt/bta/include",
@@ -129,3 +136,33 @@
"-DBUILDCFG",
],
}
+
+filegroup {
+ name: "BluetoothLegacyShimTestSources",
+ srcs: [
+ "shim/l2cap_test.cc",
+ "shim/test_stack.cc",
+ ]
+}
+
+cc_test {
+ name: "bluetooth_test_legacy",
+ defaults: ["fluoride_defaults",
+ "fluoride_osi_defaults",
+ ],
+ test_suites: ["device-tests"],
+ host_supported: true,
+ srcs: [
+ ":BluetoothLegacyShimTestSources",
+ ],
+ static_libs: [
+ "libgmock",
+ "libbluetooth-for-tests",
+ "libosi",
+ ],
+ shared_libs: [
+ "libchrome",
+ "liblog",
+ ],
+}
+
diff --git a/main/bte_main.cc b/main/bte_main.cc
index 0498439..1628976 100644
--- a/main/bte_main.cc
+++ b/main/bte_main.cc
@@ -53,6 +53,8 @@
#include "osi/include/future.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
+#include "shim/hci_layer.h"
+#include "shim/shim.h"
#include "stack_config.h"
/*******************************************************************************
@@ -155,8 +157,14 @@
void bte_main_enable() {
APPL_TRACE_DEBUG("%s", __func__);
- module_start_up(get_module(BTSNOOP_MODULE));
- module_start_up(get_module(HCI_MODULE));
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ LOG_INFO(LOG_TAG, "%s Gd shim module enabled", __func__);
+ module_start_up(get_module(GD_SHIM_MODULE));
+ module_start_up(get_module(GD_HCI_MODULE));
+ } else {
+ module_start_up(get_module(BTSNOOP_MODULE));
+ module_start_up(get_module(HCI_MODULE));
+ }
BTU_StartUp();
}
@@ -174,8 +182,14 @@
void bte_main_disable(void) {
APPL_TRACE_DEBUG("%s", __func__);
- module_shut_down(get_module(HCI_MODULE));
- module_shut_down(get_module(BTSNOOP_MODULE));
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ LOG_INFO(LOG_TAG, "%s Gd shim module enabled", __func__);
+ module_shut_down(get_module(GD_HCI_MODULE));
+ module_shut_down(get_module(GD_SHIM_MODULE));
+ } else {
+ module_shut_down(get_module(HCI_MODULE));
+ module_shut_down(get_module(BTSNOOP_MODULE));
+ }
BTU_ShutDown();
}
diff --git a/main/shim/btm.cc b/main/shim/btm.cc
new file mode 100644
index 0000000..7ebbf90
--- /dev/null
+++ b/main/shim/btm.cc
@@ -0,0 +1,432 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#define LOG_TAG "bt_shim_btm"
+
+#include <algorithm>
+#include <cstring>
+
+#include "main/shim/btm.h"
+#include "main/shim/entry.h"
+#include "main/shim/shim.h"
+#include "osi/include/log.h"
+
+bluetooth::shim::Btm::Btm() {}
+
+static constexpr size_t kMaxInquiryResultSize = 4096;
+static uint8_t inquiry_result_buf[kMaxInquiryResultSize];
+
+static int inquiry_type_ = 0;
+
+static constexpr uint8_t kInquiryResultMode = 0;
+static constexpr uint8_t kInquiryResultWithRssiMode = 1;
+static constexpr uint8_t kExtendedInquiryResultMode = 2;
+
+static constexpr size_t kRemoteDeviceNameLength = 248;
+
+extern void btm_process_cancel_complete(uint8_t status, uint8_t mode);
+extern void btm_process_inq_complete(uint8_t status, uint8_t result_type);
+extern void btm_process_inq_results(uint8_t* p, uint8_t result_mode);
+
+using BtmRemoteDeviceName = tBTM_REMOTE_DEV_NAME;
+
+/**
+ *
+ */
+void bluetooth::shim::Btm::OnInquiryResult(std::vector<const uint8_t> result) {
+ CHECK(result.size() < kMaxInquiryResultSize);
+
+ std::copy(result.begin(), result.end(), inquiry_result_buf);
+ btm_process_inq_results(inquiry_result_buf, kInquiryResultMode);
+}
+
+void bluetooth::shim::Btm::OnInquiryResultWithRssi(
+ std::vector<const uint8_t> result) {
+ CHECK(result.size() < kMaxInquiryResultSize);
+
+ std::copy(result.begin(), result.end(), inquiry_result_buf);
+ btm_process_inq_results(inquiry_result_buf, kInquiryResultWithRssiMode);
+}
+
+void bluetooth::shim::Btm::OnExtendedInquiryResult(
+ std::vector<const uint8_t> result) {
+ CHECK(result.size() < kMaxInquiryResultSize);
+
+ std::copy(result.begin(), result.end(), inquiry_result_buf);
+ btm_process_inq_results(inquiry_result_buf, kExtendedInquiryResultMode);
+}
+
+void bluetooth::shim::Btm::OnInquiryComplete(uint16_t status) {
+ btm_process_inq_complete(status, inquiry_type_);
+}
+
+bool bluetooth::shim::Btm::SetInquiryFilter(uint8_t mode, uint8_t type,
+ tBTM_INQ_FILT_COND data) {
+ switch (mode) {
+ case kInquiryModeOff:
+ break;
+ case kLimitedInquiryMode:
+ LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ break;
+ case kGeneralInquiryMode:
+ LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ break;
+ default:
+ LOG_WARN(LOG_TAG, "%s Unknown inquiry mode:%d", __func__, mode);
+ return false;
+ }
+ return true;
+}
+
+void bluetooth::shim::Btm::SetFilterInquiryOnAddress() {
+ LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::Btm::SetFilterInquiryOnDevice() {
+ LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::Btm::ClearInquiryFilter() {
+ LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+bool bluetooth::shim::Btm::SetStandardInquiryResultMode() {
+ bluetooth::shim::GetInquiry()->SetStandardInquiryResultMode();
+ return true;
+}
+
+bool bluetooth::shim::Btm::SetInquiryWithRssiResultMode() {
+ bluetooth::shim::GetInquiry()->SetInquiryWithRssiResultMode();
+ return true;
+}
+
+bool bluetooth::shim::Btm::SetExtendedInquiryResultMode() {
+ bluetooth::shim::GetInquiry()->SetExtendedInquiryResultMode();
+ return true;
+}
+
+void bluetooth::shim::Btm::SetInterlacedInquiryScan() {
+ bluetooth::shim::GetInquiry()->SetInterlacedScan();
+}
+
+void bluetooth::shim::Btm::SetStandardInquiryScan() {
+ bluetooth::shim::GetInquiry()->SetStandardScan();
+}
+
+bool bluetooth::shim::Btm::IsInterlacedScanSupported() const {
+ // TODO(cmanton) This is a controller query
+ LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return true;
+}
+
+/**
+ * One shot inquiry
+ */
+bool bluetooth::shim::Btm::StartInquiry(uint8_t mode, uint8_t duration,
+ uint8_t max_responses) {
+ switch (mode) {
+ case kInquiryModeOff:
+ LOG_DEBUG(LOG_TAG, "%s Stopping inquiry mode", __func__);
+ bluetooth::shim::GetInquiry()->StopInquiry();
+ bluetooth::shim::GetInquiry()->UnregisterInquiryResult();
+ bluetooth::shim::GetInquiry()->UnregisterInquiryResultWithRssi();
+ bluetooth::shim::GetInquiry()->UnregisterExtendedInquiryResult();
+ bluetooth::shim::GetInquiry()->UnregisterInquiryComplete();
+ break;
+
+ case kLimitedInquiryMode:
+ case kGeneralInquiryMode:
+ bluetooth::shim::GetInquiry()->RegisterInquiryResult(
+ std::bind(&Btm::OnInquiryResult, this, std::placeholders::_1));
+ bluetooth::shim::GetInquiry()->RegisterInquiryResultWithRssi(std::bind(
+ &Btm::OnInquiryResultWithRssi, this, std::placeholders::_1));
+ bluetooth::shim::GetInquiry()->RegisterExtendedInquiryResult(std::bind(
+ &Btm::OnExtendedInquiryResult, this, std::placeholders::_1));
+ bluetooth::shim::GetInquiry()->RegisterInquiryComplete(
+ std::bind(&Btm::OnInquiryComplete, this, std::placeholders::_1));
+
+ if (mode == kLimitedInquiryMode) {
+ LOG_DEBUG(
+ LOG_TAG,
+ "%s Starting limited inquiry mode duration:%hhd max responses:%hhd",
+ __func__, duration, max_responses);
+ bluetooth::shim::GetInquiry()->StartLimitedInquiry(duration,
+ max_responses);
+ } else {
+ LOG_DEBUG(
+ LOG_TAG,
+ "%s Starting general inquiry mode duration:%hhd max responses:%hhd",
+ __func__, duration, max_responses);
+ bluetooth::shim::GetInquiry()->StartGeneralInquiry(duration,
+ max_responses);
+ }
+ break;
+
+ default:
+ LOG_WARN(LOG_TAG, "%s Unknown inquiry mode:%d", __func__, mode);
+ return false;
+ }
+ return true;
+}
+
+void bluetooth::shim::Btm::CancelInquiry() {
+ bluetooth::shim::GetInquiry()->StopInquiry();
+}
+
+bool bluetooth::shim::Btm::IsInquiryActive() const {
+ return IsGeneralInquiryActive() || IsLimitedInquiryActive();
+}
+
+bool bluetooth::shim::Btm::IsGeneralInquiryActive() const {
+ return bluetooth::shim::GetInquiry()->IsGeneralInquiryActive();
+}
+
+bool bluetooth::shim::Btm::IsLimitedInquiryActive() const {
+ return bluetooth::shim::GetInquiry()->IsLimitedInquiryActive();
+}
+
+/**
+ * Periodic
+ */
+bool bluetooth::shim::Btm::StartPeriodicInquiry(
+ uint8_t mode, uint8_t duration, uint8_t max_responses, uint16_t max_delay,
+ uint16_t min_delay, tBTM_INQ_RESULTS_CB* p_results_cb) {
+ switch (mode) {
+ case kInquiryModeOff:
+ bluetooth::shim::GetInquiry()->StopPeriodicInquiry();
+ break;
+
+ case kLimitedInquiryMode:
+ case kGeneralInquiryMode:
+ if (mode == kLimitedInquiryMode) {
+ LOG_DEBUG(LOG_TAG, "%s Starting limited periodic inquiry mode",
+ __func__);
+ bluetooth::shim::GetInquiry()->StartLimitedPeriodicInquiry(
+ duration, max_responses, max_delay, min_delay);
+ } else {
+ LOG_DEBUG(LOG_TAG, "%s Starting general periodic inquiry mode",
+ __func__);
+ bluetooth::shim::GetInquiry()->StartGeneralPeriodicInquiry(
+ duration, max_responses, max_delay, min_delay);
+ }
+ break;
+
+ default:
+ LOG_WARN(LOG_TAG, "%s Unknown inquiry mode:%d", __func__, mode);
+ return false;
+ }
+ return true;
+}
+
+void bluetooth::shim::Btm::CancelPeriodicInquiry() {
+ bluetooth::shim::GetInquiry()->StopPeriodicInquiry();
+}
+
+bool bluetooth::shim::Btm::IsGeneralPeriodicInquiryActive() const {
+ return bluetooth::shim::GetInquiry()->IsGeneralPeriodicInquiryActive();
+}
+
+bool bluetooth::shim::Btm::IsLimitedPeriodicInquiryActive() const {
+ return bluetooth::shim::GetInquiry()->IsLimitedPeriodicInquiryActive();
+}
+
+/**
+ * Discoverability
+ */
+void bluetooth::shim::Btm::SetClassicGeneralDiscoverability(uint16_t window,
+ uint16_t interval) {
+ bluetooth::shim::GetInquiry()->SetScanActivity(interval, window);
+ bluetooth::shim::GetDiscoverability()->StartGeneralDiscoverability();
+}
+
+void bluetooth::shim::Btm::SetClassicLimitedDiscoverability(uint16_t window,
+ uint16_t interval) {
+ bluetooth::shim::GetInquiry()->SetScanActivity(interval, window);
+ bluetooth::shim::GetDiscoverability()->StartLimitedDiscoverability();
+}
+
+void bluetooth::shim::Btm::SetClassicDiscoverabilityOff() {
+ bluetooth::shim::GetDiscoverability()->StopDiscoverability();
+}
+
+DiscoverabilityState bluetooth::shim::Btm::GetClassicDiscoverabilityState()
+ const {
+ DiscoverabilityState state{.mode = BTM_NON_DISCOVERABLE};
+ bluetooth::shim::GetInquiry()->GetScanActivity(state.interval, state.window);
+
+ if (bluetooth::shim::GetDiscoverability()
+ ->IsGeneralDiscoverabilityEnabled()) {
+ state.mode = BTM_GENERAL_DISCOVERABLE;
+ } else if (bluetooth::shim::GetDiscoverability()
+ ->IsLimitedDiscoverabilityEnabled()) {
+ state.mode = BTM_LIMITED_DISCOVERABLE;
+ }
+ return state;
+}
+
+void bluetooth::shim::Btm::SetLeGeneralDiscoverability() {
+ LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::Btm::SetLeLimitedDiscoverability() {
+ LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::Btm::SetLeDiscoverabilityOff() {
+ LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+DiscoverabilityState bluetooth::shim::Btm::GetLeDiscoverabilityState() const {
+ DiscoverabilityState state{
+ .mode = kDiscoverableModeOff,
+ .interval = 0,
+ .window = 0,
+ };
+ LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return state;
+}
+
+/**
+ * Connectability
+ */
+void bluetooth::shim::Btm::SetClassicConnectibleOn() {
+ bluetooth::shim::GetConnectability()->StartConnectability();
+}
+
+void bluetooth::shim::Btm::SetClassicConnectibleOff() {
+ bluetooth::shim::GetConnectability()->StopConnectability();
+}
+
+ConnectabilityState bluetooth::shim::Btm::GetClassicConnectabilityState()
+ const {
+ ConnectabilityState state;
+ bluetooth::shim::GetPage()->GetScanActivity(state.interval, state.window);
+
+ if (bluetooth::shim::GetConnectability()->IsConnectable()) {
+ state.mode = BTM_CONNECTABLE;
+ } else {
+ state.mode = BTM_NON_CONNECTABLE;
+ }
+ return state;
+}
+
+void bluetooth::shim::Btm::SetInterlacedPageScan() {
+ bluetooth::shim::GetPage()->SetInterlacedScan();
+}
+
+void bluetooth::shim::Btm::SetStandardPageScan() {
+ bluetooth::shim::GetPage()->SetStandardScan();
+}
+
+void bluetooth::shim::Btm::SetLeConnectibleOn() {
+ LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::Btm::SetLeConnectibleOff() {
+ LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+ConnectabilityState bluetooth::shim::Btm::GetLeConnectabilityState() const {
+ ConnectabilityState state{
+ .mode = kConnectibleModeOff,
+ .interval = 0,
+ .window = 0,
+ };
+ LOG_WARN(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return state;
+}
+
+bool bluetooth::shim::Btm::IsLeAclConnected(
+ const RawAddress& raw_address) const {
+ // TODO(cmanton) Check current acl's for this address and indicate if there is
+ // an LE option. For now ignore and default to classic.
+ LOG_INFO(LOG_TAG, "%s Le acl connection check is temporarily unsupported",
+ __func__);
+ return false;
+}
+
+bluetooth::shim::BtmStatus bluetooth::shim::Btm::ReadClassicRemoteDeviceName(
+ const RawAddress& raw_address, tBTM_CMPL_CB* callback) {
+ if (!CheckClassicAclLink(raw_address)) {
+ return bluetooth::shim::BTM_UNKNOWN_ADDR;
+ }
+
+ if (!classic_read_remote_name_.Start(raw_address)) {
+ LOG_INFO(LOG_TAG, "%s Read remote name is currently busy address:%s",
+ __func__, raw_address.ToString().c_str());
+ return bluetooth::shim::BTM_BUSY;
+ }
+
+ LOG_DEBUG(LOG_TAG, "%s Start read name from address:%s", __func__,
+ raw_address.ToString().c_str());
+ bluetooth::shim::GetName()->ReadRemoteNameRequest(
+ classic_read_remote_name_.AddressString(),
+ [this, callback](
+ std::string address_string, uint8_t hci_status,
+ std::array<uint8_t, kRemoteDeviceNameLength> remote_name) {
+ RawAddress raw_address;
+ RawAddress::FromString(address_string, raw_address);
+
+ BtmRemoteDeviceName name{
+ .status = (hci_status == 0) ? (BTM_SUCCESS) : (BTM_BAD_VALUE_RET),
+ .bd_addr = raw_address,
+ .length = kRemoteDeviceNameLength,
+ };
+ std::copy(remote_name.begin(), remote_name.end(), name.remote_bd_name);
+ LOG_DEBUG(LOG_TAG, "%s Finish read name from address:%s name:%s",
+ __func__, address_string.c_str(), name.remote_bd_name);
+ callback(&name);
+ classic_read_remote_name_.Stop();
+ });
+ return bluetooth::shim::BTM_CMD_STARTED;
+}
+
+bluetooth::shim::BtmStatus bluetooth::shim::Btm::ReadLeRemoteDeviceName(
+ const RawAddress& raw_address, tBTM_CMPL_CB* callback) {
+ if (!CheckLeAclLink(raw_address)) {
+ return bluetooth::shim::BTM_UNKNOWN_ADDR;
+ }
+
+ if (!le_read_remote_name_.Start(raw_address)) {
+ return bluetooth::shim::BTM_BUSY;
+ }
+
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s need access to GATT module", __func__);
+ return bluetooth::shim::BTM_UNKNOWN_ADDR;
+}
+
+bluetooth::shim::BtmStatus
+bluetooth::shim::Btm::CancelAllReadRemoteDeviceName() {
+ if (classic_read_remote_name_.IsInProgress() ||
+ le_read_remote_name_.IsInProgress()) {
+ if (classic_read_remote_name_.IsInProgress()) {
+ bluetooth::shim::GetName()->CancelRemoteNameRequest(
+ classic_read_remote_name_.AddressString(),
+ [this](std::string address_string, uint8_t status) {
+ classic_read_remote_name_.Stop();
+ });
+ }
+ if (le_read_remote_name_.IsInProgress()) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s need access to GATT module",
+ __func__);
+ }
+ return bluetooth::shim::BTM_UNKNOWN_ADDR;
+ }
+ LOG_INFO(LOG_TAG,
+ "%s Cancelling classic remote device name without one in progress",
+ __func__);
+ return bluetooth::shim::BTM_WRONG_MODE;
+}
diff --git a/main/shim/btm.h b/main/shim/btm.h
new file mode 100644
index 0000000..6f9c00b
--- /dev/null
+++ b/main/shim/btm.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <mutex>
+#include <unordered_map>
+#include <vector>
+
+#include "stack/include/btm_api_types.h"
+
+/* Discoverable modes */
+static constexpr int kDiscoverableModeOff = 0;
+static constexpr int kLimitedDiscoverableMode = 1;
+static constexpr int kGeneralDiscoverableMode = 2;
+
+/* Inquiry modes */
+// NOTE: The inquiry general/limited are reversed from the discoverability
+// constants
+static constexpr int kInquiryModeOff = 0;
+static constexpr int kGeneralInquiryMode = 1;
+static constexpr int kLimitedInquiryMode = 2;
+
+/* Connectable modes */
+static constexpr int kConnectibleModeOff = 0;
+static constexpr int kConnectibleModeOn = 1;
+
+/* Inquiry and page scan modes */
+static constexpr int kStandardScanType = 0;
+static constexpr int kInterlacedScanType = 1;
+
+/* Inquiry result modes */
+static constexpr int kStandardInquiryResult = 0;
+static constexpr int kInquiryResultWithRssi = 1;
+static constexpr int kExtendedInquiryResult = 2;
+
+/* Inquiry filter types */
+static constexpr int kClearInquiryFilter = 0;
+static constexpr int kFilterOnDeviceClass = 1;
+static constexpr int kFilterOnAddress = 2;
+
+using DiscoverabilityState = struct {
+ int mode;
+ uint16_t interval;
+ uint16_t window;
+};
+using ConnectabilityState = DiscoverabilityState;
+
+namespace bluetooth {
+namespace shim {
+
+using BtmStatus = enum : uint16_t {
+ BTM_SUCCESS = 0, /* 0 Command succeeded */
+ BTM_CMD_STARTED, /* 1 Command started OK. */
+ BTM_BUSY, /* 2 Device busy with another command */
+ BTM_NO_RESOURCES, /* 3 No resources to issue command */
+ BTM_MODE_UNSUPPORTED, /* 4 Request for 1 or more unsupported modes */
+ BTM_ILLEGAL_VALUE, /* 5 Illegal parameter value */
+ BTM_WRONG_MODE, /* 6 Device in wrong mode for request */
+ BTM_UNKNOWN_ADDR, /* 7 Unknown remote BD address */
+ BTM_DEVICE_TIMEOUT, /* 8 Device timeout */
+ BTM_BAD_VALUE_RET, /* 9 A bad value was received from HCI */
+ BTM_ERR_PROCESSING, /* 10 Generic error */
+ BTM_NOT_AUTHORIZED, /* 11 Authorization failed */
+ BTM_DEV_RESET, /* 12 Device has been reset */
+ BTM_CMD_STORED, /* 13 request is stored in control block */
+ BTM_ILLEGAL_ACTION, /* 14 state machine gets illegal command */
+ BTM_DELAY_CHECK, /* 15 delay the check on encryption */
+ BTM_SCO_BAD_LENGTH, /* 16 Bad SCO over HCI data length */
+ BTM_SUCCESS_NO_SECURITY, /* 17 security passed, no security set */
+ BTM_FAILED_ON_SECURITY, /* 18 security failed */
+ BTM_REPEATED_ATTEMPTS, /* 19 repeated attempts for LE security requests */
+ BTM_MODE4_LEVEL4_NOT_SUPPORTED, /* 20 Secure Connections Only Mode can't be
+ supported */
+ BTM_DEV_BLACKLISTED /* 21 The device is Blacklisted */
+};
+
+class ReadRemoteName {
+ public:
+ bool Start(RawAddress raw_address) {
+ std::unique_lock<std::mutex> lock(mutex_);
+ if (in_progress_) {
+ return false;
+ }
+ raw_address_ = raw_address;
+ in_progress_ = true;
+ return true;
+ }
+
+ void Stop() {
+ std::unique_lock<std::mutex> lock(mutex_);
+ raw_address_ = RawAddress::kEmpty;
+ in_progress_ = false;
+ }
+
+ bool IsInProgress() const { return in_progress_; }
+
+ std::string AddressString() const { return raw_address_.ToString(); }
+
+ ReadRemoteName() : in_progress_{false}, raw_address_(RawAddress::kEmpty) {}
+
+ private:
+ bool in_progress_;
+ RawAddress raw_address_;
+ std::mutex mutex_;
+};
+
+class Btm {
+ public:
+ Btm();
+
+ // Callbacks
+ void OnInquiryResult(std::vector<const uint8_t> result);
+ void OnInquiryResultWithRssi(std::vector<const uint8_t> result);
+ void OnExtendedInquiryResult(std::vector<const uint8_t> result);
+ void OnInquiryComplete(uint16_t status);
+
+ // Inquiry API
+ bool SetInquiryFilter(uint8_t mode, uint8_t type, tBTM_INQ_FILT_COND data);
+ void SetFilterInquiryOnAddress();
+ void SetFilterInquiryOnDevice();
+ void ClearInquiryFilter();
+
+ bool SetStandardInquiryResultMode();
+ bool SetInquiryWithRssiResultMode();
+ bool SetExtendedInquiryResultMode();
+
+ void SetInterlacedInquiryScan();
+ void SetStandardInquiryScan();
+ bool IsInterlacedScanSupported() const;
+
+ bool StartInquiry(uint8_t mode, uint8_t duration, uint8_t max_responses);
+ void CancelInquiry();
+ bool IsInquiryActive() const;
+ bool IsGeneralInquiryActive() const;
+ bool IsLimitedInquiryActive() const;
+
+ bool StartPeriodicInquiry(uint8_t mode, uint8_t duration,
+ uint8_t max_responses, uint16_t max_delay,
+ uint16_t min_delay,
+ tBTM_INQ_RESULTS_CB* p_results_cb);
+ void CancelPeriodicInquiry();
+ bool IsGeneralPeriodicInquiryActive() const;
+ bool IsLimitedPeriodicInquiryActive() const;
+
+ void SetClassicGeneralDiscoverability(uint16_t window, uint16_t interval);
+ void SetClassicLimitedDiscoverability(uint16_t window, uint16_t interval);
+ void SetClassicDiscoverabilityOff();
+ DiscoverabilityState GetClassicDiscoverabilityState() const;
+
+ void SetLeGeneralDiscoverability();
+ void SetLeLimitedDiscoverability();
+ void SetLeDiscoverabilityOff();
+ DiscoverabilityState GetLeDiscoverabilityState() const;
+
+ void SetClassicConnectibleOn();
+ void SetClassicConnectibleOff();
+ ConnectabilityState GetClassicConnectabilityState() const;
+ void SetInterlacedPageScan();
+ void SetStandardPageScan();
+
+ void SetLeConnectibleOn();
+ void SetLeConnectibleOff();
+ ConnectabilityState GetLeConnectabilityState() const;
+
+ bool IsLeAclConnected(const RawAddress& raw_address) const;
+
+ // Remote device name
+ BtmStatus ReadClassicRemoteDeviceName(const RawAddress& raw_address,
+ tBTM_CMPL_CB* callback);
+ BtmStatus ReadLeRemoteDeviceName(const RawAddress& raw_address,
+ tBTM_CMPL_CB* callback);
+ BtmStatus CancelAllReadRemoteDeviceName();
+
+ private:
+ ReadRemoteName le_read_remote_name_;
+ ReadRemoteName classic_read_remote_name_;
+ // TODO(cmanton) abort if there is no classic acl link up
+ bool CheckClassicAclLink(const RawAddress& raw_address) { return true; }
+ bool CheckLeAclLink(const RawAddress& raw_address) { return true; }
+};
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/main/shim/btm_api.cc b/main/shim/btm_api.cc
new file mode 100644
index 0000000..a8adee8
--- /dev/null
+++ b/main/shim/btm_api.cc
@@ -0,0 +1,1411 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#define LOG_TAG "bt_shim_btm"
+
+#include <base/callback.h>
+
+#include "main/shim/btm.h"
+#include "main/shim/btm_api.h"
+#include "osi/include/log.h"
+#include "stack/btm/btm_int_types.h"
+
+static bluetooth::shim::Btm shim_btm;
+
+/*******************************************************************************
+ *
+ * Function BTM_StartInquiry
+ *
+ * Description This function is called to start an inquiry.
+ *
+ * Parameters: p_inqparms - pointer to the inquiry information
+ * mode - GENERAL or LIMITED inquiry, BR/LE bit mask
+ * seperately
+ * duration - length in 1.28 sec intervals (If '0', the
+ * inquiry is CANCELLED)
+ * max_resps - maximum amount of devices to search for
+ * before ending the inquiry
+ * filter_cond_type - BTM_CLR_INQUIRY_FILTER,
+ * BTM_FILTER_COND_DEVICE_CLASS, or
+ * BTM_FILTER_COND_BD_ADDR
+ * filter_cond - value for the filter (based on
+ * filter_cond_type)
+ *
+ * p_results_cb - Pointer to the callback routine which gets
+ * called upon receipt of an inquiry result. If
+ * this field is NULL, the application is not
+ * notified.
+ *
+ * p_cmpl_cb - Pointer to the callback routine which gets
+ * called upon completion. If this field is
+ * NULL, the application is not notified when
+ * completed.
+ * Returns tBTM_STATUS
+ * BTM_CMD_STARTED if successfully initiated
+ * BTM_BUSY if already in progress
+ * BTM_ILLEGAL_VALUE if parameter(s) are out of range
+ * BTM_NO_RESOURCES if could not allocate resources to start
+ * the command
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_StartInquiry(tBTM_INQ_PARMS* p_inqparms,
+ tBTM_INQ_RESULTS_CB* p_results_cb,
+ tBTM_CMPL_CB* p_cmpl_cb) {
+ CHECK(p_inqparms != nullptr);
+ CHECK(p_results_cb != nullptr);
+ CHECK(p_cmpl_cb != nullptr);
+
+ uint8_t classic_mode = p_inqparms->mode & 0x0f;
+ // TODO(cmanton) Setup the LE portion too
+ uint8_t le_mode = p_inqparms->mode >> 4;
+
+ LOG_INFO(LOG_TAG, "%s Start inquiry mode classic:%hhd le:%hhd", __func__,
+ classic_mode, le_mode);
+
+ if (!shim_btm.SetInquiryFilter(classic_mode, p_inqparms->filter_cond_type,
+ p_inqparms->filter_cond)) {
+ LOG_WARN(LOG_TAG, "%s Unable to set inquiry filter", __func__);
+ return BTM_ERR_PROCESSING;
+ }
+
+ if (!shim_btm.StartInquiry(classic_mode, p_inqparms->duration,
+ p_inqparms->max_resps)) {
+ LOG_WARN(LOG_TAG, "%s Unable to start inquiry", __func__);
+ return BTM_ERR_PROCESSING;
+ }
+ return BTM_CMD_STARTED;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetPeriodicInquiryMode
+ *
+ * Description This function is called to set the device periodic inquiry
+ * mode. If the duration is zero, the periodic inquiry mode is
+ * cancelled.
+ *
+ * Note: We currently do not allow concurrent inquiry and
+ * periodic inquiry.
+ *
+ * Parameters: p_inqparms - pointer to the inquiry information
+ * mode - GENERAL or LIMITED inquiry
+ * duration - length in 1.28 sec intervals (If '0', the
+ * inquiry is CANCELLED)
+ * max_resps - maximum amount of devices to search for
+ * before ending the inquiry
+ * filter_cond_type - BTM_CLR_INQUIRY_FILTER,
+ * BTM_FILTER_COND_DEVICE_CLASS, or
+ * BTM_FILTER_COND_BD_ADDR
+ * filter_cond - value for the filter (based on
+ * filter_cond_type)
+ *
+ * max_delay - maximum amount of time between successive
+ * inquiries
+ * min_delay - minimum amount of time between successive
+ * inquiries
+ * p_results_cb - callback returning pointer to results
+ * (tBTM_INQ_RESULTS)
+ *
+ * Returns BTM_CMD_STARTED if successfully started
+ * BTM_ILLEGAL_VALUE if a bad parameter is detected
+ * BTM_NO_RESOURCES if could not allocate a message buffer
+ * BTM_SUCCESS - if cancelling the periodic inquiry
+ * BTM_BUSY - if an inquiry is already active
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_SetPeriodicInquiryMode(
+ tBTM_INQ_PARMS* p_inqparms, uint16_t max_delay, uint16_t min_delay,
+ tBTM_INQ_RESULTS_CB* p_results_cb) {
+ CHECK(p_inqparms != nullptr);
+ CHECK(p_results_cb != nullptr);
+
+ if (p_inqparms->duration < BTM_MIN_INQUIRY_LEN ||
+ p_inqparms->duration > BTM_MAX_INQUIRY_LENGTH ||
+ min_delay <= p_inqparms->duration ||
+ min_delay < BTM_PER_INQ_MIN_MIN_PERIOD ||
+ min_delay > BTM_PER_INQ_MAX_MIN_PERIOD || max_delay <= min_delay ||
+ max_delay < BTM_PER_INQ_MIN_MAX_PERIOD) {
+ return (BTM_ILLEGAL_VALUE);
+ }
+
+ if (shim_btm.IsInquiryActive()) {
+ return BTM_BUSY;
+ }
+
+ switch (p_inqparms->filter_cond_type) {
+ case kClearInquiryFilter:
+ shim_btm.ClearInquiryFilter();
+ return BTM_SUCCESS;
+ break;
+ case kFilterOnDeviceClass:
+ shim_btm.SetFilterInquiryOnDevice();
+ return BTM_SUCCESS;
+ break;
+ case kFilterOnAddress:
+ shim_btm.SetFilterInquiryOnAddress();
+ return BTM_SUCCESS;
+ break;
+ default:
+ return BTM_ILLEGAL_VALUE;
+ }
+ return BTM_MODE_UNSUPPORTED;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetDiscoverability
+ *
+ * Description This function is called to set the device into or out of
+ * discoverable mode. Discoverable mode means inquiry
+ * scans are enabled. If a value of '0' is entered for window
+ * or interval, the default values are used.
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_BUSY if a setting of the filter is already in progress
+ * BTM_NO_RESOURCES if couldn't get a memory pool buffer
+ * BTM_ILLEGAL_VALUE if a bad parameter was detected
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_SetDiscoverability(uint16_t discoverable_mode,
+ uint16_t window,
+ uint16_t interval) {
+ uint16_t classic_discoverable_mode = discoverable_mode & 0xff;
+ uint16_t le_discoverable_mode = discoverable_mode >> 8;
+
+ if (window == 0) window = BTM_DEFAULT_DISC_WINDOW;
+ if (interval == 0) interval = BTM_DEFAULT_DISC_INTERVAL;
+
+ switch (le_discoverable_mode) {
+ case kDiscoverableModeOff:
+ shim_btm.SetLeDiscoverabilityOff();
+ break;
+ case kLimitedDiscoverableMode:
+ shim_btm.SetLeLimitedDiscoverability();
+ break;
+ case kGeneralDiscoverableMode:
+ shim_btm.SetLeGeneralDiscoverability();
+ break;
+ }
+
+ switch (classic_discoverable_mode) {
+ case kDiscoverableModeOff:
+ shim_btm.SetClassicDiscoverabilityOff();
+ break;
+ case kLimitedDiscoverableMode:
+ shim_btm.SetClassicLimitedDiscoverability(window, interval);
+ break;
+ case kGeneralDiscoverableMode:
+ shim_btm.SetClassicGeneralDiscoverability(window, interval);
+ break;
+ }
+
+ return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetInquiryScanType
+ *
+ * Description This function is called to set the iquiry scan-type to
+ * standard or interlaced.
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_MODE_UNSUPPORTED if not a 1.2 device
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_SetInquiryScanType(uint16_t scan_type) {
+ switch (scan_type) {
+ case kInterlacedScanType:
+ shim_btm.SetInterlacedInquiryScan();
+ return BTM_SUCCESS;
+ break;
+ case kStandardScanType:
+ shim_btm.SetStandardInquiryScan();
+ return BTM_SUCCESS;
+ break;
+ default:
+ return BTM_ILLEGAL_VALUE;
+ }
+ return BTM_WRONG_MODE;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetPageScanType
+ *
+ * Description This function is called to set the page scan-type to
+ * standard or interlaced.
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_MODE_UNSUPPORTED if not a 1.2 device
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_SetPageScanType(uint16_t scan_type) {
+ switch (scan_type) {
+ case kInterlacedScanType:
+ if (!shim_btm.IsInterlacedScanSupported()) {
+ return BTM_MODE_UNSUPPORTED;
+ }
+ shim_btm.SetInterlacedPageScan();
+ return BTM_SUCCESS;
+ break;
+ case kStandardScanType:
+ shim_btm.SetStandardPageScan();
+ return BTM_SUCCESS;
+ break;
+ default:
+ return BTM_ILLEGAL_VALUE;
+ }
+ return BTM_WRONG_MODE;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetInquiryMode
+ *
+ * Description This function is called to set standard or with RSSI
+ * mode of the inquiry for local device.
+ *
+ * Output Params: mode - standard, with RSSI, extended
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_NO_RESOURCES if couldn't get a memory pool buffer
+ * BTM_ILLEGAL_VALUE if a bad parameter was detected
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_SetInquiryMode(uint8_t inquiry_mode) {
+ switch (inquiry_mode) {
+ case kStandardInquiryResult:
+ if (shim_btm.SetStandardInquiryResultMode()) {
+ return BTM_SUCCESS;
+ }
+ break;
+ case kInquiryResultWithRssi:
+ if (shim_btm.SetInquiryWithRssiResultMode()) {
+ return BTM_SUCCESS;
+ }
+ break;
+ case kExtendedInquiryResult:
+ if (shim_btm.SetExtendedInquiryResultMode()) {
+ return BTM_SUCCESS;
+ }
+ break;
+ default:
+ return BTM_ILLEGAL_VALUE;
+ }
+ return BTM_MODE_UNSUPPORTED;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadDiscoverability
+ *
+ * Description This function is called to read the current discoverability
+ * mode of the device.
+ *
+ * Output Params: p_window - current inquiry scan duration
+ * p_interval - current inquiry scan interval
+ *
+ * Returns BTM_NON_DISCOVERABLE, BTM_LIMITED_DISCOVERABLE, or
+ * BTM_GENERAL_DISCOVERABLE
+ *
+ ******************************************************************************/
+uint16_t bluetooth::shim::BTM_ReadDiscoverability(uint16_t* p_window,
+ uint16_t* p_interval) {
+ DiscoverabilityState state = shim_btm.GetClassicDiscoverabilityState();
+
+ if (p_interval) *p_interval = state.interval;
+ if (p_window) *p_window = state.window;
+
+ return state.mode;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_CancelPeriodicInquiry
+ *
+ * Description This function cancels a periodic inquiry
+ *
+ * Returns
+ * BTM_NO_RESOURCES if could not allocate a message buffer
+ * BTM_SUCCESS - if cancelling the periodic inquiry
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_CancelPeriodicInquiry(void) {
+ shim_btm.CancelPeriodicInquiry();
+ return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetConnectability
+ *
+ * Description This function is called to set the device into or out of
+ * connectable mode. Discoverable mode means page scans are
+ * enabled.
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_ILLEGAL_VALUE if a bad parameter is detected
+ * BTM_NO_RESOURCES if could not allocate a message buffer
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_SetConnectability(uint16_t page_mode,
+ uint16_t window,
+ uint16_t interval) {
+ uint16_t classic_connectible_mode = page_mode & 0xff;
+ uint16_t le_connectible_mode = page_mode >> 8;
+
+ if (!window) window = BTM_DEFAULT_CONN_WINDOW;
+ if (!interval) interval = BTM_DEFAULT_CONN_INTERVAL;
+
+ switch (le_connectible_mode) {
+ case kConnectibleModeOff:
+ shim_btm.SetLeConnectibleOff();
+ break;
+ case kConnectibleModeOn:
+ shim_btm.SetLeConnectibleOn();
+ break;
+ default:
+ return BTM_ILLEGAL_VALUE;
+ break;
+ }
+
+ switch (classic_connectible_mode) {
+ case kConnectibleModeOff:
+ shim_btm.SetClassicConnectibleOff();
+ break;
+ case kConnectibleModeOn:
+ shim_btm.SetClassicConnectibleOn();
+ break;
+ default:
+ return BTM_ILLEGAL_VALUE;
+ break;
+ }
+ return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadConnectability
+ *
+ * Description This function is called to read the current discoverability
+ * mode of the device.
+ * Output Params p_window - current page scan duration
+ * p_interval - current time between page scans
+ *
+ * Returns BTM_NON_CONNECTABLE or BTM_CONNECTABLE
+ *
+ ******************************************************************************/
+uint16_t bluetooth::shim::BTM_ReadConnectability(uint16_t* p_window,
+ uint16_t* p_interval) {
+ ConnectabilityState state = shim_btm.GetClassicConnectabilityState();
+
+ if (p_window) *p_window = state.window;
+ if (p_interval) *p_interval = state.interval;
+
+ return state.mode;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_IsInquiryActive
+ *
+ * Description This function returns a bit mask of the current inquiry
+ * state
+ *
+ * Returns BTM_INQUIRY_INACTIVE if inactive (0)
+ * BTM_LIMITED_INQUIRY_ACTIVE if a limted inquiry is active
+ * BTM_GENERAL_INQUIRY_ACTIVE if a general inquiry is active
+ * BTM_PERIODIC_INQUIRY_ACTIVE if a periodic inquiry is active
+ *
+ ******************************************************************************/
+uint16_t bluetooth::shim::BTM_IsInquiryActive(void) {
+ if (shim_btm.IsLimitedInquiryActive()) {
+ return BTM_LIMITED_INQUIRY_ACTIVE;
+ } else if (shim_btm.IsGeneralInquiryActive()) {
+ return BTM_GENERAL_INQUIRY_ACTIVE;
+ } else if (shim_btm.IsGeneralPeriodicInquiryActive() ||
+ shim_btm.IsLimitedPeriodicInquiryActive()) {
+ return BTM_PERIODIC_INQUIRY_ACTIVE;
+ }
+ return BTM_INQUIRY_INACTIVE;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_CancelInquiry
+ *
+ * Description This function cancels an inquiry if active
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_NO_RESOURCES if could not allocate a message buffer
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_CancelInquiry(void) {
+ shim_btm.CancelInquiry();
+ return BTM_SUCCESS;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadRemoteDeviceName
+ *
+ * Description This function initiates a remote device HCI command to the
+ * controller and calls the callback when the process has
+ * completed.
+ *
+ * Input Params: remote_bda - device address of name to retrieve
+ * p_cb - callback function called when
+ * BTM_CMD_STARTED is returned.
+ * A pointer to tBTM_REMOTE_DEV_NAME is
+ * passed to the callback.
+ *
+ * Returns
+ * BTM_CMD_STARTED is returned if the request was successfully
+ * sent to HCI.
+ * BTM_BUSY if already in progress
+ * BTM_UNKNOWN_ADDR if device address is bad
+ * BTM_NO_RESOURCES if could not allocate resources to start
+ * the command
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_ReadRemoteDeviceName(
+ const RawAddress& raw_address, tBTM_CMPL_CB* callback,
+ tBT_TRANSPORT transport) {
+ CHECK(callback != nullptr);
+ tBTM_STATUS status = BTM_NO_RESOURCES;
+
+ switch (transport) {
+ case BT_TRANSPORT_LE:
+ status = shim_btm.ReadLeRemoteDeviceName(raw_address, callback);
+ break;
+ case BT_TRANSPORT_BR_EDR:
+ status = shim_btm.ReadClassicRemoteDeviceName(raw_address, callback);
+ break;
+ default:
+ LOG_WARN(LOG_TAG, "%s Unspecified transport:%d", __func__, transport);
+ break;
+ }
+ return status;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_CancelRemoteDeviceName
+ *
+ * Description This function initiates the cancel request for the specified
+ * remote device.
+ *
+ * Input Params: None
+ *
+ * Returns
+ * BTM_CMD_STARTED is returned if the request was successfully
+ * sent to HCI.
+ * BTM_NO_RESOURCES if could not allocate resources to start
+ * the command
+ * BTM_WRONG_MODE if there is not an active remote name
+ * request.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_CancelRemoteDeviceName(void) {
+ return shim_btm.CancelAllReadRemoteDeviceName();
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_InqDbRead
+ *
+ * Description This function looks through the inquiry database for a match
+ * based on Bluetooth Device Address. This is the application's
+ * interface to get the inquiry details of a specific BD
+ * address.
+ *
+ * Returns pointer to entry, or NULL if not found
+ *
+ ******************************************************************************/
+tBTM_INQ_INFO* bluetooth::shim::BTM_InqDbRead(const RawAddress& p_bda) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return nullptr;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_InqDbFirst
+ *
+ * Description This function looks through the inquiry database for the
+ * first used entry, and returns that. This is used in
+ * conjunction with
+ * BTM_InqDbNext by applications as a way to walk through the
+ * inquiry database.
+ *
+ * Returns pointer to first in-use entry, or NULL if DB is empty
+ *
+ ******************************************************************************/
+tBTM_INQ_INFO* bluetooth::shim::BTM_InqDbFirst(void) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return nullptr;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_InqDbNext
+ *
+ * Description This function looks through the inquiry database for the
+ * next used entry, and returns that. If the input parameter
+ * is NULL, the first entry is returned.
+ *
+ * Returns pointer to next in-use entry, or NULL if no more found.
+ *
+ ******************************************************************************/
+tBTM_INQ_INFO* bluetooth::shim::BTM_InqDbNext(tBTM_INQ_INFO* p_cur) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_cur != nullptr);
+ return nullptr;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ClearInqDb
+ *
+ * Description This function is called to clear out a device or all devices
+ * from the inquiry database.
+ *
+ * Parameter p_bda - (input) BD_ADDR -> Address of device to clear
+ * (NULL clears all entries)
+ *
+ * Returns BTM_BUSY if an inquiry, get remote name, or event filter
+ * is active, otherwise BTM_SUCCESS
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_ClearInqDb(const RawAddress* p_bda) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ if (p_bda == nullptr) {
+ // clear all entries
+ } else {
+ // clear specific entry
+ }
+ return BTM_NO_RESOURCES;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadInquiryRspTxPower
+ *
+ * Description This command will read the inquiry Transmit Power level used
+ * to transmit the FHS and EIR data packets. This can be used
+ * directly in the Tx Power Level EIR data type.
+ *
+ * Returns BTM_SUCCESS if successful
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_ReadInquiryRspTxPower(tBTM_CMPL_CB* p_cb) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_cb != nullptr);
+ return BTM_NO_RESOURCES;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_WriteEIR
+ *
+ * Description This function is called to write EIR data to controller.
+ *
+ * Parameters p_buff - allocated HCI command buffer including extended
+ * inquriry response
+ *
+ * Returns BTM_SUCCESS - if successful
+ * BTM_MODE_UNSUPPORTED - if local device cannot support it
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_WriteEIR(BT_HDR* p_buff) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_buff != nullptr);
+ return BTM_NO_RESOURCES;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_HasEirService
+ *
+ * Description This function is called to know if UUID in bit map of UUID.
+ *
+ * Parameters p_eir_uuid - bit map of UUID list
+ * uuid16 - UUID 16-bit
+ *
+ * Returns true - if found
+ * false - if not found
+ *
+ ******************************************************************************/
+bool bluetooth::shim::BTM_HasEirService(const uint32_t* p_eir_uuid,
+ uint16_t uuid16) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_eir_uuid != nullptr);
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_HasInquiryEirService
+ *
+ * Description This function is called to know if UUID in bit map of UUID
+ * list.
+ *
+ * Parameters p_results - inquiry results
+ * uuid16 - UUID 16-bit
+ *
+ * Returns BTM_EIR_FOUND - if found
+ * BTM_EIR_NOT_FOUND - if not found and it is complete list
+ * BTM_EIR_UNKNOWN - if not found and it is not complete list
+ *
+ ******************************************************************************/
+tBTM_EIR_SEARCH_RESULT bluetooth::shim::BTM_HasInquiryEirService(
+ tBTM_INQ_RESULTS* p_results, uint16_t uuid16) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_results != nullptr);
+ return BTM_EIR_UNKNOWN;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_AddEirService
+ *
+ * Description This function is called to add a service in bit map of UUID
+ * list.
+ *
+ * Parameters p_eir_uuid - bit mask of UUID list for EIR
+ * uuid16 - UUID 16-bit
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_AddEirService(uint32_t* p_eir_uuid, uint16_t uuid16) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_eir_uuid != nullptr);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_RemoveEirService
+ *
+ * Description This function is called to remove a service in bit map of
+ * UUID list.
+ *
+ * Parameters p_eir_uuid - bit mask of UUID list for EIR
+ * uuid16 - UUID 16-bit
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_RemoveEirService(uint32_t* p_eir_uuid,
+ uint16_t uuid16) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_eir_uuid != nullptr);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_GetEirSupportedServices
+ *
+ * Description This function is called to get UUID list from bit map of
+ * UUID list.
+ *
+ * Parameters p_eir_uuid - bit mask of UUID list for EIR
+ * p - reference of current pointer of EIR
+ * max_num_uuid16 - max number of UUID can be written in EIR
+ * num_uuid16 - number of UUID have been written in EIR
+ *
+ * Returns BTM_EIR_MORE_16BITS_UUID_TYPE, if it has more than max
+ * BTM_EIR_COMPLETE_16BITS_UUID_TYPE, otherwise
+ *
+ ******************************************************************************/
+uint8_t bluetooth::shim::BTM_GetEirSupportedServices(uint32_t* p_eir_uuid,
+ uint8_t** p,
+ uint8_t max_num_uuid16,
+ uint8_t* p_num_uuid16) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_eir_uuid != nullptr);
+ CHECK(p != nullptr);
+ CHECK(*p != nullptr);
+ CHECK(p_num_uuid16 != nullptr);
+ return BTM_NO_RESOURCES;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_GetEirUuidList
+ *
+ * Description This function parses EIR and returns UUID list.
+ *
+ * Parameters p_eir - EIR
+ * eir_len - EIR len
+ * uuid_size - Uuid::kNumBytes16, Uuid::kNumBytes32,
+ * Uuid::kNumBytes128
+ * p_num_uuid - return number of UUID in found list
+ * p_uuid_list - return UUID list
+ * max_num_uuid - maximum number of UUID to be returned
+ *
+ * Returns 0 - if not found
+ * BTM_EIR_COMPLETE_16BITS_UUID_TYPE
+ * BTM_EIR_MORE_16BITS_UUID_TYPE
+ * BTM_EIR_COMPLETE_32BITS_UUID_TYPE
+ * BTM_EIR_MORE_32BITS_UUID_TYPE
+ * BTM_EIR_COMPLETE_128BITS_UUID_TYPE
+ * BTM_EIR_MORE_128BITS_UUID_TYPE
+ *
+ ******************************************************************************/
+uint8_t bluetooth::shim::BTM_GetEirUuidList(uint8_t* p_eir, size_t eir_len,
+ uint8_t uuid_size,
+ uint8_t* p_num_uuid,
+ uint8_t* p_uuid_list,
+ uint8_t max_num_uuid) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_eir != nullptr);
+ CHECK(p_num_uuid != nullptr);
+ CHECK(p_uuid_list != nullptr);
+ return 0;
+}
+
+/**
+ *
+ * BLE API HERE
+ *
+ */
+
+bool bluetooth::shim::BTM_SecAddBleDevice(const RawAddress& bd_addr,
+ BD_NAME bd_name,
+ tBT_DEVICE_TYPE dev_type,
+ tBLE_ADDR_TYPE addr_type) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SecAddBleKey
+ *
+ * Description Add/modify LE device information. This function will be
+ * normally called during host startup to restore all required
+ * information stored in the NVRAM.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * p_le_key - LE key values.
+ * key_type - LE SMP key type.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool bluetooth::shim::BTM_SecAddBleKey(const RawAddress& bd_addr,
+ tBTM_LE_KEY_VALUE* p_le_key,
+ tBTM_LE_KEY_TYPE key_type) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_le_key != nullptr);
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleLoadLocalKeys
+ *
+ * Description Local local identity key, encryption root or sign counter.
+ *
+ * Parameters: key_type: type of key, can be BTM_BLE_KEY_TYPE_ID,
+ * BTM_BLE_KEY_TYPE_ER
+ * or BTM_BLE_KEY_TYPE_COUNTER.
+ * p_key: pointer to the key.
+ *
+ * Returns non2.
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleLoadLocalKeys(uint8_t key_type,
+ tBTM_BLE_LOCAL_KEYS* p_key) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_key != nullptr);
+}
+
+static Octet16 bogus_root;
+
+/** Returns local device encryption root (ER) */
+const Octet16& bluetooth::shim::BTM_GetDeviceEncRoot() {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return bogus_root;
+}
+
+/** Returns local device identity root (IR). */
+const Octet16& bluetooth::shim::BTM_GetDeviceIDRoot() {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return bogus_root;
+}
+
+/** Return local device DHK. */
+const Octet16& bluetooth::shim::BTM_GetDeviceDHK() {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return bogus_root;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadConnectionAddr
+ *
+ * Description This function is called to get the local device address
+ * information.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_ReadConnectionAddr(const RawAddress& remote_bda,
+ RawAddress& local_conn_addr,
+ tBLE_ADDR_TYPE* p_addr_type) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_addr_type != nullptr);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_IsBleConnection
+ *
+ * Description This function is called to check if the connection handle
+ * for an LE link
+ *
+ * Returns true if connection is LE link, otherwise false.
+ *
+ ******************************************************************************/
+bool bluetooth::shim::BTM_IsBleConnection(uint16_t conn_handle) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadRemoteConnectionAddr
+ *
+ * Description This function is read the remote device address currently used
+ *
+ * Parameters pseudo_addr: pseudo random address available
+ * conn_addr:connection address used
+ * p_addr_type : BD Address type, Public or Random of the address
+ * used
+ *
+ * Returns bool, true if connection to remote device exists, else false
+ *
+ ******************************************************************************/
+bool bluetooth::shim::BTM_ReadRemoteConnectionAddr(
+ const RawAddress& pseudo_addr, RawAddress& conn_addr,
+ tBLE_ADDR_TYPE* p_addr_type) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_addr_type != nullptr);
+ return false;
+}
+/*******************************************************************************
+ *
+ * Function BTM_SecurityGrant
+ *
+ * Description This function is called to grant security process.
+ *
+ * Parameters bd_addr - peer device bd address.
+ * res - result of the operation BTM_SUCCESS if success.
+ * Otherwise, BTM_REPEATED_ATTEMPTS if too many
+ * attempts.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_SecurityGrant(const RawAddress& bd_addr,
+ uint8_t res) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BlePasskeyReply
+ *
+ * Description This function is called after Security Manager submitted
+ * passkey request to the application.
+ *
+ * Parameters: bd_addr - Address of the device for which passkey was
+ * requested
+ * res - result of the operation BTM_SUCCESS if success
+ * key_len - length in bytes of the Passkey
+ * p_passkey - pointer to array with the passkey
+ * trusted_mask - bitwise OR of trusted services (array of
+ * uint32_t)
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BlePasskeyReply(const RawAddress& bd_addr,
+ uint8_t res, uint32_t passkey) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleConfirmReply
+ *
+ * Description This function is called after Security Manager submitted
+ * numeric comparison request to the application.
+ *
+ * Parameters: bd_addr - Address of the device with which numeric
+ * comparison was requested
+ * res - comparison result BTM_SUCCESS if success
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleConfirmReply(const RawAddress& bd_addr,
+ uint8_t res) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleOobDataReply
+ *
+ * Description This function is called to provide the OOB data for
+ * SMP in response to BTM_LE_OOB_REQ_EVT
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * res - result of the operation SMP_SUCCESS if success
+ * p_data - oob data, depending on transport and
+ * capabilities.
+ * Might be "Simple Pairing Randomizer", or
+ * "Security Manager TK Value".
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleOobDataReply(const RawAddress& bd_addr,
+ uint8_t res, uint8_t len,
+ uint8_t* p_data) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_data != nullptr);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleSecureConnectionOobDataReply
+ *
+ * Description This function is called to provide the OOB data for
+ * SMP in response to BTM_LE_OOB_REQ_EVT when secure connection
+ * data is available
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * p_c - pointer to Confirmation.
+ * p_r - pointer to Randomizer
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleSecureConnectionOobDataReply(
+ const RawAddress& bd_addr, uint8_t* p_c, uint8_t* p_r) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_c != nullptr);
+ CHECK(p_r != nullptr);
+}
+
+/******************************************************************************
+ *
+ * Function BTM_BleSetConnScanParams
+ *
+ * Description Set scan parameter used in BLE connection request
+ *
+ * Parameters: scan_interval: scan interval
+ * scan_window: scan window
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleSetConnScanParams(uint32_t scan_interval,
+ uint32_t scan_window) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+/********************************************************
+ *
+ * Function BTM_BleSetPrefConnParams
+ *
+ * Description Set a peripheral's preferred connection parameters
+ *
+ * Parameters: bd_addr - BD address of the peripheral
+ * scan_interval: scan interval
+ * scan_window: scan window
+ * min_conn_int - minimum preferred connection interval
+ * max_conn_int - maximum preferred connection interval
+ * slave_latency - preferred slave latency
+ * supervision_tout - preferred supervision timeout
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleSetPrefConnParams(const RawAddress& bd_addr,
+ uint16_t min_conn_int,
+ uint16_t max_conn_int,
+ uint16_t slave_latency,
+ uint16_t supervision_tout) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadDevInfo
+ *
+ * Description This function is called to read the device/address type
+ * of BD address.
+ *
+ * Parameter remote_bda: remote device address
+ * p_dev_type: output parameter to read the device type.
+ * p_addr_type: output parameter to read the address type.
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_ReadDevInfo(const RawAddress& remote_bda,
+ tBT_DEVICE_TYPE* p_dev_type,
+ tBLE_ADDR_TYPE* p_addr_type) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_dev_type != nullptr);
+ CHECK(p_addr_type != nullptr);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadConnectedTransportAddress
+ *
+ * Description This function is called to read the paired device/address
+ * type of other device paired corresponding to the BD_address
+ *
+ * Parameter remote_bda: remote device address, carry out the transport
+ * address
+ * transport: active transport
+ *
+ * Return true if an active link is identified; false otherwise
+ *
+ ******************************************************************************/
+bool bluetooth::shim::BTM_ReadConnectedTransportAddress(
+ RawAddress* remote_bda, tBT_TRANSPORT transport) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(remote_bda != nullptr);
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleReceiverTest
+ *
+ * Description This function is called to start the LE Receiver test
+ *
+ * Parameter rx_freq - Frequency Range
+ * p_cmd_cmpl_cback - Command Complete callback
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleReceiverTest(uint8_t rx_freq,
+ tBTM_CMPL_CB* p_cmd_cmpl_cback) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_cmd_cmpl_cback != nullptr);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleTransmitterTest
+ *
+ * Description This function is called to start the LE Transmitter test
+ *
+ * Parameter tx_freq - Frequency Range
+ * test_data_len - Length in bytes of payload data in each
+ * packet
+ * packet_payload - Pattern to use in the payload
+ * p_cmd_cmpl_cback - Command Complete callback
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleTransmitterTest(uint8_t tx_freq,
+ uint8_t test_data_len,
+ uint8_t packet_payload,
+ tBTM_CMPL_CB* p_cmd_cmpl_cback) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_cmd_cmpl_cback != nullptr);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleTestEnd
+ *
+ * Description This function is called to stop the in-progress TX or RX
+ * test
+ *
+ * Parameter p_cmd_cmpl_cback - Command complete callback
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleTestEnd(tBTM_CMPL_CB* p_cmd_cmpl_cback) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_cmd_cmpl_cback != nullptr);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_UseLeLink
+ *
+ * Description This function is to select the underlying physical link to
+ * use.
+ *
+ * Returns true to use LE, false use BR/EDR.
+ *
+ ******************************************************************************/
+bool bluetooth::shim::BTM_UseLeLink(const RawAddress& raw_address) {
+ return shim_btm.IsLeAclConnected(raw_address);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_SetBleDataLength
+ *
+ * Description This function is to set maximum BLE transmission packet size
+ *
+ * Returns BTM_SUCCESS if success; otherwise failed.
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_SetBleDataLength(const RawAddress& bd_addr,
+ uint16_t tx_pdu_length) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return BTM_NO_RESOURCES;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleReadPhy
+ *
+ * Description To read the current PHYs for specified LE connection
+ *
+ *
+ * Returns BTM_SUCCESS if command successfully sent to controller,
+ * BTM_MODE_UNSUPPORTED if local controller doesn't support LE
+ * 2M or LE Coded PHY,
+ * BTM_WRONG_MODE if Device in wrong mode for request.
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleReadPhy(
+ const RawAddress& bd_addr,
+ base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleSetDefaultPhy
+ *
+ * Description To set preferred PHY for ensuing LE connections
+ *
+ *
+ * Returns BTM_SUCCESS if command successfully sent to controller,
+ * BTM_MODE_UNSUPPORTED if local controller doesn't support LE
+ * 2M or LE Coded PHY
+ *
+ ******************************************************************************/
+tBTM_STATUS bluetooth::shim::BTM_BleSetDefaultPhy(uint8_t all_phys,
+ uint8_t tx_phys,
+ uint8_t rx_phys) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return BTM_NO_RESOURCES;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleSetPhy
+ *
+ * Description To set PHY preferences for specified LE connection
+ *
+ *
+ * Returns BTM_SUCCESS if command successfully sent to controller,
+ * BTM_MODE_UNSUPPORTED if local controller doesn't support LE
+ * 2M or LE Coded PHY,
+ * BTM_ILLEGAL_VALUE if specified remote doesn't support LE 2M
+ * or LE Coded PHY,
+ * BTM_WRONG_MODE if Device in wrong mode for request.
+ *
+ ******************************************************************************/
+void bluetooth::shim::BTM_BleSetPhy(const RawAddress& bd_addr, uint8_t tx_phys,
+ uint8_t rx_phys, uint16_t phy_options) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleDataSignature
+ *
+ * Description This function is called to sign the data using AES128 CMAC
+ * algorith.
+ *
+ * Parameter bd_addr: target device the data to be signed for.
+ * p_text: singing data
+ * len: length of the data to be signed.
+ * signature: output parameter where data signature is going to
+ * be stored.
+ *
+ * Returns true if signing sucessul, otherwise false.
+ *
+ ******************************************************************************/
+bool bluetooth::shim::BTM_BleDataSignature(const RawAddress& bd_addr,
+ uint8_t* p_text, uint16_t len,
+ BLE_SIGNATURE signature) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_text != nullptr);
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleVerifySignature
+ *
+ * Description This function is called to verify the data signature
+ *
+ * Parameter bd_addr: target device the data to be signed for.
+ * p_orig: original data before signature.
+ * len: length of the signing data
+ * counter: counter used when doing data signing
+ * p_comp: signature to be compared against.
+
+ * Returns true if signature verified correctly; otherwise false.
+ *
+ ******************************************************************************/
+bool bluetooth::shim::BTM_BleVerifySignature(const RawAddress& bd_addr,
+ uint8_t* p_orig, uint16_t len,
+ uint32_t counter,
+ uint8_t* p_comp) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_orig != nullptr);
+ CHECK(p_comp != nullptr);
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_GetLeSecurityState
+ *
+ * Description This function is called to get security mode 1 flags and
+ * encryption key size for LE peer.
+ *
+ * Returns bool true if LE device is found, false otherwise.
+ *
+ ******************************************************************************/
+bool bluetooth::shim::BTM_GetLeSecurityState(const RawAddress& bd_addr,
+ uint8_t* p_le_dev_sec_flags,
+ uint8_t* p_le_key_size) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ CHECK(p_le_dev_sec_flags != nullptr);
+ CHECK(p_le_key_size != nullptr);
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleSecurityProcedureIsRunning
+ *
+ * Description This function indicates if LE security procedure is
+ * currently running with the peer.
+ *
+ * Returns bool true if security procedure is running, false
+ * otherwise.
+ *
+ ******************************************************************************/
+bool bluetooth::shim::BTM_BleSecurityProcedureIsRunning(
+ const RawAddress& bd_addr) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+/*******************************************************************************
+ *
+ * Function BTM_BleGetSupportedKeySize
+ *
+ * Description This function gets the maximum encryption key size in bytes
+ * the local device can suport.
+ * record.
+ *
+ * Returns the key size or 0 if the size can't be retrieved.
+ *
+ ******************************************************************************/
+uint8_t bluetooth::shim::BTM_BleGetSupportedKeySize(const RawAddress& bd_addr) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return 0;
+}
+
+/**
+ * This function update(add,delete or clear) the adv local name filtering
+ * condition.
+ */
+void bluetooth::shim::BTM_LE_PF_local_name(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index,
+ std::vector<uint8_t> name,
+ tBTM_BLE_PF_CFG_CBACK cb) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::BTM_LE_PF_srvc_data(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::BTM_LE_PF_manu_data(
+ tBTM_BLE_SCAN_COND_OP action, tBTM_BLE_PF_FILT_INDEX filt_index,
+ uint16_t company_id, uint16_t company_id_mask, std::vector<uint8_t> data,
+ std::vector<uint8_t> data_mask, tBTM_BLE_PF_CFG_CBACK cb) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::BTM_LE_PF_srvc_data_pattern(
+ tBTM_BLE_SCAN_COND_OP action, tBTM_BLE_PF_FILT_INDEX filt_index,
+ std::vector<uint8_t> data, std::vector<uint8_t> data_mask,
+ tBTM_BLE_PF_CFG_CBACK cb) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::BTM_LE_PF_addr_filter(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index,
+ tBLE_BD_ADDR addr,
+ tBTM_BLE_PF_CFG_CBACK cb) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::BTM_LE_PF_uuid_filter(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index,
+ tBTM_BLE_PF_COND_TYPE filter_type,
+ const bluetooth::Uuid& uuid,
+ tBTM_BLE_PF_LOGIC_TYPE cond_logic,
+ const bluetooth::Uuid& uuid_mask,
+ tBTM_BLE_PF_CFG_CBACK cb) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::BTM_LE_PF_set(tBTM_BLE_PF_FILT_INDEX filt_index,
+ std::vector<ApcfCommand> commands,
+ tBTM_BLE_PF_CFG_CBACK cb) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::BTM_LE_PF_clear(tBTM_BLE_PF_FILT_INDEX filt_index,
+ tBTM_BLE_PF_CFG_CBACK cb) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::BTM_BleAdvFilterParamSetup(
+ int action, tBTM_BLE_PF_FILT_INDEX filt_index,
+ std::unique_ptr<btgatt_filt_param_setup_t> p_filt_params,
+ tBTM_BLE_PF_PARAM_CB cb) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
+
+void bluetooth::shim::BTM_BleEnableDisableFilterFeature(
+ uint8_t enable, tBTM_BLE_PF_STATUS_CBACK p_stat_cback) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+}
diff --git a/main/shim/btm_api.h b/main/shim/btm_api.h
new file mode 100644
index 0000000..6cd1fc4
--- /dev/null
+++ b/main/shim/btm_api.h
@@ -0,0 +1,2785 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "stack/include/btm_api_types.h"
+#include "stack/include/btm_ble_api_types.h"
+
+namespace bluetooth {
+namespace shim {
+
+/*******************************************************************************
+ *
+ * Function BTM_DeviceReset
+ *
+ * Description This function is called to reset the controller. The
+ * Callback function if provided is called when startup of the
+ * device has completed.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_DeviceReset(tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_IsDeviceUp
+ *
+ * Description This function is called to check if the device is up.
+ *
+ * Returns true if device is up, else false
+ *
+ ******************************************************************************/
+bool BTM_IsDeviceUp(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetLocalDeviceName
+ *
+ * Description This function is called to set the local device name.
+ *
+ * Returns BTM_CMD_STARTED if successful, otherwise an error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetLocalDeviceName(char* p_name);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetDeviceClass
+ *
+ * Description This function is called to set the local device class
+ *
+ * Returns BTM_SUCCESS if successful, otherwise an error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetDeviceClass(DEV_CLASS dev_class);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadLocalDeviceName
+ *
+ * Description This function is called to read the local device name.
+ *
+ * Returns status of the operation
+ * If success, BTM_SUCCESS is returned and p_name points stored
+ * local device name
+ * If BTM doesn't store local device name, BTM_NO_RESOURCES is
+ * is returned and p_name is set to NULL
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadLocalDeviceName(char** p_name);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadLocalDeviceNameFromController
+ *
+ * Description Get local device name from controller. Do not use cached
+ * name (used to get chip-id prior to btm reset complete).
+ *
+ * Returns BTM_CMD_STARTED if successful, otherwise an error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadLocalDeviceNameFromController(
+ tBTM_CMPL_CB* p_rln_cmpl_cback);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadDeviceClass
+ *
+ * Description This function is called to read the local device class
+ *
+ * Returns pointer to the device class
+ *
+ ******************************************************************************/
+uint8_t* BTM_ReadDeviceClass(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadLocalFeatures
+ *
+ * Description This function is called to read the local features
+ *
+ * Returns pointer to the local features string
+ *
+ ******************************************************************************/
+uint8_t* BTM_ReadLocalFeatures(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_RegisterForDeviceStatusNotif
+ *
+ * Description This function is called to register for device status
+ * change notifications.
+ *
+ * Returns pointer to previous caller's callback function or NULL if
+ * first registration.
+ *
+ ******************************************************************************/
+tBTM_DEV_STATUS_CB* BTM_RegisterForDeviceStatusNotif(tBTM_DEV_STATUS_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_RegisterForVSEvents
+ *
+ * Description This function is called to register/deregister for vendor
+ * specific HCI events.
+ *
+ * If is_register=true, then the function will be registered;
+ * otherwise the function will be deregistered.
+ *
+ * Returns BTM_SUCCESS if successful,
+ * BTM_BUSY if maximum number of callbacks have already been
+ * registered.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_RegisterForVSEvents(tBTM_VS_EVT_CB* p_cb, bool is_register);
+
+/*******************************************************************************
+ *
+ * Function BTM_VendorSpecificCommand
+ *
+ * Description Send a vendor specific HCI command to the controller.
+ *
+ ******************************************************************************/
+void BTM_VendorSpecificCommand(uint16_t opcode, uint8_t param_len,
+ uint8_t* p_param_buf, tBTM_VSC_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_AllocateSCN
+ *
+ * Description Look through the Server Channel Numbers for a free one to be
+ * used with an RFCOMM connection.
+ *
+ * Returns Allocated SCN number or 0 if none.
+ *
+ ******************************************************************************/
+uint8_t BTM_AllocateSCN(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_TryAllocateSCN
+ *
+ * Description Try to allocate a fixed server channel
+ *
+ * Returns Returns true if server channel was available
+ *
+ ******************************************************************************/
+bool BTM_TryAllocateSCN(uint8_t scn);
+
+/*******************************************************************************
+ *
+ * Function BTM_FreeSCN
+ *
+ * Description Free the specified SCN.
+ *
+ * Returns true if successful, false if SCN is not in use or invalid
+ *
+ ******************************************************************************/
+bool BTM_FreeSCN(uint8_t scn);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetTraceLevel
+ *
+ * Description This function sets the trace level for BTM. If called with
+ * a value of 0xFF, it simply returns the current trace level.
+ *
+ * Returns The new or current trace level
+ *
+ ******************************************************************************/
+uint8_t BTM_SetTraceLevel(uint8_t new_level);
+
+/*******************************************************************************
+ *
+ * Function BTM_WritePageTimeout
+ *
+ * Description Send HCI Wite Page Timeout.
+ *
+ ******************************************************************************/
+void BTM_WritePageTimeout(uint16_t timeout);
+
+/*******************************************************************************
+ *
+ * Function BTM_WriteVoiceSettings
+ *
+ * Description Send HCI Write Voice Settings command.
+ * See hcidefs.h for settings bitmask values.
+ *
+ ******************************************************************************/
+void BTM_WriteVoiceSettings(uint16_t settings);
+
+/*******************************************************************************
+ *
+ * Function BTM_EnableTestMode
+ *
+ * Description Send HCI the enable device under test command.
+ *
+ * Note: Controller can only be taken out of this mode by
+ * resetting the controller.
+ *
+ * Returns
+ * BTM_SUCCESS Command sent.
+ * BTM_NO_RESOURCES If out of resources to send the command.
+ *
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_EnableTestMode(void);
+
+/*******************************************************************************
+ * DEVICE DISCOVERY FUNCTIONS - Inquiry, Remote Name, Discovery, Class of Device
+ ******************************************************************************/
+
+/*******************************************************************************
+ *
+ * Function BTM_SetDiscoverability
+ *
+ * Description This function is called to set the device into or out of
+ * discoverable mode. Discoverable mode means inquiry
+ * scans are enabled. If a value of '0' is entered for window
+ * or interval, the default values are used.
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_BUSY if a setting of the filter is already in progress
+ * BTM_NO_RESOURCES if couldn't get a memory pool buffer
+ * BTM_ILLEGAL_VALUE if a bad parameter was detected
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetDiscoverability(uint16_t inq_mode, uint16_t window,
+ uint16_t interval);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadDiscoverability
+ *
+ * Description This function is called to read the current discoverability
+ * mode of the device.
+ *
+ * Output Params: p_window - current inquiry scan duration
+ * p_interval - current inquiry scan interval
+ *
+ * Returns BTM_NON_DISCOVERABLE, BTM_LIMITED_DISCOVERABLE, or
+ * BTM_GENERAL_DISCOVERABLE
+ *
+ ******************************************************************************/
+uint16_t BTM_ReadDiscoverability(uint16_t* p_window, uint16_t* p_interval);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetPeriodicInquiryMode
+ *
+ * Description This function is called to set the device periodic inquiry
+ * mode. If the duration is zero, the periodic inquiry mode is
+ * cancelled.
+ *
+ * Parameters: p_inqparms - pointer to the inquiry information
+ * mode - GENERAL or LIMITED inquiry
+ * duration - length in 1.28 sec intervals (If '0', the
+ * inquiry is CANCELLED)
+ * max_resps - maximum amount of devices to search for
+ * before ending the inquiry
+ * filter_cond_type - BTM_CLR_INQUIRY_FILTER,
+ * BTM_FILTER_COND_DEVICE_CLASS, or
+ * BTM_FILTER_COND_BD_ADDR
+ * filter_cond - value for the filter (based on
+ * filter_cond_type)
+ *
+ * max_delay - maximum amount of time between successive
+ * inquiries
+ * min_delay - minimum amount of time between successive
+ * inquiries
+ * p_results_cb - callback returning pointer to results
+ * (tBTM_INQ_RESULTS)
+ *
+ * Returns BTM_CMD_STARTED if successfully started
+ * BTM_ILLEGAL_VALUE if a bad parameter is detected
+ * BTM_NO_RESOURCES if could not allocate a message buffer
+ * BTM_SUCCESS - if cancelling the periodic inquiry
+ * BTM_BUSY - if an inquiry is already active
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetPeriodicInquiryMode(tBTM_INQ_PARMS* p_inqparms,
+ uint16_t max_delay, uint16_t min_delay,
+ tBTM_INQ_RESULTS_CB* p_results_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_StartInquiry
+ *
+ * Description This function is called to start an inquiry.
+ *
+ * Parameters: p_inqparms - pointer to the inquiry information
+ * mode - GENERAL or LIMITED inquiry
+ * duration - length in 1.28 sec intervals (If '0', the
+ * inquiry is CANCELLED)
+ * max_resps - maximum amount of devices to search for
+ * before ending the inquiry
+ * filter_cond_type - BTM_CLR_INQUIRY_FILTER,
+ * BTM_FILTER_COND_DEVICE_CLASS, or
+ * BTM_FILTER_COND_BD_ADDR
+ * filter_cond - value for the filter (based on
+ * filter_cond_type)
+ *
+ * p_results_cb - Pointer to the callback routine which gets
+ * called upon receipt of an inquiry result. If
+ * this field is NULL, the application is not
+ * notified.
+ *
+ * p_cmpl_cb - Pointer to the callback routine which gets
+ * called upon completion. If this field is
+ * NULL, the application is not notified when
+ * completed.
+ * Returns tBTM_STATUS
+ * BTM_CMD_STARTED if successfully initiated
+ * BTM_BUSY if already in progress
+ * BTM_ILLEGAL_VALUE if parameter(s) are out of range
+ * BTM_NO_RESOURCES if could not allocate resources to start
+ * the command
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_StartInquiry(tBTM_INQ_PARMS* p_inqparms,
+ tBTM_INQ_RESULTS_CB* p_results_cb,
+ tBTM_CMPL_CB* p_cmpl_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_IsInquiryActive
+ *
+ * Description Return a bit mask of the current inquiry state
+ *
+ * Returns BTM_INQUIRY_INACTIVE if inactive (0)
+ * BTM_LIMITED_INQUIRY_ACTIVE if a limted inquiry is active
+ * BTM_GENERAL_INQUIRY_ACTIVE if a general inquiry is active
+ * BTM_PERIODIC_INQUIRY_ACTIVE if a periodic inquiry is active
+ *
+ ******************************************************************************/
+uint16_t BTM_IsInquiryActive(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_CancelInquiry
+ *
+ * Description This function cancels an inquiry if active
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_NO_RESOURCES if could not allocate a message buffer
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_CancelInquiry(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_CancelPeriodicInquiry
+ *
+ * Description This function cancels a periodic inquiry
+ *
+ * Returns
+ * BTM_NO_RESOURCES if could not allocate a message buffer
+ * BTM_SUCCESS - if cancelling the periodic inquiry
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_CancelPeriodicInquiry(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetConnectability
+ *
+ * Description This function is called to set the device into or out of
+ * connectable mode. Discoverable mode means page scans are
+ * enabled.
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_ILLEGAL_VALUE if a bad parameter is detected
+ * BTM_NO_RESOURCES if could not allocate a message buffer
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetConnectability(uint16_t page_mode, uint16_t window,
+ uint16_t interval);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadConnectability
+ *
+ * Description This function is called to read the current discoverability
+ * mode of the device.
+ * Output Params p_window - current page scan duration
+ * p_interval - current time between page scans
+ *
+ * Returns BTM_NON_CONNECTABLE or BTM_CONNECTABLE
+ *
+ ******************************************************************************/
+uint16_t BTM_ReadConnectability(uint16_t* p_window, uint16_t* p_interval);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetInquiryMode
+ *
+ * Description This function is called to set standard, with RSSI
+ * mode or extended of the inquiry for local device.
+ *
+ * Input Params: BTM_INQ_RESULT_STANDARD, BTM_INQ_RESULT_WITH_RSSI or
+ * BTM_INQ_RESULT_EXTENDED
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_NO_RESOURCES if couldn't get a memory pool buffer
+ * BTM_ILLEGAL_VALUE if a bad parameter was detected
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetInquiryMode(uint8_t mode);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetInquiryScanType
+ *
+ * Description This function is called to set the iquiry scan-type to
+ * standard or interlaced.
+ *
+ * Input Params: BTM_SCAN_TYPE_STANDARD or BTM_SCAN_TYPE_INTERLACED
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_MODE_UNSUPPORTED if not a 1.2 device
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetInquiryScanType(uint16_t scan_type);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetPageScanType
+ *
+ * Description This function is called to set the page scan-type to
+ * standard or interlaced.
+ *
+ * Input Params: BTM_SCAN_TYPE_STANDARD or BTM_SCAN_TYPE_INTERLACED
+ *
+ * Returns BTM_SUCCESS if successful
+ * BTM_MODE_UNSUPPORTED if not a 1.2 device
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+
+tBTM_STATUS BTM_SetPageScanType(uint16_t scan_type);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadRemoteDeviceName
+ *
+ * Description This function initiates a remote device HCI command to the
+ * controller and calls the callback when the process has
+ * completed.
+ *
+ * Input Params: remote_bda - device address of name to retrieve
+ * p_cb - callback function called when
+ * BTM_CMD_STARTED is returned.
+ * A pointer to tBTM_REMOTE_DEV_NAME is
+ * passed to the callback.
+ *
+ * Returns
+ * BTM_CMD_STARTED is returned if the request was successfully
+ * sent to HCI.
+ * BTM_BUSY if already in progress
+ * BTM_UNKNOWN_ADDR if device address is bad
+ * BTM_NO_RESOURCES if resources could not be allocated to
+ * start the command
+ * BTM_WRONG_MODE if the device is not up.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadRemoteDeviceName(const RawAddress& remote_bda,
+ tBTM_CMPL_CB* p_cb,
+ tBT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function BTM_CancelRemoteDeviceName
+ *
+ * Description This function initiates the cancel request for the specified
+ * remote device.
+ *
+ * Input Params: None
+ *
+ * Returns
+ * BTM_CMD_STARTED is returned if the request was successfully
+ * sent to HCI.
+ * BTM_NO_RESOURCES if resources could not be allocated to
+ * start the command
+ * BTM_WRONG_MODE if there is no active remote name request.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_CancelRemoteDeviceName(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadRemoteVersion
+ *
+ * Description This function is called to read a remote device's version
+ *
+ * Returns BTM_SUCCESS if successful, otherwise an error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadRemoteVersion(const RawAddress& addr, uint8_t* lmp_version,
+ uint16_t* manufacturer,
+ uint16_t* lmp_sub_version);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadRemoteFeatures
+ *
+ * Description This function is called to read a remote device's
+ * supported features mask (features mask located at page 0)
+ *
+ * Note: The size of device features mask page is
+ * BTM_FEATURE_BYTES_PER_PAGE bytes.
+ *
+ * Returns pointer to the remote supported features mask
+ *
+ ******************************************************************************/
+uint8_t* BTM_ReadRemoteFeatures(const RawAddress& addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadRemoteExtendedFeatures
+ *
+ * Description This function is called to read a specific extended features
+ * page of the remote device
+ *
+ * Note1: The size of device features mask page is
+ * BTM_FEATURE_BYTES_PER_PAGE bytes.
+ * Note2: The valid device features mask page number depends on
+ * the remote device capabilities. It is expected to be in the
+ * range [0 - BTM_EXT_FEATURES_PAGE_MAX].
+
+ * Returns pointer to the remote extended features mask
+ * or NULL if page_number is not valid
+ *
+ ******************************************************************************/
+uint8_t* BTM_ReadRemoteExtendedFeatures(const RawAddress& addr,
+ uint8_t page_number);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadNumberRemoteFeaturesPages
+ *
+ * Description This function is called to retrieve the number of feature
+ * pages read from the remote device
+ *
+ * Returns number of features pages read from the remote device
+ *
+ ******************************************************************************/
+uint8_t BTM_ReadNumberRemoteFeaturesPages(const RawAddress& addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadAllRemoteFeatures
+ *
+ * Description Read all the features of the remote device
+ *
+ * Returns pointer to the byte[0] of the page[0] of the remote device
+ * feature mask.
+ *
+ * Note: the function returns the pointer to the array of the size
+ * BTM_FEATURE_BYTES_PER_PAGE * (BTM_EXT_FEATURES_PAGE_MAX + 1)
+ *
+ ******************************************************************************/
+uint8_t* BTM_ReadAllRemoteFeatures(const RawAddress& addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_InqDbRead
+ *
+ * Description This function looks through the inquiry database for a match
+ * based on Bluetooth Device Address. This is the application's
+ * interface to get the inquiry details of a specific BD
+ * address.
+ *
+ * Returns pointer to entry, or NULL if not found
+ *
+ ******************************************************************************/
+tBTM_INQ_INFO* BTM_InqDbRead(const RawAddress& p_bda);
+
+/*******************************************************************************
+ *
+ * Function BTM_InqDbFirst
+ *
+ * Description This function looks through the inquiry database for the
+ * first used entry, and returns that. This is used in
+ * conjunction with BTM_InqDbNext by applications as a way to
+ * walk through the inquiry database.
+ *
+ * Returns pointer to first in-use entry, or NULL if DB is empty
+ *
+ ******************************************************************************/
+tBTM_INQ_INFO* BTM_InqDbFirst(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_InqDbNext
+ *
+ * Description This function looks through the inquiry database for the
+ * next used entry, and returns that. If the input parameter
+ * is NULL, the first entry is returned.
+ *
+ * Returns pointer to next in-use entry, or NULL if no more found.
+ *
+ ******************************************************************************/
+tBTM_INQ_INFO* BTM_InqDbNext(tBTM_INQ_INFO* p_cur);
+
+/*******************************************************************************
+ *
+ * Function BTM_ClearInqDb
+ *
+ * Description This function is called to clear out a device or all devices
+ * from the inquiry database.
+ *
+ * Parameter p_bda - (input) BD_ADDR -> Address of device to clear
+ * (NULL clears all entries)
+ *
+ * Returns BTM_BUSY if an inquiry, get remote name, or event filter
+ * is active, otherwise BTM_SUCCESS
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ClearInqDb(const RawAddress* p_bda);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadInquiryRspTxPower
+ *
+ * Description This command will read the inquiry Transmit Power level used
+ * to transmit the FHS and EIR data packets.
+ * This can be used directly in the Tx Power Level EIR data
+ * type.
+ *
+ * Returns BTM_SUCCESS if successful
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadInquiryRspTxPower(tBTM_CMPL_CB* p_cb);
+
+/*****************************************************************************
+ * ACL CHANNEL MANAGEMENT FUNCTIONS
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function BTM_SetLinkPolicy
+ *
+ * Description Create and send HCI "Write Policy Set" command
+ *
+ * Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetLinkPolicy(const RawAddress& remote_bda, uint16_t* settings);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetDefaultLinkPolicy
+ *
+ * Description Set the default value for HCI "Write Policy Set" command
+ * to use when an ACL link is created.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_SetDefaultLinkPolicy(uint16_t settings);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetDefaultLinkSuperTout
+ *
+ * Description Set the default value for HCI "Write Link Supervision
+ * Timeout" command to use when an ACL link is created.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_SetDefaultLinkSuperTout(uint16_t timeout);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetLinkSuperTout
+ *
+ * Description Create and send HCI "Write Link Supervision Timeout" command
+ *
+ * Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetLinkSuperTout(const RawAddress& remote_bda,
+ uint16_t timeout);
+/*******************************************************************************
+ *
+ * Function BTM_GetLinkSuperTout
+ *
+ * Description Read the link supervision timeout value of the connection
+ *
+ * Returns status of the operation
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_GetLinkSuperTout(const RawAddress& remote_bda,
+ uint16_t* p_timeout);
+
+/*******************************************************************************
+ *
+ * Function BTM_IsAclConnectionUp
+ *
+ * Description This function is called to check if an ACL connection exists
+ * to a specific remote BD Address.
+ *
+ * Returns true if connection is up, else false.
+ *
+ ******************************************************************************/
+bool BTM_IsAclConnectionUp(const RawAddress& remote_bda,
+ tBT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function BTM_GetRole
+ *
+ * Description This function is called to get the role of the local device
+ * for the ACL connection with the specified remote device
+ *
+ * Returns BTM_SUCCESS if connection exists.
+ * BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_GetRole(const RawAddress& remote_bd_addr, uint8_t* p_role);
+
+/*******************************************************************************
+ *
+ * Function BTM_SwitchRole
+ *
+ * Description This function is called to switch role between master and
+ * slave. If role is already set it will do nothing. If the
+ * command was initiated, the callback function is called upon
+ * completion.
+ *
+ * Returns BTM_SUCCESS if already in specified role.
+ * BTM_CMD_STARTED if command issued to controller.
+ * BTM_NO_RESOURCES if memory couldn't be allocated to issue
+ * the command
+ * BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ * BTM_MODE_UNSUPPORTED if the local device does not support
+ * role switching
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SwitchRole(const RawAddress& remote_bd_addr, uint8_t new_role,
+ tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadRSSI
+ *
+ * Description This function is called to read the link policy settings.
+ * The address of link policy results are returned in the
+ * callback. (tBTM_RSSI_RESULT)
+ *
+ * Returns BTM_CMD_STARTED if command issued to controller.
+ * BTM_NO_RESOURCES if memory couldn't be allocated to issue
+ * the command
+ * BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ * BTM_BUSY if command is already in progress
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadRSSI(const RawAddress& remote_bda, tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadFailedContactCounter
+ *
+ * Description This function is called to read the failed contact counter.
+ * The result is returned in the callback.
+ * (tBTM_FAILED_CONTACT_COUNTER_RESULT)
+ *
+ * Returns BTM_CMD_STARTED if command issued to controller.
+ * BTM_NO_RESOURCES if memory couldn't be allocated to issue
+ * the command
+ * BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ * BTM_BUSY if command is already in progress
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadFailedContactCounter(const RawAddress& remote_bda,
+ tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadAutomaticFlushTimeout
+ *
+ * Description This function is called to read the automatic flush timeout.
+ * The result is returned in the callback.
+ * (tBTM_AUTOMATIC_FLUSH_TIMEOUT_RESULT)
+ *
+ * Returns BTM_CMD_STARTED if command issued to controller.
+ * BTM_NO_RESOURCES if memory couldn't be allocated to issue
+ * the command
+ * BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ * BTM_BUSY if command is already in progress
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadAutomaticFlushTimeout(const RawAddress& remote_bda,
+ tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadTxPower
+ *
+ * Description This function is called to read the current connection
+ * TX power of the connection. The TX power level results
+ * are returned in the callback.
+ * (tBTM_RSSI_RESULT)
+ *
+ * Returns BTM_CMD_STARTED if command issued to controller.
+ * BTM_NO_RESOURCES if memory couldn't be allocated to issue
+ * the command
+ * BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ * BTM_BUSY if command is already in progress
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadTxPower(const RawAddress& remote_bda,
+ tBT_TRANSPORT transport, tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadLinkQuality
+ *
+ * Description This function is called to read the link quality.
+ * The value of the link quality is returned in the callback.
+ * (tBTM_LINK_QUALITY_RESULT)
+ *
+ * Returns BTM_CMD_STARTED if command issued to controller.
+ * BTM_NO_RESOURCES if memory couldn't be allocated to issue
+ * the command
+ * BTM_UNKNOWN_ADDR if no active link with bd addr specified
+ * BTM_BUSY if command is already in progress
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadLinkQuality(const RawAddress& remote_bda,
+ tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_RegBusyLevelNotif
+ *
+ * Description This function is called to register a callback to receive
+ * busy level change events.
+ *
+ * Returns BTM_SUCCESS if successfully registered, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_RegBusyLevelNotif(tBTM_BL_CHANGE_CB* p_cb, uint8_t* p_level,
+ tBTM_BL_EVENT_MASK evt_mask);
+
+/*******************************************************************************
+ *
+ * Function BTM_AclRegisterForChanges
+ *
+ * Description This function is called to register a callback to receive
+ * ACL database change events, i.e. new connection or removed.
+ *
+ * Returns BTM_SUCCESS if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_AclRegisterForChanges(tBTM_ACL_DB_CHANGE_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_GetNumAclLinks
+ *
+ * Description This function is called to count the number of
+ * ACL links that are active.
+ *
+ * Returns uint16_t Number of active ACL links
+ *
+ ******************************************************************************/
+uint16_t BTM_GetNumAclLinks(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetQoS
+ *
+ * Description This function is called to setup QoS
+ *
+ * Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetQoS(const RawAddress& bd, FLOW_SPEC* p_flow,
+ tBTM_CMPL_CB* p_cb);
+
+/*****************************************************************************
+ * (e)SCO CHANNEL MANAGEMENT FUNCTIONS
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function BTM_CreateSco
+ *
+ * Description This function is called to create an SCO connection. If the
+ * "is_orig" flag is true, the connection will be originated,
+ * otherwise BTM will wait for the other side to connect.
+ *
+ * Returns BTM_UNKNOWN_ADDR if the ACL connection is not up
+ * BTM_BUSY if another SCO being set up to
+ * the same BD address
+ * BTM_NO_RESOURCES if the max SCO limit has been reached
+ * BTM_CMD_STARTED if the connection establishment is started.
+ * In this case, "*p_sco_inx" is filled in
+ * with the sco index used for the connection.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_CreateSco(const RawAddress* remote_bda, bool is_orig,
+ uint16_t pkt_types, uint16_t* p_sco_inx,
+ tBTM_SCO_CB* p_conn_cb, tBTM_SCO_CB* p_disc_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_RemoveSco
+ *
+ * Description This function is called to remove a specific SCO connection.
+ *
+ * Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_RemoveSco(uint16_t sco_inx);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetScoPacketTypes
+ *
+ * Description This function is called to set the packet types used for
+ * a specific SCO connection,
+ *
+ * Parameters pkt_types - One or more of the following
+ * BTM_SCO_PKT_TYPES_MASK_HV1
+ * BTM_SCO_PKT_TYPES_MASK_HV2
+ * BTM_SCO_PKT_TYPES_MASK_HV3
+ * BTM_SCO_PKT_TYPES_MASK_EV3
+ * BTM_SCO_PKT_TYPES_MASK_EV4
+ * BTM_SCO_PKT_TYPES_MASK_EV5
+ *
+ * BTM_SCO_LINK_ALL_MASK - enables all supported types
+ *
+ * Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetScoPacketTypes(uint16_t sco_inx, uint16_t pkt_types);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadScoPacketTypes
+ *
+ * Description This function is read the packet types used for a specific
+ * SCO connection.
+ *
+ * Returns One or more of the following (bitmask)
+ * BTM_SCO_PKT_TYPES_MASK_HV1
+ * BTM_SCO_PKT_TYPES_MASK_HV2
+ * BTM_SCO_PKT_TYPES_MASK_HV3
+ * BTM_SCO_PKT_TYPES_MASK_EV3
+ * BTM_SCO_PKT_TYPES_MASK_EV4
+ * BTM_SCO_PKT_TYPES_MASK_EV5
+ *
+ * Returns packet types supported for the connection
+ *
+ ******************************************************************************/
+uint16_t BTM_ReadScoPacketTypes(uint16_t sco_inx);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadDeviceScoPacketTypes
+ *
+ * Description This function is read the SCO packet types that
+ * the device supports.
+ *
+ * Returns packet types supported by the device.
+ *
+ ******************************************************************************/
+uint16_t BTM_ReadDeviceScoPacketTypes(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadScoHandle
+ *
+ * Description Reead the HCI handle used for a specific SCO connection,
+ *
+ * Returns handle for the connection, or 0xFFFF if invalid SCO index.
+ *
+ ******************************************************************************/
+uint16_t BTM_ReadScoHandle(uint16_t sco_inx);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadScoBdAddr
+ *
+ * Description This function is read the remote BD Address for a specific
+ * SCO connection,
+ *
+ * Returns pointer to BD address or NULL if not known
+ *
+ ******************************************************************************/
+const RawAddress* BTM_ReadScoBdAddr(uint16_t sco_inx);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadScoDiscReason
+ *
+ * Description This function is returns the reason why an (e)SCO connection
+ * has been removed. It contains the value until read, or until
+ * another (e)SCO connection has disconnected.
+ *
+ * Returns HCI reason or BTM_INVALID_SCO_DISC_REASON if not set.
+ *
+ ******************************************************************************/
+uint16_t BTM_ReadScoDiscReason(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetEScoMode
+ *
+ * Description This function sets up the negotiated parameters for SCO or
+ * eSCO, and sets as the default mode used for calls to
+ * BTM_CreateSco. It can be called only when there are no
+ * active (e)SCO links.
+ *
+ * Returns BTM_SUCCESS if the successful.
+ * BTM_BUSY if there are one or more active (e)SCO links.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetEScoMode(enh_esco_params_t* p_parms);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetWBSCodec
+ *
+ * Description This function sends command to the controller to setup
+ * WBS codec for the upcoming eSCO connection.
+ *
+ * Returns BTM_SUCCESS.
+ *
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetWBSCodec(tBTM_SCO_CODEC_TYPE codec_type);
+
+/*******************************************************************************
+ *
+ * Function BTM_RegForEScoEvts
+ *
+ * Description This function registers a SCO event callback with the
+ * specified instance. It should be used to received
+ * connection indication events and change of link parameter
+ * events.
+ *
+ * Returns BTM_SUCCESS if the successful.
+ * BTM_ILLEGAL_VALUE if there is an illegal sco_inx
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_RegForEScoEvts(uint16_t sco_inx, tBTM_ESCO_CBACK* p_esco_cback);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadEScoLinkParms
+ *
+ * Description This function returns the current eSCO link parameters for
+ * the specified handle. This can be called anytime a
+ * connection is active, but is typically called after
+ * receiving the SCO opened callback.
+ *
+ * Note: If called over a 1.1 controller, only the packet types
+ * field has meaning.
+ * Note: If the upper layer doesn't know the current sco index,
+ * BTM_FIRST_ACTIVE_SCO_INDEX can be used as the first
+ * parameter to find the first active SCO index
+ *
+ * Returns BTM_SUCCESS if returned data is valid connection.
+ * BTM_ILLEGAL_VALUE if no connection for specified sco_inx.
+ * BTM_MODE_UNSUPPORTED if local controller does not support
+ * 1.2 specification.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadEScoLinkParms(uint16_t sco_inx, tBTM_ESCO_DATA* p_parms);
+
+/*******************************************************************************
+ *
+ * Function BTM_ChangeEScoLinkParms
+ *
+ * Description This function requests renegotiation of the parameters on
+ * the current eSCO Link. If any of the changes are accepted
+ * by the controllers, the BTM_ESCO_CHG_EVT event is sent in
+ * the tBTM_ESCO_CBACK function with the current settings of
+ * the link. The callback is registered through the call to
+ * BTM_SetEScoMode.
+ *
+ *
+ * Returns BTM_CMD_STARTED if command is successfully initiated.
+ * BTM_ILLEGAL_VALUE if no connection for specified sco_inx.
+ * BTM_NO_RESOURCES - not enough resources to initiate command.
+ * BTM_MODE_UNSUPPORTED if local controller does not support
+ * 1.2 specification.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ChangeEScoLinkParms(uint16_t sco_inx,
+ tBTM_CHG_ESCO_PARAMS* p_parms);
+
+/*******************************************************************************
+ *
+ * Function BTM_EScoConnRsp
+ *
+ * Description This function is called upon receipt of an (e)SCO connection
+ * request event (BTM_ESCO_CONN_REQ_EVT) to accept or reject
+ * the request. Parameters used to negotiate eSCO links.
+ * If p_parms is NULL, then values set through BTM_SetEScoMode
+ * are used.
+ * If the link type of the incoming request is SCO, then only
+ * the tx_bw, max_latency, content format, and packet_types are
+ * valid. The hci_status parameter should be
+ * ([0x0] to accept, [0x0d..0x0f] to reject)
+ *
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_EScoConnRsp(uint16_t sco_inx, uint8_t hci_status,
+ enh_esco_params_t* p_parms);
+
+/*******************************************************************************
+ *
+ * Function BTM_GetNumScoLinks
+ *
+ * Description This function returns the number of active SCO links.
+ *
+ * Returns uint8_t
+ *
+ ******************************************************************************/
+uint8_t BTM_GetNumScoLinks(void);
+
+/*****************************************************************************
+ * SECURITY MANAGEMENT FUNCTIONS
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function BTM_SecRegister
+ *
+ * Description Application manager calls this function to register for
+ * security services. There can be one and only one
+ * application saving link keys. BTM allows only first
+ * registration.
+ *
+ * Returns true if registered OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SecRegister(const tBTM_APPL_INFO* p_cb_info);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecRegisterLinkKeyNotificationCallback
+ *
+ * Description Profiles can register to be notified when a new Link Key
+ * is generated per connection.
+ *
+ * Returns true if registered OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SecRegisterLinkKeyNotificationCallback(
+ tBTM_LINK_KEY_CALLBACK* p_callback);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecAddRmtNameNotifyCallback
+ *
+ * Description Profiles can register to be notified when name of the
+ * remote device is resolved (up to
+ * BTM_SEC_MAX_RMT_NAME_CALLBACKS).
+ *
+ * Returns true if registered OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SecAddRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecDeleteRmtNameNotifyCallback
+ *
+ * Description A profile can deregister notification when a new Link Key
+ * is generated per connection.
+ *
+ * Returns true if OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SecDeleteRmtNameNotifyCallback(tBTM_RMT_NAME_CALLBACK* p_callback);
+
+/*******************************************************************************
+ *
+ * Function BTM_GetSecurityFlags
+ *
+ * Description Get security flags for the device
+ *
+ * Returns bool true or false is device found
+ *
+ ******************************************************************************/
+bool BTM_GetSecurityFlags(const RawAddress& bd_addr, uint8_t* p_sec_flags);
+
+/*******************************************************************************
+ *
+ * Function BTM_GetSecurityFlagsByTransport
+ *
+ * Description Get security flags for the device on a particular transport
+ *
+ * Parameters bd_addr: BD address of remote device
+ * p_sec_flags : Out parameter to be filled with security
+ * flags for the connection
+ * transport : Physical transport of the connection
+ * (BR/EDR or LE)
+ *
+ * Returns bool true or false is device found
+ *
+ ******************************************************************************/
+bool BTM_GetSecurityFlagsByTransport(const RawAddress& bd_addr,
+ uint8_t* p_sec_flags,
+ tBT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadTrustedMask
+ *
+ * Description Get trusted mask for the device
+ *
+ * Returns NULL, if the device record is not found.
+ * otherwise, the trusted mask
+ *
+ ******************************************************************************/
+uint32_t* BTM_ReadTrustedMask(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetPinType
+ *
+ * Description Set PIN type for the device.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_SetPinType(uint8_t pin_type, PIN_CODE pin_code, uint8_t pin_code_len);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetPairableMode
+ *
+ * Description Enable or disable pairing
+ *
+ * Parameters allow_pairing - (true or false) whether or not the device
+ * allows pairing.
+ * connect_only_paired - (true or false) whether or not to
+ * only allow paired devices to connect.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_SetPairableMode(bool allow_pairing, bool connect_only_paired);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetSecureConnectionsOnly
+ *
+ * Description Enable or disable default treatment for Mode 4 Level 0
+ * services
+ *
+ * Parameter secure_connections_only_mode - (true or false)
+ * true means that the device should treat Mode 4 Level 0
+ * services as services of other levels.
+ * false means that the device should provide default
+ * treatment for Mode 4 Level 0 services.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_SetSecureConnectionsOnly(bool secure_connections_only_mode);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetSecurityLevel
+ *
+ * Description Register service security level with Security Manager. Each
+ * service must register its requirements regardless of the
+ * security level that is used. This API is called once for
+ * originators and again for acceptors of connections.
+ *
+ * Returns true if registered OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SetSecurityLevel(bool is_originator, const char* p_name,
+ uint8_t service_id, uint16_t sec_level, uint16_t psm,
+ uint32_t mx_proto_id, uint32_t mx_chan_id);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetOutService
+ *
+ * Description This function is called to set the service for
+ * outgoing connection.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_SetOutService(const RawAddress& bd_addr, uint8_t service_id,
+ uint32_t mx_chan_id);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecClrService
+ *
+ * Description Removes specified service record(s) from the security
+ * database. All service records with the specified name are
+ * removed. Typically used only by devices with limited RAM
+ * so that it can reuse an old security service record.
+ *
+ * Returns Number of records that were freed.
+ *
+ ******************************************************************************/
+uint8_t BTM_SecClrService(uint8_t service_id);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecAddDevice
+ *
+ * Description Add/modify device. This function will be normally called
+ * during host startup to restore all required information
+ * stored in the NVRAM.
+ * dev_class, bd_name, link_key, and features are NULL if
+ * unknown
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SecAddDevice(const RawAddress& bd_addr, DEV_CLASS dev_class,
+ BD_NAME bd_name, uint8_t* features,
+ uint32_t trusted_mask[], LinkKey* link_key,
+ uint8_t key_type, tBTM_IO_CAP io_cap, uint8_t pin_length);
+
+/** Free resources associated with the device associated with |bd_addr| address.
+ *
+ * *** WARNING ***
+ * tBTM_SEC_DEV_REC associated with bd_addr becomes invalid after this function
+ * is called, also any of it's fields. i.e. if you use p_dev_rec->bd_addr, it is
+ * no longer valid!
+ * *** WARNING ***
+ *
+ * Returns true if removed OK, false if not found or ACL link is active.
+ */
+bool BTM_SecDeleteDevice(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecClearSecurityFlags
+ *
+ * Description Reset the security flags (mark as not-paired) for a given
+ * remove device.
+ *
+ ******************************************************************************/
+void BTM_SecClearSecurityFlags(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecGetDeviceLinkKey
+ *
+ * Description This function is called to obtain link key for the device
+ * it returns BTM_SUCCESS if link key is available, or
+ * BTM_UNKNOWN_ADDR if Security Manager does not know about
+ * the device or device record does not contain link key info
+ *
+ * Returns BTM_SUCCESS if successful, otherwise error code
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SecGetDeviceLinkKey(const RawAddress& bd_addr,
+ LinkKey* link_key);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecGetDeviceLinkKeyType
+ *
+ * Description This function is called to obtain link key type for the
+ * device.
+ * it returns BTM_SUCCESS if link key is available, or
+ * BTM_UNKNOWN_ADDR if Security Manager does not know about
+ * the device or device record does not contain link key info
+ *
+ * Returns BTM_LKEY_TYPE_IGNORE if link key is unknown, link type
+ * otherwise.
+ *
+ ******************************************************************************/
+tBTM_LINK_KEY_TYPE BTM_SecGetDeviceLinkKeyType(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_PINCodeReply
+ *
+ * Description This function is called after Security Manager submitted
+ * PIN code request to the UI.
+ *
+ * Parameters: bd_addr - Address of the device for which PIN was
+ * requested
+ * res - result of the operation BTM_SUCCESS if
+ * success
+ * pin_len - length in bytes of the PIN Code
+ * p_pin - pointer to array with the PIN Code
+ * trusted_mask - bitwise OR of trusted services
+ * (array of uint32_t)
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_PINCodeReply(const RawAddress& bd_addr, uint8_t res, uint8_t pin_len,
+ uint8_t* p_pin, uint32_t trusted_mask[]);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecBond
+ *
+ * Description This function is called to perform bonding with peer device.
+ *
+ * Parameters: bd_addr - Address of the device to bond
+ * pin_len - length in bytes of the PIN Code
+ * p_pin - pointer to array with the PIN Code
+ * trusted_mask - bitwise OR of trusted services
+ * (array of uint32_t)
+ * Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SecBond(const RawAddress& bd_addr, uint8_t pin_len,
+ uint8_t* p_pin, uint32_t trusted_mask[]);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecBondByTransport
+ *
+ * Description Perform bonding by designated transport
+ *
+ * Parameters: bd_addr - Address of the device to bond
+ * pin_len - length in bytes of the PIN Code
+ * p_pin - pointer to array with the PIN Code
+ * trusted_mask - bitwise OR of trusted services
+ * (array of uint32_t)
+ * transport : Physical transport to use for bonding
+ * (BR/EDR or LE)
+ *
+ * Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SecBondByTransport(const RawAddress& bd_addr,
+ tBT_TRANSPORT transport, uint8_t pin_len,
+ uint8_t* p_pin, uint32_t trusted_mask[]);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecBondCancel
+ *
+ * Description This function is called to cancel ongoing bonding process
+ * with peer device.
+ *
+ * Returns BTM_CMD_STARTED if successfully initiated, otherwise error
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SecBondCancel(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetEncryption
+ *
+ * Description This function is called to ensure that connection is
+ * encrypted. Should be called only on an open connection.
+ * Typically only needed for connections that first want to
+ * bring up unencrypted links, then later encrypt them.
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * transport - Link transport
+ * p_callback - Pointer to callback function called if
+ * this function returns PENDING after required
+ * procedures are completed. Can be set to
+ * NULL if status is not desired.
+ * p_ref_data - pointer to any data the caller wishes to
+ * receive in the callback function upon
+ * completion.
+ * can be set to NULL if not used.
+ * sec_act - LE security action, unused for BR/EDR
+ *
+ * Returns BTM_SUCCESS - already encrypted
+ * BTM_PENDING - command will be returned in the callback
+ * BTM_WRONG_MODE- connection not up.
+ * BTM_BUSY - security procedures are currently active
+ * BTM_MODE_UNSUPPORTED - if security manager not linked in.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetEncryption(const RawAddress& bd_addr,
+ tBT_TRANSPORT transport,
+ tBTM_SEC_CBACK* p_callback, void* p_ref_data,
+ tBTM_BLE_SEC_ACT sec_act);
+
+/*******************************************************************************
+ *
+ * Function BTM_ConfirmReqReply
+ *
+ * Description This function is called to confirm the numeric value for
+ * Simple Pairing in response to BTM_SP_CFM_REQ_EVT
+ *
+ * Parameters: res - result of the operation BTM_SUCCESS if
+ * success
+ * bd_addr - Address of the peer device
+ *
+ ******************************************************************************/
+void BTM_ConfirmReqReply(tBTM_STATUS res, const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_PasskeyReqReply
+ *
+ * Description This function is called to provide the passkey for
+ * Simple Pairing in response to BTM_SP_KEY_REQ_EVT
+ *
+ * Parameters: res - result of the operation BTM_SUCCESS if
+ * success
+ * bd_addr - Address of the peer device
+ * passkey - numeric value in the range of
+ * 0 - 999999(0xF423F).
+ *
+ ******************************************************************************/
+void BTM_PasskeyReqReply(tBTM_STATUS res, const RawAddress& bd_addr,
+ uint32_t passkey);
+
+/*******************************************************************************
+ *
+ * Function BTM_SendKeypressNotif
+ *
+ * Description This function is used during the passkey entry model
+ * by a device with KeyboardOnly IO capabilities
+ * (very likely to be a HID Device).
+ * It is called by a HID Device to inform the remote device
+ * when a key has been entered or erased.
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * type - notification type
+ *
+ ******************************************************************************/
+void BTM_SendKeypressNotif(const RawAddress& bd_addr, tBTM_SP_KEY_TYPE type);
+
+/*******************************************************************************
+ *
+ * Function BTM_IoCapRsp
+ *
+ * Description This function is called in response to BTM_SP_IO_REQ_EVT
+ * When the event data io_req.oob_data is set to
+ * BTM_OOB_UNKNOWN by the tBTM_SP_CALLBACK implementation, this
+ * function is called to provide the actual response
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * io_cap - The IO capability of local device.
+ * oob - BTM_OOB_NONE or BTM_OOB_PRESENT.
+ * auth_req- MITM protection required or not.
+ *
+ ******************************************************************************/
+void BTM_IoCapRsp(const RawAddress& bd_addr, tBTM_IO_CAP io_cap,
+ tBTM_OOB_DATA oob, tBTM_AUTH_REQ auth_req);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadLocalOobData
+ *
+ * Description This function is called to read the local OOB data from
+ * LM
+ *
+ ******************************************************************************/
+void BTM_ReadLocalOobData(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_RemoteOobDataReply
+ *
+ * Description This function is called to provide the remote OOB data for
+ * Simple Pairing in response to BTM_SP_RMT_OOB_EVT
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * c - simple pairing Hash C.
+ * r - simple pairing Randomizer C.
+ *
+ ******************************************************************************/
+void BTM_RemoteOobDataReply(tBTM_STATUS res, const RawAddress& bd_addr,
+ const Octet16& c, const Octet16& r);
+
+/*******************************************************************************
+ *
+ * Function BTM_BuildOobData
+ *
+ * Description This function is called to build the OOB data payload to
+ * be sent over OOB (non-Bluetooth) link
+ *
+ * Parameters: p_data - the location for OOB data
+ * max_len - p_data size.
+ * c - simple pairing Hash C.
+ * r - simple pairing Randomizer C.
+ * name_len- 0, local device name would not be included.
+ * otherwise, the local device name is included for
+ * up to this specified length
+ *
+ * Returns Number of bytes in p_data.
+ *
+ ******************************************************************************/
+uint16_t BTM_BuildOobData(uint8_t* p_data, uint16_t max_len, const Octet16& c,
+ const Octet16& r, uint8_t name_len);
+
+/*******************************************************************************
+ *
+ * Function BTM_BothEndsSupportSecureConnections
+ *
+ * Description This function is called to check if both the local device
+ * and the peer device specified by bd_addr support BR/EDR
+ * Secure Connections.
+ *
+ * Parameters: bd_addr - address of the peer
+ *
+ * Returns true if BR/EDR Secure Connections are supported by both
+ * local and the remote device.
+ * else false.
+ *
+ ******************************************************************************/
+bool BTM_BothEndsSupportSecureConnections(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_PeerSupportsSecureConnections
+ *
+ * Description This function is called to check if the peer supports
+ * BR/EDR Secure Connections.
+ *
+ * Parameters: bd_addr - address of the peer
+ *
+ * Returns true if BR/EDR Secure Connections are supported by the peer,
+ * else false.
+ *
+ ******************************************************************************/
+bool BTM_PeerSupportsSecureConnections(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadOobData
+ *
+ * Description This function is called to parse the OOB data payload
+ * received over OOB (non-Bluetooth) link
+ *
+ * Parameters: p_data - the location for OOB data
+ * eir_tag - The associated EIR tag to read the data.
+ * *p_len(output) - the length of the data with the given tag.
+ *
+ * Returns the beginning of the data with the given tag.
+ * NULL, if the tag is not found.
+ *
+ ******************************************************************************/
+uint8_t* BTM_ReadOobData(uint8_t* p_data, uint8_t eir_tag, uint8_t* p_len);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecReadDevName
+ *
+ * Description Looks for the device name in the security database for the
+ * specified BD address.
+ *
+ * Returns Pointer to the name or NULL
+ *
+ ******************************************************************************/
+char* BTM_SecReadDevName(const RawAddress& bd_addr);
+
+/*****************************************************************************
+ * POWER MANAGEMENT FUNCTIONS
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function BTM_PmRegister
+ *
+ * Description register or deregister with power manager
+ *
+ * Returns BTM_SUCCESS if successful,
+ * BTM_NO_RESOURCES if no room to hold registration
+ * BTM_ILLEGAL_VALUE
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_PmRegister(uint8_t mask, uint8_t* p_pm_id,
+ tBTM_PM_STATUS_CBACK* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetPowerMode
+ *
+ * Description store the mode in control block or
+ * alter ACL connection behavior.
+ *
+ * Returns BTM_SUCCESS if successful,
+ * BTM_UNKNOWN_ADDR if bd addr is not active or bad
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetPowerMode(uint8_t pm_id, const RawAddress& remote_bda,
+ const tBTM_PM_PWR_MD* p_mode);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadPowerMode
+ *
+ * Description This returns the current mode for a specific
+ * ACL connection.
+ *
+ * Input Param remote_bda - device address of desired ACL connection
+ *
+ * Output Param p_mode - address where the current mode is copied into.
+ * BTM_ACL_MODE_NORMAL
+ * BTM_ACL_MODE_HOLD
+ * BTM_ACL_MODE_SNIFF
+ * BTM_ACL_MODE_PARK
+ * (valid only if return code is BTM_SUCCESS)
+ *
+ * Returns BTM_SUCCESS if successful,
+ * BTM_UNKNOWN_ADDR if bd addr is not active or bad
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ReadPowerMode(const RawAddress& remote_bda,
+ tBTM_PM_MODE* p_mode);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetSsrParams
+ *
+ * Description This sends the given SSR parameters for the given ACL
+ * connection if it is in ACTIVE mode.
+ *
+ * Input Param remote_bda - device address of desired ACL connection
+ * max_lat - maximum latency (in 0.625ms)(0-0xFFFE)
+ * min_rmt_to - minimum remote timeout
+ * min_loc_to - minimum local timeout
+ *
+ *
+ * Returns BTM_SUCCESS if the HCI command is issued successful,
+ * BTM_UNKNOWN_ADDR if bd addr is not active or bad
+ * BTM_CMD_STORED if the command is stored
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetSsrParams(const RawAddress& remote_bda, uint16_t max_lat,
+ uint16_t min_rmt_to, uint16_t min_loc_to);
+
+/*******************************************************************************
+ *
+ * Function BTM_GetHCIConnHandle
+ *
+ * Description This function is called to get the handle for an ACL
+ * connection to a specific remote BD Address.
+ *
+ * Returns the handle of the connection, or 0xFFFF if none.
+ *
+ ******************************************************************************/
+uint16_t BTM_GetHCIConnHandle(const RawAddress& remote_bda,
+ tBT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function BTM_DeleteStoredLinkKey
+ *
+ * Description This function is called to delete link key for the specified
+ * device addresses from the NVRAM storage attached to the
+ * Bluetooth controller.
+ *
+ * Parameters: bd_addr - Addresses of the devices
+ * p_cb - Call back function to be called to return
+ * the results
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_DeleteStoredLinkKey(const RawAddress* bd_addr,
+ tBTM_CMPL_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_WriteEIR
+ *
+ * Description This function is called to write EIR data to controller.
+ *
+ * Parameters p_buff - allocated HCI command buffer including extended
+ * inquriry response
+ *
+ * Returns BTM_SUCCESS - if successful
+ * BTM_MODE_UNSUPPORTED - if local device cannot support it
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_WriteEIR(BT_HDR* p_buff);
+
+/*******************************************************************************
+ *
+ * Function BTM_HasEirService
+ *
+ * Description This function is called to know if UUID in bit map of UUID.
+ *
+ * Parameters p_eir_uuid - bit map of UUID list
+ * uuid16 - UUID 16-bit
+ *
+ * Returns true - if found
+ * false - if not found
+ *
+ ******************************************************************************/
+bool BTM_HasEirService(const uint32_t* p_eir_uuid, uint16_t uuid16);
+
+/*******************************************************************************
+ *
+ * Function BTM_HasInquiryEirService
+ *
+ * Description Return if a UUID is in the bit map of a UUID list.
+ *
+ * Parameters p_results - inquiry results
+ * uuid16 - UUID 16-bit
+ *
+ * Returns BTM_EIR_FOUND - if found
+ * BTM_EIR_NOT_FOUND - if not found and it is a complete list
+ * BTM_EIR_UNKNOWN - if not found and it is not complete list
+ *
+ ******************************************************************************/
+tBTM_EIR_SEARCH_RESULT BTM_HasInquiryEirService(tBTM_INQ_RESULTS* p_results,
+ uint16_t uuid16);
+
+/*******************************************************************************
+ *
+ * Function BTM_AddEirService
+ *
+ * Description This function is called to add a service in the bit map UUID
+ * list.
+ *
+ * Parameters p_eir_uuid - bit mask of UUID list for EIR
+ * uuid16 - UUID 16-bit
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTM_AddEirService(uint32_t* p_eir_uuid, uint16_t uuid16);
+
+/*******************************************************************************
+ *
+ * Function BTM_RemoveEirService
+ *
+ * Description This function is called to remove a service from the bit map
+ * UUID list.
+ *
+ * Parameters p_eir_uuid - bit mask of UUID list for EIR
+ * uuid16 - UUID 16-bit
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTM_RemoveEirService(uint32_t* p_eir_uuid, uint16_t uuid16);
+
+/*******************************************************************************
+ *
+ * Function BTM_GetEirSupportedServices
+ *
+ * Description This function is called to get UUID list from bit map UUID
+ * list.
+ *
+ * Parameters p_eir_uuid - bit mask of UUID list for EIR
+ * p - reference of current pointer of EIR
+ * max_num_uuid16 - max number of UUID can be written in EIR
+ * num_uuid16 - number of UUID have been written in EIR
+ *
+ * Returns BTM_EIR_MORE_16BITS_UUID_TYPE, if it has more than max
+ * BTM_EIR_COMPLETE_16BITS_UUID_TYPE, otherwise
+ *
+ ******************************************************************************/
+uint8_t BTM_GetEirSupportedServices(uint32_t* p_eir_uuid, uint8_t** p,
+ uint8_t max_num_uuid16,
+ uint8_t* p_num_uuid16);
+
+/*******************************************************************************
+ *
+ * Function BTM_GetEirUuidList
+ *
+ * Description This function parses EIR and returns UUID list.
+ *
+ * Parameters p_eir - EIR
+ * eirl_len - EIR len
+ * uuid_size - Uuid::kNumBytes16, Uuid::kNumBytes32,
+ * Uuid::kNumBytes128
+ * p_num_uuid - return number of UUID in found list
+ * p_uuid_list - return UUID 16-bit list
+ * max_num_uuid - maximum number of UUID to be returned
+ *
+ * Returns 0 - if not found
+ * BTM_EIR_COMPLETE_16BITS_UUID_TYPE
+ * BTM_EIR_MORE_16BITS_UUID_TYPE
+ * BTM_EIR_COMPLETE_32BITS_UUID_TYPE
+ * BTM_EIR_MORE_32BITS_UUID_TYPE
+ * BTM_EIR_COMPLETE_128BITS_UUID_TYPE
+ * BTM_EIR_MORE_128BITS_UUID_TYPE
+ *
+ ******************************************************************************/
+uint8_t BTM_GetEirUuidList(uint8_t* p_eir, size_t eir_len, uint8_t uuid_size,
+ uint8_t* p_num_uuid, uint8_t* p_uuid_list,
+ uint8_t max_num_uuid);
+
+/*****************************************************************************
+ * SCO OVER HCI
+ ****************************************************************************/
+/*******************************************************************************
+ *
+ * Function BTM_ConfigScoPath
+ *
+ * Description This function enable/disable SCO over HCI and registers SCO
+ * data callback if SCO over HCI is enabled.
+ *
+ * Parameter path: SCO or HCI
+ * p_sco_data_cb: callback function or SCO data if path is set
+ * to transport.
+ * p_pcm_param: pointer to the PCM interface parameter. If a
+ * NULL pointer is used, the PCM parameter
+ * maintained in the control block will be used;
+ * otherwise update the control block value.
+ * err_data_rpt: Lisbon feature to enable the erronous data
+ * report or not.
+ *
+ * Returns BTM_SUCCESS if the successful.
+ * BTM_NO_RESOURCES: no rsource to start the command.
+ * BTM_ILLEGAL_VALUE: invalid callback function pointer.
+ * BTM_CMD_STARTED : Command sent. Waiting for command
+ * complete event.
+ *
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_ConfigScoPath(esco_data_path_t path,
+ tBTM_SCO_DATA_CB* p_sco_data_cb,
+ tBTM_SCO_PCM_PARAM* p_pcm_param,
+ bool err_data_rpt);
+
+/*******************************************************************************
+ *
+ * Function BTM_WriteScoData
+ *
+ * Description This function write SCO data to a specified instance. The
+ * data to be written p_buf needs to carry an offset of
+ * HCI_SCO_PREAMBLE_SIZE bytes, and the data length can not
+ * exceed BTM_SCO_DATA_SIZE_MAX bytes, whose default value is
+ * set to 60 and is configurable. Data longer than the maximum
+ * bytes will be truncated.
+ *
+ * Returns BTM_SUCCESS: data write is successful
+ * BTM_ILLEGAL_VALUE: SCO data contains illegal offset value.
+ * BTM_SCO_BAD_LENGTH: SCO data length exceeds the max SCO
+ * packet size.
+ * BTM_NO_RESOURCES: no resources.
+ * BTM_UNKNOWN_ADDR: unknown SCO connection handle, or SCO is
+ * not routed via HCI.
+ *
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_WriteScoData(uint16_t sco_inx, BT_HDR* p_buf);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetARCMode
+ *
+ * Description Send Audio Routing Control command.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_SetARCMode(uint8_t iface, uint8_t arc_mode,
+ tBTM_VSC_CMPL_CB* p_arc_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_PCM2Setup_Write
+ *
+ * Description Send PCM2_Setup write command.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_PCM2Setup_Write(bool clk_master, tBTM_VSC_CMPL_CB* p_arc_cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_PM_ReadControllerState
+ *
+ * Description This function is called to obtain the controller state
+ *
+ * Returns Controller state (BTM_CONTRL_ACTIVE, BTM_CONTRL_SCAN, and
+ * BTM_CONTRL_IDLE)
+ *
+ ******************************************************************************/
+tBTM_CONTRL_STATE BTM_PM_ReadControllerState(void);
+
+/**
+ *
+ * BLE API
+ */
+/*******************************************************************************
+ *
+ * Function BTM_SecAddBleDevice
+ *
+ * Description Add/modify device. This function will be normally called
+ * during host startup to restore all required information
+ * for a LE device stored in the NVRAM.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * bd_name - Name of the peer device. NULL if unknown.
+ * dev_type - Remote device's device type.
+ * addr_type - LE device address type.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SecAddBleDevice(const RawAddress& bd_addr, BD_NAME bd_name,
+ tBT_DEVICE_TYPE dev_type, tBLE_ADDR_TYPE addr_type);
+
+/*******************************************************************************
+ *
+ * Function BTM_SecAddBleKey
+ *
+ * Description Add/modify LE device information. This function will be
+ * normally called during host startup to restore all required
+ * information stored in the NVRAM.
+ *
+ * Parameters: bd_addr - BD address of the peer
+ * p_le_key - LE key values.
+ * key_type - LE SMP key type.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+bool BTM_SecAddBleKey(const RawAddress& bd_addr, tBTM_LE_KEY_VALUE* p_le_key,
+ tBTM_LE_KEY_TYPE key_type);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleObtainVendorCapabilities
+ *
+ * Description This function is called to obatin vendor capabilties
+ *
+ * Parameters p_cmn_vsc_cb - Returns the vednor capabilities
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_BleObtainVendorCapabilities(tBTM_BLE_VSC_CB* p_cmn_vsc_cb);
+
+/**
+ * This function is called to set scan parameters. |cb| is called with operation
+ * status
+ **/
+void BTM_BleSetScanParams(uint32_t scan_interval, uint32_t scan_window,
+ tBLE_SCAN_MODE scan_type,
+ base::Callback<void(uint8_t)> cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleGetVendorCapabilities
+ *
+ * Description This function reads local LE features
+ *
+ * Parameters p_cmn_vsc_cb : Locala LE capability structure
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_BleGetVendorCapabilities(tBTM_BLE_VSC_CB* p_cmn_vsc_cb);
+/*******************************************************************************
+ *
+ * Function BTM_BleSetStorageConfig
+ *
+ * Description This function is called to setup storage configuration and
+ * setup callbacks.
+ *
+ * Parameters uint8_t batch_scan_full_max -Batch scan full maximum
+ uint8_t batch_scan_trunc_max - Batch scan truncated value
+ maximum
+ uint8_t batch_scan_notify_threshold - Threshold value
+ cb - Setup callback
+ tBTM_BLE_SCAN_THRESHOLD_CBACK *p_thres_cback -Threshold
+ callback
+ void *p_ref - Reference value
+ *
+ *
+ ******************************************************************************/
+void BTM_BleSetStorageConfig(uint8_t batch_scan_full_max,
+ uint8_t batch_scan_trunc_max,
+ uint8_t batch_scan_notify_threshold,
+ base::Callback<void(uint8_t /* status */)> cb,
+ tBTM_BLE_SCAN_THRESHOLD_CBACK* p_thres_cback,
+ tBTM_BLE_REF_VALUE ref_value);
+
+/* This function is called to enable batch scan */
+void BTM_BleEnableBatchScan(tBTM_BLE_BATCH_SCAN_MODE scan_mode,
+ uint32_t scan_interval, uint32_t scan_window,
+ tBTM_BLE_DISCARD_RULE discard_rule,
+ tBLE_ADDR_TYPE addr_type,
+ base::Callback<void(uint8_t /* status */)> cb);
+
+/* This function is called to disable batch scanning */
+void BTM_BleDisableBatchScan(base::Callback<void(uint8_t /* status */)> cb);
+
+/* This function is called to read batch scan reports */
+void BTM_BleReadScanReports(tBLE_SCAN_MODE scan_mode,
+ tBTM_BLE_SCAN_REP_CBACK cb);
+
+/* This function is called to setup the callback for tracking */
+void BTM_BleTrackAdvertiser(tBTM_BLE_TRACK_ADV_CBACK* p_track_cback,
+ tBTM_BLE_REF_VALUE ref_value);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleWriteScanRsp
+ *
+ * Description This function is called to write LE scan response.
+ *
+ * Parameters: p_scan_rsp: scan response.
+ *
+ * Returns status
+ *
+ ******************************************************************************/
+void BTM_BleWriteScanRsp(uint8_t* data, uint8_t length,
+ tBTM_BLE_ADV_DATA_CMPL_CBACK* p_adv_data_cback);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleObserve
+ *
+ * Description This procedure keep the device listening for advertising
+ * events from a broadcast device.
+ *
+ * Parameters start: start or stop observe.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_BleObserve(bool start, uint8_t duration,
+ tBTM_INQ_RESULTS_CB* p_results_cb,
+ tBTM_CMPL_CB* p_cmpl_cb);
+
+/** Returns local device encryption root (ER) */
+const Octet16& BTM_GetDeviceEncRoot();
+
+/** Returns local device identity root (IR) */
+const Octet16& BTM_GetDeviceIDRoot();
+
+/** Return local device DHK. */
+const Octet16& BTM_GetDeviceDHK();
+
+/*******************************************************************************
+ *
+ * Function BTM_SecurityGrant
+ *
+ * Description This function is called to grant security process.
+ *
+ * Parameters bd_addr - peer device bd address.
+ * res - result of the operation BTM_SUCCESS if success.
+ * Otherwise, BTM_REPEATED_ATTEMPTS is too many
+ * attempts.
+ *
+ * Returns None
+ *
+ ******************************************************************************/
+void BTM_SecurityGrant(const RawAddress& bd_addr, uint8_t res);
+
+/*******************************************************************************
+ *
+ * Function BTM_BlePasskeyReply
+ *
+ * Description This function is called after Security Manager submitted
+ * passkey request to the application.
+ *
+ * Parameters: bd_addr - Address of the device for which passkey was
+ * requested
+ * res - result of the operation SMP_SUCCESS if success
+ * passkey - numeric value in the range of
+ * BTM_MIN_PASSKEY_VAL(0) -
+ * BTM_MAX_PASSKEY_VAL(999999(0xF423F)).
+ *
+ ******************************************************************************/
+void BTM_BlePasskeyReply(const RawAddress& bd_addr, uint8_t res,
+ uint32_t passkey);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleConfirmReply
+ *
+ * Description This function is called after Security Manager submitted
+ * numeric comparison request to the application.
+ *
+ * Parameters: bd_addr - Address of the device with which numeric
+ * comparison was requested
+ * res - comparison result BTM_SUCCESS if success
+ *
+ ******************************************************************************/
+void BTM_BleConfirmReply(const RawAddress& bd_addr, uint8_t res);
+
+/*******************************************************************************
+ *
+ * Function BTM_LeOobDataReply
+ *
+ * Description This function is called to provide the OOB data for
+ * SMP in response to BTM_LE_OOB_REQ_EVT
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * res - result of the operation SMP_SUCCESS if success
+ * p_data - simple pairing Randomizer C.
+ *
+ ******************************************************************************/
+void BTM_BleOobDataReply(const RawAddress& bd_addr, uint8_t res, uint8_t len,
+ uint8_t* p_data);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleSecureConnectionOobDataReply
+ *
+ * Description This function is called to provide the OOB data for
+ * SMP in response to BTM_LE_OOB_REQ_EVT when secure connection
+ * data is available
+ *
+ * Parameters: bd_addr - Address of the peer device
+ * p_c - pointer to Confirmation
+ * p_r - pointer to Randomizer.
+ *
+ ******************************************************************************/
+void BTM_BleSecureConnectionOobDataReply(const RawAddress& bd_addr,
+ uint8_t* p_c, uint8_t* p_r);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleDataSignature
+ *
+ * Description This function is called to sign the data using AES128 CMAC
+ * algorith.
+ *
+ * Parameter bd_addr: target device the data to be signed for.
+ * p_text: singing data
+ * len: length of the signing data
+ * signature: output parameter where data signature is going to
+ * be stored.
+ *
+ * Returns true if signing sucessul, otherwise false.
+ *
+ ******************************************************************************/
+bool BTM_BleDataSignature(const RawAddress& bd_addr, uint8_t* p_text,
+ uint16_t len, BLE_SIGNATURE signature);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleVerifySignature
+ *
+ * Description This function is called to verify the data signature
+ *
+ * Parameter bd_addr: target device the data to be signed for.
+ * p_orig: original data before signature.
+ * len: length of the signing data
+ * counter: counter used when doing data signing
+ * p_comp: signature to be compared against.
+
+ * Returns true if signature verified correctly; otherwise false.
+ *
+ ******************************************************************************/
+bool BTM_BleVerifySignature(const RawAddress& bd_addr, uint8_t* p_orig,
+ uint16_t len, uint32_t counter, uint8_t* p_comp);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadConnectionAddr
+ *
+ * Description Read the local device random address.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_ReadConnectionAddr(const RawAddress& remote_bda,
+ RawAddress& local_conn_addr,
+ tBLE_ADDR_TYPE* p_addr_type);
+
+/*******************************************************************************
+ *
+ * Function BTM_IsBleConnection
+ *
+ * Description This function is called to check if the connection handle
+ * for an LE link
+ *
+ * Returns true if connection is LE link, otherwise false.
+ *
+ ******************************************************************************/
+bool BTM_IsBleConnection(uint16_t conn_handle);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadRemoteConnectionAddr
+ *
+ * Description Read the remote device address currently used.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool BTM_ReadRemoteConnectionAddr(const RawAddress& pseudo_addr,
+ RawAddress& conn_addr,
+ tBLE_ADDR_TYPE* p_addr_type);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleLoadLocalKeys
+ *
+ * Description Local local identity key, encryption root or sign counter.
+ *
+ * Parameters: key_type: type of key, can be BTM_BLE_KEY_TYPE_ID,
+ * BTM_BLE_KEY_TYPE_ER
+ * or BTM_BLE_KEY_TYPE_COUNTER.
+ * p_key: pointer to the key.
+ *
+ * Returns non2.
+ *
+ ******************************************************************************/
+void BTM_BleLoadLocalKeys(uint8_t key_type, tBTM_BLE_LOCAL_KEYS* p_key);
+
+/********************************************************
+ *
+ * Function BTM_BleSetPrefConnParams
+ *
+ * Description Set a peripheral's preferred connection parameters. When
+ * any of the value does not want to be updated while others
+ * do, use BTM_BLE_CONN_PARAM_UNDEF for the ones want to
+ * leave untouched.
+ *
+ * Parameters: bd_addr - BD address of the peripheral
+ * min_conn_int - minimum preferred connection interval
+ * max_conn_int - maximum preferred connection interval
+ * slave_latency - preferred slave latency
+ * supervision_tout - preferred supervision timeout
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_BleSetPrefConnParams(const RawAddress& bd_addr, uint16_t min_conn_int,
+ uint16_t max_conn_int, uint16_t slave_latency,
+ uint16_t supervision_tout);
+
+/******************************************************************************
+ *
+ * Function BTM_BleSetConnScanParams
+ *
+ * Description Set scan parameters used in BLE connection request
+ *
+ * Parameters: scan_interval - scan interval
+ * scan_window - scan window
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_BleSetConnScanParams(uint32_t scan_interval, uint32_t scan_window);
+
+/******************************************************************************
+ *
+ * Function BTM_BleReadControllerFeatures
+ *
+ * Description Reads BLE specific controller features
+ *
+ * Parameters: tBTM_BLE_CTRL_FEATURES_CBACK : Callback to notify when
+ * features are read
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_BleReadControllerFeatures(tBTM_BLE_CTRL_FEATURES_CBACK* p_vsc_cback);
+
+/*******************************************************************************
+ *
+ * Function BTM__BLEReadDiscoverability
+ *
+ * Description This function is called to read the current LE
+ * discoverability mode of the device.
+ *
+ * Returns BTM_BLE_NON_DISCOVERABLE ,BTM_BLE_LIMITED_DISCOVERABLE or
+ * BTM_BLE_GENRAL_DISCOVERABLE
+ *
+ ******************************************************************************/
+uint16_t BTM_BleReadDiscoverability();
+
+/*******************************************************************************
+ *
+ * Function BTM__BLEReadConnectability
+ *
+ * Description This function is called to read the current LE
+ * connectibility mode of the device.
+ *
+ * Returns BTM_BLE_NON_CONNECTABLE or BTM_BLE_CONNECTABLE
+ *
+ ******************************************************************************/
+uint16_t BTM_BleReadConnectability();
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadDevInfo
+ *
+ * Description This function is called to read the device/address type
+ * of BD address.
+ *
+ * Parameter remote_bda: remote device address
+ * p_dev_type: output parameter to read the device type.
+ * p_addr_type: output parameter to read the address type.
+ *
+ ******************************************************************************/
+void BTM_ReadDevInfo(const RawAddress& remote_bda, tBT_DEVICE_TYPE* p_dev_type,
+ tBLE_ADDR_TYPE* p_addr_type);
+
+/*******************************************************************************
+ *
+ * Function BTM_ReadConnectedTransportAddress
+ *
+ * Description This function is called to read the paired device/address
+ * type of other device paired corresponding to the BD_address
+ *
+ * Parameter remote_bda: remote device address, carry out the transport
+ * address
+ * transport: active transport
+ *
+ * Return true if an active link is identified; false otherwise
+ *
+ ******************************************************************************/
+bool BTM_ReadConnectedTransportAddress(RawAddress* remote_bda,
+ tBT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleConfigPrivacy
+ *
+ * Description This function is called to enable or disable the privacy in
+ * the local device.
+ *
+ * Parameters enable: true to enable it; false to disable it.
+ *
+ * Returns bool privacy mode set success; otherwise failed.
+ *
+ ******************************************************************************/
+bool BTM_BleConfigPrivacy(bool enable);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleLocalPrivacyEnabled
+ *
+ * Description Checks if local device supports private address
+ *
+ * Returns Return true if local privacy is enabled else false
+ *
+ ******************************************************************************/
+bool BTM_BleLocalPrivacyEnabled(void);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleEnableMixedPrivacyMode
+ *
+ * Description This function is called to enabled Mixed mode if privacy 1.2
+ * is applicable in controller.
+ *
+ * Parameters mixed_on: mixed mode to be used or not.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_BleEnableMixedPrivacyMode(bool mixed_on);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleMaxMultiAdvInstanceCount
+ *
+ * Description Returns the maximum number of multi adv instances supported
+ * by the controller.
+ *
+ * Returns Max multi adv instance count
+ *
+ ******************************************************************************/
+uint8_t BTM_BleMaxMultiAdvInstanceCount();
+
+/*******************************************************************************
+ *
+ * Function BTM_BleSetConnectableMode
+ *
+ * Description This function is called to set BLE connectable mode for a
+ * peripheral device.
+ *
+ * Parameters connectable_mode: directed connectable mode, or
+ * non-directed. It can be
+ * BTM_BLE_CONNECT_EVT,
+ * BTM_BLE_CONNECT_DIR_EVT or
+ * BTM_BLE_CONNECT_LO_DUTY_DIR_EVT
+ *
+ * Returns BTM_ILLEGAL_VALUE if controller does not support BLE.
+ * BTM_SUCCESS is status set successfully; otherwise failure.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_BleSetConnectableMode(tBTM_BLE_CONN_MODE connectable_mode);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleTurnOnPrivacyOnRemote
+ *
+ * Description This function is called to enable or disable the privacy on
+ * the remote device.
+ *
+ * Parameters bd_addr: remote device address.
+ * privacy_on: true to enable it; false to disable it.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void BTM_BleTurnOnPrivacyOnRemote(const RawAddress& bd_addr, bool privacy_on);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleUpdateAdvFilterPolicy
+ *
+ * Description This function update the filter policy of advertiser.
+ *
+ * Parameter adv_policy: advertising filter policy
+ *
+ * Return void
+ ******************************************************************************/
+void BTM_BleUpdateAdvFilterPolicy(tBTM_BLE_AFP adv_policy);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleReceiverTest
+ *
+ * Description This function is called to start the LE Receiver test
+ *
+ * Parameter rx_freq - Frequency Range
+ * p_cmd_cmpl_cback - Command Complete callback
+ *
+ ******************************************************************************/
+void BTM_BleReceiverTest(uint8_t rx_freq, tBTM_CMPL_CB* p_cmd_cmpl_cback);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleTransmitterTest
+ *
+ * Description This function is called to start the LE Transmitter test
+ *
+ * Parameter tx_freq - Frequency Range
+ * test_data_len - Length in bytes of payload data in each
+ * packet
+ * packet_payload - Pattern to use in the payload
+ * p_cmd_cmpl_cback - Command Complete callback
+ *
+ ******************************************************************************/
+void BTM_BleTransmitterTest(uint8_t tx_freq, uint8_t test_data_len,
+ uint8_t packet_payload,
+ tBTM_CMPL_CB* p_cmd_cmpl_cback);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleTestEnd
+ *
+ * Description This function is called to stop the in-progress TX or RX test
+ *
+ * Parameter p_cmd_cmpl_cback - Command complete callback
+ *
+ ******************************************************************************/
+void BTM_BleTestEnd(tBTM_CMPL_CB* p_cmd_cmpl_cback);
+
+/*******************************************************************************
+ *
+ * Function BTM_UseLeLink
+ *
+ * Description Select the underlying physical link to use.
+ *
+ * Returns true to use LE, false use BR/EDR.
+ *
+ ******************************************************************************/
+bool BTM_UseLeLink(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleStackEnable
+ *
+ * Description Enable/Disable BLE functionality on stack regardless of
+ * controller capability.
+ *
+ * Parameters: enable: true to enable, false to disable.
+ *
+ * Returns true if added OK, else false
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_BleStackEnable(bool enable);
+
+/*******************************************************************************
+ *
+ * Function BTM_GetLeSecurityState
+ *
+ * Description This function is called to get security mode 1 flags and
+ * encryption key size for LE peer.
+ *
+ * Returns bool true if LE device is found, false otherwise.
+ *
+ ******************************************************************************/
+bool BTM_GetLeSecurityState(const RawAddress& bd_addr,
+ uint8_t* p_le_dev_sec_flags,
+ uint8_t* p_le_key_size);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleSecurityProcedureIsRunning
+ *
+ * Description This function indicates if LE security procedure is
+ * currently running with the peer.
+ *
+ * Returns bool true if security procedure is running, false otherwise.
+ *
+ ******************************************************************************/
+bool BTM_BleSecurityProcedureIsRunning(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleGetSupportedKeySize
+ *
+ * Description This function gets the maximum encryption key size in bytes
+ * the local device can suport.
+ * record.
+ *
+ * Returns the key size or 0 if the size can't be retrieved.
+ *
+ ******************************************************************************/
+uint8_t BTM_BleGetSupportedKeySize(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleAdvFilterParamSetup
+ *
+ * Description This function is called to setup the adv data payload filter
+ * condition.
+ *
+ ******************************************************************************/
+void BTM_BleAdvFilterParamSetup(
+ int action, tBTM_BLE_PF_FILT_INDEX filt_index,
+ std::unique_ptr<btgatt_filt_param_setup_t> p_filt_params,
+ tBTM_BLE_PF_PARAM_CB cb);
+
+/**
+ * This functions are called to configure the adv data payload filter condition
+ */
+void BTM_LE_PF_set(tBTM_BLE_PF_FILT_INDEX filt_index,
+ std::vector<ApcfCommand> commands, tBTM_BLE_PF_CFG_CBACK cb);
+void BTM_LE_PF_clear(tBTM_BLE_PF_FILT_INDEX filt_index,
+ tBTM_BLE_PF_CFG_CBACK cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleEnableDisableFilterFeature
+ *
+ * Description Enable or disable the APCF feature
+ *
+ * Parameters enable - true - enables APCF, false - disables APCF
+ *
+ ******************************************************************************/
+void BTM_BleEnableDisableFilterFeature(uint8_t enable,
+ tBTM_BLE_PF_STATUS_CBACK p_stat_cback);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleGetEnergyInfo
+ *
+ * Description This function obtains the energy info
+ *
+ * Parameters p_ener_cback - Callback pointer
+ *
+ * Returns status
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_BleGetEnergyInfo(tBTM_BLE_ENERGY_INFO_CBACK* p_ener_cback);
+
+/*******************************************************************************
+ *
+ * Function BTM_SetBleDataLength
+ *
+ * Description Set the maximum BLE transmission packet size
+ *
+ * Returns BTM_SUCCESS if success; otherwise failed.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_SetBleDataLength(const RawAddress& bd_addr,
+ uint16_t tx_pdu_length);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleReadPhy
+ *
+ * Description To read the current PHYs for specified LE connection
+ *
+ *
+ * Returns BTM_SUCCESS if success; otherwise failed.
+ *
+ ******************************************************************************/
+void BTM_BleReadPhy(
+ const RawAddress& bd_addr,
+ base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleSetDefaultPhy
+ *
+ * Description To set preferred PHY for ensuing LE connections
+ *
+ *
+ * Returns BTM_SUCCESS if success; otherwise failed.
+ *
+ ******************************************************************************/
+tBTM_STATUS BTM_BleSetDefaultPhy(uint8_t all_phys, uint8_t tx_phys,
+ uint8_t rx_phys);
+
+/*******************************************************************************
+ *
+ * Function BTM_BleSetPhy
+ *
+ * Description To set PHY preferences for specified LE connection
+ *
+ *
+ * Returns BTM_SUCCESS if success; otherwise failed.
+ *
+ ******************************************************************************/
+void BTM_BleSetPhy(const RawAddress& bd_addr, uint8_t tx_phys, uint8_t rx_phys,
+ uint16_t phy_options);
+
+void BTM_LE_PF_local_name(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index,
+ std::vector<uint8_t> name, tBTM_BLE_PF_CFG_CBACK cb);
+
+void BTM_LE_PF_srvc_data(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index);
+
+void BTM_LE_PF_manu_data(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index, uint16_t company_id,
+ uint16_t company_id_mask, std::vector<uint8_t> data,
+ std::vector<uint8_t> data_mask,
+ tBTM_BLE_PF_CFG_CBACK cb);
+
+void BTM_LE_PF_srvc_data_pattern(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index,
+ std::vector<uint8_t> data,
+ std::vector<uint8_t> data_mask,
+ tBTM_BLE_PF_CFG_CBACK cb);
+
+void BTM_LE_PF_addr_filter(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index, tBLE_BD_ADDR addr,
+ tBTM_BLE_PF_CFG_CBACK cb);
+
+void BTM_LE_PF_uuid_filter(tBTM_BLE_SCAN_COND_OP action,
+ tBTM_BLE_PF_FILT_INDEX filt_index,
+ tBTM_BLE_PF_COND_TYPE filter_type,
+ const bluetooth::Uuid& uuid,
+ tBTM_BLE_PF_LOGIC_TYPE cond_logic,
+ const bluetooth::Uuid& uuid_mask,
+ tBTM_BLE_PF_CFG_CBACK cb);
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/main/shim/controller.cc b/main/shim/controller.cc
new file mode 100644
index 0000000..284d360
--- /dev/null
+++ b/main/shim/controller.cc
@@ -0,0 +1,341 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#define LOG_TAG "bt_shim_controller"
+
+#include "main/shim/controller.h"
+#include "btcore/include/module.h"
+#include "main/shim/entry.h"
+#include "main/shim/shim.h"
+#include "osi/include/future.h"
+#include "osi/include/log.h"
+
+using ::bluetooth::shim::GetController;
+
+constexpr uint8_t kPageZero = 0;
+constexpr uint8_t kPageOne = 1;
+constexpr uint8_t kPageTwo = 2;
+constexpr uint8_t kMaxFeaturePage = 3;
+
+constexpr int kMaxSupportedCodecs = 8; // MAX_LOCAL_SUPPORTED_CODECS_SIZE
+
+constexpr uint8_t kPhyLe1M = 0x01;
+
+/**
+ * Interesting commands supported by controller
+ */
+constexpr int kReadRemoteExtendedFeatures = 0x41c;
+constexpr int kEnhancedSetupSynchronousConnection = 0x428;
+constexpr int kEnhancedAcceptSynchronousConnection = 0x429;
+constexpr int kLeSetPrivacyMode = 0x204e;
+
+constexpr int kHciDataPreambleSize = 4; // #define HCI_DATA_PREAMBLE_SIZE 4
+
+// Module lifecycle functions
+static future_t* start_up(void);
+static future_t* shut_down(void);
+
+EXPORT_SYMBOL extern const module_t gd_controller_module = {
+ .name = GD_CONTROLLER_MODULE,
+ .init = nullptr,
+ .start_up = start_up,
+ .shut_down = shut_down,
+ .clean_up = nullptr,
+ .dependencies = {GD_SHIM_MODULE, nullptr}};
+
+struct {
+ bool ready;
+ uint64_t feature[kMaxFeaturePage];
+ uint64_t le_feature[kMaxFeaturePage];
+ RawAddress raw_address;
+ bt_version_t bt_version;
+ uint8_t local_supported_codecs[kMaxSupportedCodecs];
+ uint8_t number_of_local_supported_codecs;
+ uint64_t le_supported_states;
+ uint8_t phy;
+} data_;
+
+static future_t* start_up(void) {
+ LOG_INFO(LOG_TAG, "%s Starting up", __func__);
+ data_.ready = true;
+
+ std::string string_address = GetController()->GetControllerMacAddress();
+ RawAddress::FromString(string_address, data_.raw_address);
+
+ data_.le_supported_states =
+ bluetooth::shim::GetController()->GetControllerLeSupportedStates();
+
+ LOG_INFO(LOG_TAG, "Mac address:%s", string_address.c_str());
+
+ data_.phy = kPhyLe1M;
+
+ return future_new_immediate(FUTURE_SUCCESS);
+}
+
+static future_t* shut_down(void) {
+ data_.ready = false;
+ return future_new_immediate(FUTURE_SUCCESS);
+}
+
+/**
+ * Module methods
+ */
+#define BIT(x) (0x1ULL << (x))
+
+static bool get_is_ready(void) { return data_.ready; }
+
+static const RawAddress* get_address(void) { return &data_.raw_address; }
+
+static const bt_version_t* get_bt_version(void) { return &data_.bt_version; }
+
+static const bt_device_features_t* get_features_classic(int index) {
+ CHECK(index >= 0 && index < kMaxFeaturePage);
+ data_.feature[index] =
+ bluetooth::shim::GetController()->GetControllerLocalExtendedFeatures(
+ index);
+ return (const bt_device_features_t*)&data_.feature[index];
+}
+
+static uint8_t get_last_features_classic_index(void) {
+ return bluetooth::shim::GetController()
+ ->GetControllerLocalExtendedFeaturesMaxPageNumber();
+}
+
+static uint8_t* get_local_supported_codecs(uint8_t* number_of_codecs) {
+ CHECK(number_of_codecs != nullptr);
+ if (data_.number_of_local_supported_codecs != 0) {
+ *number_of_codecs = data_.number_of_local_supported_codecs;
+ return data_.local_supported_codecs;
+ }
+ return (uint8_t*)nullptr;
+}
+
+static const bt_device_features_t* get_features_ble(void) {
+ return (const bt_device_features_t*)&data_.le_feature[0];
+}
+
+static const uint8_t* get_ble_supported_states(void) {
+ return (const uint8_t*)&data_.le_supported_states;
+}
+
+static bool supports_simple_pairing(void) {
+ return GetController()->GetControllerLocalExtendedFeatures(kPageOne) &
+ BIT(51);
+}
+
+static bool supports_secure_connections(void) {
+ return GetController()->GetControllerLocalExtendedFeatures(kPageTwo) & BIT(8);
+}
+
+static bool supports_simultaneous_le_bredr(void) {
+ return GetController()->GetControllerLocalExtendedFeatures(kPageZero) &
+ BIT(49);
+}
+
+static bool supports_reading_remote_extended_features(void) {
+ return GetController()->IsCommandSupported(kReadRemoteExtendedFeatures);
+}
+
+static bool supports_interlaced_inquiry_scan(void) {
+ return GetController()->GetControllerLocalExtendedFeatures(kPageZero) &
+ BIT(28);
+}
+
+static bool supports_rssi_with_inquiry_results(void) {
+ return GetController()->GetControllerLocalExtendedFeatures(kPageZero) &
+ BIT(28);
+}
+
+static bool supports_extended_inquiry_response(void) {
+ return GetController()->GetControllerLocalExtendedFeatures(kPageZero) &
+ BIT(48);
+}
+
+static bool supports_master_slave_role_switch(void) {
+ return GetController()->GetControllerLocalExtendedFeatures(kPageZero) &
+ BIT(5);
+}
+
+static bool supports_enhanced_setup_synchronous_connection(void) {
+ return GetController()->IsCommandSupported(
+ kEnhancedSetupSynchronousConnection);
+}
+
+static bool supports_enhanced_accept_synchronous_connection(void) {
+ return GetController()->IsCommandSupported(
+ kEnhancedAcceptSynchronousConnection);
+}
+
+static bool supports_ble(void) {
+ return GetController()->GetControllerLocalExtendedFeatures(kPageOne) & BIT(1);
+}
+
+static bool supports_ble_privacy(void) {
+ return GetController()->GetControllerLeLocalSupportedFeatures() & BIT(6);
+}
+
+static bool supports_ble_set_privacy_mode() {
+ return GetController()->IsCommandSupported(kLeSetPrivacyMode);
+}
+
+static bool supports_ble_packet_extension(void) {
+ return GetController()->GetControllerLeLocalSupportedFeatures() & BIT(5);
+}
+
+static bool supports_ble_connection_parameters_request(void) {
+ return GetController()->GetControllerLeLocalSupportedFeatures() & BIT(2);
+}
+
+static bool supports_ble_2m_phy(void) {
+ return GetController()->GetControllerLeLocalSupportedFeatures() & BIT(8);
+}
+
+static bool supports_ble_coded_phy(void) {
+ return GetController()->GetControllerLeLocalSupportedFeatures() & BIT(11);
+}
+
+static bool supports_ble_extended_advertising(void) {
+ return GetController()->GetControllerLeLocalSupportedFeatures() & BIT(12);
+}
+
+static bool supports_ble_periodic_advertising(void) {
+ return GetController()->GetControllerLeLocalSupportedFeatures() & BIT(13);
+}
+
+static uint16_t get_acl_data_size_classic(void) {
+ return GetController()->GetControllerAclPacketLength();
+}
+
+static uint16_t get_acl_data_size_ble(void) {
+ ::bluetooth::shim::LeBufferSize le_buffer_size =
+ GetController()->GetControllerLeBufferSize();
+ return le_buffer_size.le_data_packet_length;
+}
+
+static uint16_t get_acl_packet_size_classic(void) {
+ return get_acl_data_size_classic() + kHciDataPreambleSize;
+}
+
+static uint16_t get_acl_packet_size_ble(void) {
+ return get_acl_data_size_ble() + kHciDataPreambleSize;
+}
+
+static uint16_t get_ble_suggested_default_data_length(void) {
+ LOG_WARN(LOG_TAG, "%s TODO Unimplemented", __func__);
+ return 0;
+}
+
+static uint16_t get_ble_maximum_tx_data_length(void) {
+ ::bluetooth::shim::LeMaximumDataLength le_maximum_data_length =
+ GetController()->GetControllerLeMaximumDataLength();
+ return le_maximum_data_length.supported_max_tx_octets;
+}
+
+static uint16_t get_ble_maxium_advertising_data_length(void) {
+ LOG_WARN(LOG_TAG, "%s TODO Unimplemented", __func__);
+ return 0;
+}
+
+static uint8_t get_ble_number_of_supported_advertising_sets(void) {
+ LOG_WARN(LOG_TAG, "%s TODO Unimplemented", __func__);
+ return 0;
+}
+
+static uint16_t get_acl_buffer_count_classic(void) {
+ return GetController()->GetControllerNumAclPacketBuffers();
+}
+
+static uint8_t get_acl_buffer_count_ble(void) {
+ LOG_WARN(LOG_TAG, "%s TODO Unimplemented", __func__);
+ return 0;
+}
+
+static uint8_t get_ble_white_list_size(void) {
+ LOG_WARN(LOG_TAG, "%s TODO Unimplemented", __func__);
+ return 0;
+}
+
+static uint8_t get_ble_resolving_list_max_size(void) {
+ LOG_WARN(LOG_TAG, "%s TODO Unimplemented", __func__);
+ return 0;
+}
+
+static void set_ble_resolving_list_max_size(int resolving_list_max_size) {
+ LOG_WARN(LOG_TAG, "%s TODO Unimplemented", __func__);
+}
+
+static uint8_t get_le_all_initiating_phys() { return data_.phy; }
+
+static const controller_t interface = {
+ get_is_ready,
+
+ get_address,
+ get_bt_version,
+
+ get_features_classic,
+ get_last_features_classic_index,
+
+ get_features_ble,
+ get_ble_supported_states,
+
+ supports_simple_pairing,
+ supports_secure_connections,
+ supports_simultaneous_le_bredr,
+ supports_reading_remote_extended_features,
+ supports_interlaced_inquiry_scan,
+ supports_rssi_with_inquiry_results,
+ supports_extended_inquiry_response,
+ supports_master_slave_role_switch,
+ supports_enhanced_setup_synchronous_connection,
+ supports_enhanced_accept_synchronous_connection,
+
+ supports_ble,
+ supports_ble_packet_extension,
+ supports_ble_connection_parameters_request,
+ supports_ble_privacy,
+ supports_ble_set_privacy_mode,
+ supports_ble_2m_phy,
+ supports_ble_coded_phy,
+ supports_ble_extended_advertising,
+ supports_ble_periodic_advertising,
+
+ get_acl_data_size_classic,
+ get_acl_data_size_ble,
+
+ get_acl_packet_size_classic,
+ get_acl_packet_size_ble,
+ get_ble_suggested_default_data_length,
+ get_ble_maximum_tx_data_length,
+ get_ble_maxium_advertising_data_length,
+ get_ble_number_of_supported_advertising_sets,
+
+ get_acl_buffer_count_classic,
+ get_acl_buffer_count_ble,
+
+ get_ble_white_list_size,
+
+ get_ble_resolving_list_max_size,
+ set_ble_resolving_list_max_size,
+ get_local_supported_codecs,
+ get_le_all_initiating_phys};
+
+const controller_t* bluetooth::shim::controller_get_interface() {
+ static bool loaded = false;
+ if (!loaded) {
+ loaded = true;
+ }
+ return &interface;
+}
diff --git a/main/shim/controller.h b/main/shim/controller.h
new file mode 100644
index 0000000..6b77982
--- /dev/null
+++ b/main/shim/controller.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include "device/include/controller.h"
+
+static const char GD_CONTROLLER_MODULE[] = "gd_controller_module";
+
+namespace bluetooth {
+namespace shim {
+
+const controller_t* controller_get_interface();
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/main/shim/entry.cc b/main/shim/entry.cc
new file mode 100644
index 0000000..4655219
--- /dev/null
+++ b/main/shim/entry.cc
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2019 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 "main/shim/entry.h"
+#include "gd/shim/only_include_this_file_into_legacy_stack___ever.h"
+#include "osi/include/future.h"
+
+using bluetooth::shim::GetGabeldorscheStack;
+
+future_t* bluetooth::shim::StartGabeldorscheStack() {
+ GetGabeldorscheStack()->Start();
+ return (future_t*)nullptr;
+}
+
+future_t* bluetooth::shim::StopGabeldorscheStack() {
+ GetGabeldorscheStack()->Stop();
+ return (future_t*)nullptr;
+}
+
+bluetooth::shim::IController* bluetooth::shim::GetController() {
+ return GetGabeldorscheStack()->GetController();
+}
+
+bluetooth::shim::IConnectability* bluetooth::shim::GetConnectability() {
+ return GetGabeldorscheStack()->GetConnectability();
+}
+
+bluetooth::shim::IDiscoverability* bluetooth::shim::GetDiscoverability() {
+ return GetGabeldorscheStack()->GetDiscoverability();
+}
+
+bluetooth::shim::IInquiry* bluetooth::shim::GetInquiry() {
+ return GetGabeldorscheStack()->GetInquiry();
+}
+
+bluetooth::shim::IHciLayer* bluetooth::shim::GetHciLayer() {
+ return GetGabeldorscheStack()->GetHciLayer();
+}
+
+bluetooth::shim::IL2cap* bluetooth::shim::GetL2cap() {
+ return GetGabeldorscheStack()->GetL2cap();
+}
+
+bluetooth::shim::IName* bluetooth::shim::GetName() {
+ return GetGabeldorscheStack()->GetName();
+}
+
+bluetooth::shim::IPage* bluetooth::shim::GetPage() {
+ return GetGabeldorscheStack()->GetPage();
+}
diff --git a/main/shim/entry.h b/main/shim/entry.h
new file mode 100644
index 0000000..2ffd2e5
--- /dev/null
+++ b/main/shim/entry.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+/**
+ * Entrypoints called into Gabeldorsche from legacy stack
+ *
+ * Any marshalling/unmarshalling, data transformation of APIs to
+ * or from the Gabeldorsche stack may be placed here.
+ *
+ * The idea is to effectively provide a binary interface to prevent cross
+ * contamination of data structures and the like between the stacks.
+ *
+ * **ABSOLUTELY** No reference to Gabeldorsche stack other than well defined
+ * interfaces may be made here
+ */
+
+#include "gd/shim/only_include_this_file_into_legacy_stack___ever.h"
+#include "osi/include/future.h"
+
+namespace bluetooth {
+namespace shim {
+
+future_t* StartGabeldorscheStack();
+future_t* StopGabeldorscheStack();
+
+bluetooth::shim::IController* GetController();
+bluetooth::shim::IDiscoverability* GetDiscoverability();
+bluetooth::shim::IConnectability* GetConnectability();
+bluetooth::shim::IInquiry* GetInquiry();
+bluetooth::shim::IHciLayer* GetHciLayer();
+bluetooth::shim::IL2cap* GetL2cap();
+bluetooth::shim::IName* GetName();
+bluetooth::shim::IPage* GetPage();
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/main/shim/entry_for_test.cc b/main/shim/entry_for_test.cc
new file mode 100644
index 0000000..26b9b22
--- /dev/null
+++ b/main/shim/entry_for_test.cc
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2019 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 "gd/shim/only_include_this_file_into_legacy_stack___ever.h"
+#include "main/shim/entry.h"
+
+/**
+ * Entrypoints for stubbed bluetooth test library
+ *
+ * Gd stack is not supported using legacy test modes
+ */
+bluetooth::shim::IStack* bluetooth::shim::GetGabeldorscheStack() {
+ return (bluetooth::shim::IStack*)nullptr;
+}
diff --git a/main/shim/hci_layer.cc b/main/shim/hci_layer.cc
new file mode 100644
index 0000000..ba21cae
--- /dev/null
+++ b/main/shim/hci_layer.cc
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#define LOG_TAG "bt_shim_hci"
+
+#include <base/bind.h>
+#include <frameworks/base/core/proto/android/bluetooth/hci/enums.pb.h>
+#include <algorithm>
+#include <cstdint>
+
+#include "btcore/include/module.h"
+#include "main/shim/hci_layer.h"
+#include "main/shim/shim.h"
+#include "osi/include/allocator.h"
+#include "osi/include/future.h"
+#include "stack/include/bt_types.h"
+
+/**
+ * Callback data wrapped as opaque token bundled with the command
+ * transmit request to the Gd layer.
+ *
+ * Upon completion a token for a corresponding command transmit.
+ * request is returned from the Gd layer.
+ */
+using CommandCallbackData = struct {
+ void* context;
+ command_complete_cb complete_callback;
+ command_status_cb status_callback;
+};
+
+constexpr size_t kBtHdrSize = sizeof(BT_HDR);
+constexpr size_t kCommandLengthSize = sizeof(uint8_t);
+constexpr size_t kCommandOpcodeSize = sizeof(uint16_t);
+
+static hci_t interface;
+static base::Callback<void(const base::Location&, BT_HDR*)> send_data_upwards;
+
+static future_t* hci_module_shut_down(void);
+static future_t* hci_module_start_up(void);
+
+static void OnCommandComplete(uint16_t command_op_code,
+ std::vector<const uint8_t> data,
+ const void* token) {
+ BT_HDR* response = static_cast<BT_HDR*>(osi_calloc(data.size() + kBtHdrSize));
+ std::copy(data.begin(), data.end(), response->data);
+ response->len = data.size();
+
+ const CommandCallbackData* command_callback_data =
+ static_cast<const CommandCallbackData*>(token);
+ CHECK(command_callback_data->complete_callback != nullptr);
+
+ command_callback_data->complete_callback(response,
+ command_callback_data->context);
+ delete command_callback_data;
+}
+
+static void OnCommandStatus(uint16_t command_op_code,
+ std::vector<const uint8_t> data, const void* token,
+ uint8_t status) {
+ BT_HDR* response = static_cast<BT_HDR*>(osi_calloc(data.size() + kBtHdrSize));
+ std::copy(data.begin(), data.end(), response->data);
+ response->len = data.size();
+
+ const CommandCallbackData* command_callback_data =
+ static_cast<const CommandCallbackData*>(token);
+ CHECK(command_callback_data->status_callback != nullptr);
+
+ command_callback_data->status_callback(status, response,
+ command_callback_data->context);
+ delete command_callback_data;
+}
+
+EXPORT_SYMBOL extern const module_t gd_hci_module = {
+ .name = GD_HCI_MODULE,
+ .init = nullptr,
+ .start_up = hci_module_start_up,
+ .shut_down = hci_module_shut_down,
+ .clean_up = nullptr,
+ .dependencies = {GD_SHIM_MODULE, nullptr}};
+
+static future_t* hci_module_start_up(void) {
+ bluetooth::shim::GetHciLayer()->RegisterCommandComplete(OnCommandComplete);
+ bluetooth::shim::GetHciLayer()->RegisterCommandStatus(OnCommandStatus);
+ return nullptr;
+}
+
+static future_t* hci_module_shut_down(void) {
+ bluetooth::shim::GetHciLayer()->UnregisterCommandComplete();
+ bluetooth::shim::GetHciLayer()->UnregisterCommandStatus();
+ return nullptr;
+}
+
+static void set_data_cb(
+ base::Callback<void(const base::Location&, BT_HDR*)> send_data_cb) {
+ send_data_upwards = std::move(send_data_cb);
+}
+
+static void transmit_command(BT_HDR* command,
+ command_complete_cb complete_callback,
+ command_status_cb status_callback, void* context) {
+ CHECK(command != nullptr);
+ uint8_t* data = command->data + command->offset;
+ size_t len = command->len;
+ CHECK(len >= (kCommandOpcodeSize + kCommandLengthSize));
+
+ // little endian command opcode
+ uint16_t command_op_code = (data[1] << 8 | data[0]);
+ // Gd stack API requires opcode specification and calculates length, so
+ // no need to provide opcode or length here.
+ data += (kCommandOpcodeSize + kCommandLengthSize);
+ len -= (kCommandOpcodeSize + kCommandLengthSize);
+
+ const CommandCallbackData* command_callback_data = new CommandCallbackData{
+ context,
+ complete_callback,
+ status_callback,
+ };
+ bluetooth::shim::GetHciLayer()->TransmitCommand(
+ command_op_code, const_cast<const uint8_t*>(data), len,
+ static_cast<const void*>(command_callback_data));
+}
+
+const hci_t* bluetooth::shim::hci_layer_get_interface() {
+ static bool loaded = false;
+ if (!loaded) {
+ loaded = true;
+ interface.set_data_cb = set_data_cb;
+ interface.transmit_command = transmit_command;
+ interface.transmit_command_futured = nullptr;
+ interface.transmit_downward = nullptr;
+ }
+ return &interface;
+}
diff --git a/main/shim/hci_layer.h b/main/shim/hci_layer.h
new file mode 100644
index 0000000..6b0bbcc
--- /dev/null
+++ b/main/shim/hci_layer.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2019 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.
+ */
+
+/**
+ * Gd shim layer to legacy hci layer stack
+ */
+#pragma once
+
+#include "hci/include/hci_layer.h"
+
+static const char GD_HCI_MODULE[] = "gd_hci_module";
+
+namespace bluetooth {
+namespace shim {
+
+const hci_t* hci_layer_get_interface();
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/main/shim/l2c_api.cc b/main/shim/l2c_api.cc
new file mode 100644
index 0000000..ccfb879
--- /dev/null
+++ b/main/shim/l2c_api.cc
@@ -0,0 +1,423 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#define LOG_TAG "bt_shim_l2cap"
+
+#include "main/shim/l2c_api.h"
+#include "main/shim/l2cap.h"
+#include "main/shim/shim.h"
+#include "osi/include/log.h"
+
+static bluetooth::legacy::shim::L2cap shim_l2cap;
+
+/**
+ * Classic Service Registration APIs
+ */
+uint16_t bluetooth::shim::L2CA_Register(uint16_t client_psm,
+ tL2CAP_APPL_INFO* callbacks,
+ bool enable_snoop) {
+ if (L2C_INVALID_PSM(client_psm)) {
+ LOG_ERROR(LOG_TAG, "%s Invalid classic psm:%hd", __func__, client_psm);
+ return 0;
+ }
+
+ if ((callbacks->pL2CA_ConfigCfm_Cb == nullptr) ||
+ (callbacks->pL2CA_ConfigInd_Cb == nullptr) ||
+ (callbacks->pL2CA_DataInd_Cb == nullptr) ||
+ (callbacks->pL2CA_DisconnectInd_Cb == nullptr)) {
+ LOG_ERROR(LOG_TAG, "%s Invalid classic callbacks psm:%hd", __func__,
+ client_psm);
+ return 0;
+ }
+
+ /**
+ * Check if this is a registration for an outgoing-only connection.
+ */
+ bool is_outgoing_connection_only = callbacks->pL2CA_ConnectInd_Cb == nullptr;
+ uint16_t psm = shim_l2cap.ConvertClientToRealPsm(client_psm,
+ is_outgoing_connection_only);
+
+ if (shim_l2cap.Classic().IsPsmRegistered(psm)) {
+ LOG_ERROR(LOG_TAG, "%s Already registered classic client_psm:%hd psm:%hd",
+ __func__, client_psm, psm);
+ return 0;
+ }
+ shim_l2cap.Classic().RegisterPsm(psm, callbacks);
+
+ LOG_INFO(LOG_TAG, "%s classic client_psm:%hd psm:%hd", __func__, client_psm,
+ psm);
+
+ shim_l2cap.RegisterService(psm, callbacks, enable_snoop);
+
+ return client_psm;
+}
+
+void bluetooth::shim::L2CA_Deregister(uint16_t client_psm) {
+ if (L2C_INVALID_PSM(client_psm)) {
+ LOG_ERROR(LOG_TAG, "%s Invalid classic client_psm:%hd", __func__,
+ client_psm);
+ return;
+ }
+ uint16_t psm = shim_l2cap.ConvertClientToRealPsm(client_psm);
+
+ if (!shim_l2cap.Classic().IsPsmRegistered(psm)) {
+ LOG_ERROR(LOG_TAG,
+ "%s Not previously registered classic client_psm:%hd psm:%hd",
+ __func__, client_psm, psm);
+ return;
+ }
+ shim_l2cap.Classic().UnregisterPsm(psm);
+ shim_l2cap.RemoveClientPsm(psm);
+}
+
+uint16_t bluetooth::shim::L2CA_AllocatePSM(void) {
+ uint16_t psm = shim_l2cap.GetNextDynamicClassicPsm();
+ shim_l2cap.Classic().AllocatePsm(psm);
+ return psm;
+}
+
+uint16_t bluetooth::shim::L2CA_AllocateLePSM(void) {
+ uint16_t psm = shim_l2cap.GetNextDynamicLePsm();
+ shim_l2cap.Le().AllocatePsm(psm);
+ return psm;
+}
+
+void bluetooth::shim::L2CA_FreeLePSM(uint16_t psm) {
+ if (!shim_l2cap.Le().IsPsmAllocated(psm)) {
+ LOG_ERROR(LOG_TAG, "%s Not previously allocated le psm:%hd", __func__, psm);
+ return;
+ }
+ if (!shim_l2cap.Le().IsPsmRegistered(psm)) {
+ LOG_ERROR(LOG_TAG, "%s Must deregister psm before deallocation psm:%hd",
+ __func__, psm);
+ return;
+ }
+ shim_l2cap.Le().DeallocatePsm(psm);
+}
+
+/**
+ * Classic Connection Oriented Channel APIS
+ */
+uint16_t bluetooth::shim::L2CA_ErtmConnectReq(uint16_t psm,
+ const RawAddress& raw_address,
+ tL2CAP_ERTM_INFO* p_ertm_info) {
+ CHECK(p_ertm_info == nullptr)
+ << "UNIMPLEMENTED set enhanced retransmission mode config";
+ return shim_l2cap.CreateConnection(psm, raw_address);
+}
+
+uint16_t bluetooth::shim::L2CA_ConnectReq(uint16_t psm,
+ const RawAddress& raw_address) {
+ return bluetooth::shim::L2CA_ErtmConnectReq(psm, raw_address, nullptr);
+}
+
+bool bluetooth::shim::L2CA_ErtmConnectRsp(const RawAddress& p_bd_addr,
+ uint8_t id, uint16_t lcid,
+ uint16_t result, uint16_t status,
+ tL2CAP_ERTM_INFO* p_ertm_info) {
+ LOG_INFO(LOG_TAG,
+ "UNIMPLEMENTED %s addr:%s id:%hhd lcid:%hd result:%hd status:%hd "
+ "p_ertm_info:%p",
+ __func__, p_bd_addr.ToString().c_str(), id, lcid, result, status,
+ p_ertm_info);
+ return false;
+}
+
+bool bluetooth::shim::L2CA_ConnectRsp(const RawAddress& p_bd_addr, uint8_t id,
+ uint16_t lcid, uint16_t result,
+ uint16_t status) {
+ return bluetooth::shim::L2CA_ErtmConnectRsp(p_bd_addr, id, lcid, result,
+ status, NULL);
+}
+
+bool bluetooth::shim::L2CA_ConfigReq(uint16_t cid, tL2CAP_CFG_INFO* cfg_info) {
+ return shim_l2cap.ConfigRequest(cid, cfg_info);
+}
+
+bool bluetooth::shim::L2CA_ConfigRsp(uint16_t cid, tL2CAP_CFG_INFO* cfg_info) {
+ return shim_l2cap.ConfigResponse(cid, cfg_info);
+}
+
+bool bluetooth::shim::L2CA_DisconnectReq(uint16_t cid) {
+ return shim_l2cap.DisconnectRequest(cid);
+}
+
+bool bluetooth::shim::L2CA_DisconnectRsp(uint16_t cid) {
+ return shim_l2cap.DisconnectResponse(cid);
+}
+
+/**
+ * Le Connection Oriented Channel APIs
+ */
+uint16_t bluetooth::shim::L2CA_RegisterLECoc(uint16_t psm,
+ tL2CAP_APPL_INFO* callbacks) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s psm:%hd callbacks:%p", __func__, psm,
+ callbacks);
+ return 0;
+}
+
+void bluetooth::shim::L2CA_DeregisterLECoc(uint16_t psm) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s psm:%hd", __func__, psm);
+}
+
+uint16_t bluetooth::shim::L2CA_ConnectLECocReq(uint16_t psm,
+ const RawAddress& p_bd_addr,
+ tL2CAP_LE_CFG_INFO* p_cfg) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s psm:%hd addr:%s p_cfg:%p", __func__, psm,
+ p_bd_addr.ToString().c_str(), p_cfg);
+ return 0;
+}
+
+bool bluetooth::shim::L2CA_ConnectLECocRsp(const RawAddress& p_bd_addr,
+ uint8_t id, uint16_t lcid,
+ uint16_t result, uint16_t status,
+ tL2CAP_LE_CFG_INFO* p_cfg) {
+ LOG_INFO(LOG_TAG,
+ "UNIMPLEMENTED %s addr:%s id:%hhd lcid:%hd result:%hd status:%hd "
+ "p_cfg:%p",
+ __func__, p_bd_addr.ToString().c_str(), id, lcid, result, status,
+ p_cfg);
+ return false;
+}
+
+bool bluetooth::shim::L2CA_GetPeerLECocConfig(uint16_t lcid,
+ tL2CAP_LE_CFG_INFO* peer_cfg) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s lcid:%hd peer_cfg:%p", __func__, lcid,
+ peer_cfg);
+ return false;
+}
+
+/**
+ * Channel Data Writes
+ */
+bool bluetooth::shim::L2CA_SetConnectionCallbacks(
+ uint16_t cid, const tL2CAP_APPL_INFO* callbacks) {
+ LOG_INFO(LOG_TAG, "Unsupported API %s", __func__);
+ return false;
+}
+
+uint8_t bluetooth::shim::L2CA_DataWriteEx(uint16_t cid, BT_HDR* bt_hdr,
+ uint16_t flags) {
+ bool write_success = false;
+ switch (flags) {
+ case L2CAP_FLUSHABLE_CH_BASED:
+ write_success = shim_l2cap.Write(cid, bt_hdr);
+ break;
+ case L2CAP_FLUSHABLE_PKT:
+ write_success = shim_l2cap.WriteFlushable(cid, bt_hdr);
+ break;
+ case L2CAP_NON_FLUSHABLE_PKT:
+ write_success = shim_l2cap.WriteNonFlushable(cid, bt_hdr);
+ break;
+ }
+ return write_success ? L2CAP_DW_SUCCESS : L2CAP_DW_FAILED;
+}
+
+uint8_t bluetooth::shim::L2CA_DataWrite(uint16_t cid, BT_HDR* p_data) {
+ return bluetooth::shim::L2CA_DataWriteEx(cid, p_data,
+ L2CAP_FLUSHABLE_CH_BASED);
+}
+
+/**
+ * L2cap Layer APIs
+ */
+uint8_t bluetooth::shim::L2CA_SetDesireRole(uint8_t new_role) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return 0;
+}
+
+/**
+ * Ping APIs
+ */
+bool bluetooth::shim::L2CA_Ping(const RawAddress& p_bd_addr,
+ tL2CA_ECHO_RSP_CB* p_callback) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s addr:%s p_callback:%p", __func__,
+ p_bd_addr.ToString().c_str(), p_callback);
+ return false;
+}
+
+bool bluetooth::shim::L2CA_Echo(const RawAddress& p_bd_addr, BT_HDR* p_data,
+ tL2CA_ECHO_DATA_CB* p_callback) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s addr:%s p_callback:%p", __func__,
+ p_bd_addr.ToString().c_str(), p_callback);
+ return false;
+}
+
+/**
+ * Link APIs
+ */
+bool bluetooth::shim::L2CA_SetIdleTimeoutByBdAddr(const RawAddress& bd_addr,
+ uint16_t timeout,
+ tBT_TRANSPORT transport) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+uint16_t bluetooth::shim::L2CA_LocalLoopbackReq(uint16_t psm, uint16_t handle,
+ const RawAddress& p_bd_addr) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return 0;
+}
+
+bool bluetooth::shim::L2CA_SetAclPriority(const RawAddress& bd_addr,
+ uint8_t priority) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+bool bluetooth::shim::L2CA_SetFlushTimeout(const RawAddress& bd_addr,
+ uint16_t flush_tout) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+bool bluetooth::shim::L2CA_GetPeerFeatures(const RawAddress& bd_addr,
+ uint32_t* p_ext_feat,
+ uint8_t* p_chnl_mask) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+bool bluetooth::shim::L2CA_GetBDAddrbyHandle(uint16_t handle,
+ RawAddress& bd_addr) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+/**
+ * Fixed Channel APIs
+ */
+bool bluetooth::shim::L2CA_RegisterFixedChannel(uint16_t fixed_cid,
+ tL2CAP_FIXED_CHNL_REG* p_freg) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+bool bluetooth::shim::L2CA_ConnectFixedChnl(uint16_t fixed_cid,
+ const RawAddress& rem_bda) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+bool bluetooth::shim::L2CA_ConnectFixedChnl(uint16_t fixed_cid,
+ const RawAddress& rem_bda,
+ uint8_t initiating_phys) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+uint16_t bluetooth::shim::L2CA_SendFixedChnlData(uint16_t fixed_cid,
+ const RawAddress& rem_bda,
+ BT_HDR* p_buf) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return 0;
+}
+
+bool bluetooth::shim::L2CA_RemoveFixedChnl(uint16_t fixed_cid,
+ const RawAddress& rem_bda) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+/**
+ * Channel Configuration API
+ */
+bool bluetooth::shim::L2CA_GetCurrentConfig(
+ uint16_t lcid, tL2CAP_CFG_INFO** pp_our_cfg,
+ tL2CAP_CH_CFG_BITS* p_our_cfg_bits, tL2CAP_CFG_INFO** pp_peer_cfg,
+ tL2CAP_CH_CFG_BITS* p_peer_cfg_bits) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+bool bluetooth::shim::L2CA_GetConnectionConfig(uint16_t lcid, uint16_t* mtu,
+ uint16_t* rcid,
+ uint16_t* handle) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+/**
+ * Channel hygiene APIs
+ */
+bool bluetooth::shim::L2CA_GetIdentifiers(uint16_t lcid, uint16_t* rcid,
+ uint16_t* handle) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+bool bluetooth::shim::L2CA_SetIdleTimeout(uint16_t cid, uint16_t timeout,
+ bool is_global) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+bool bluetooth::shim::L2CA_FlowControl(uint16_t cid, bool data_enabled) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+bool bluetooth::shim::L2CA_SendTestSFrame(uint16_t cid, uint8_t sup_type,
+ uint8_t back_track) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+bool bluetooth::shim::L2CA_SetTxPriority(uint16_t cid,
+ tL2CAP_CHNL_PRIORITY priority) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+bool bluetooth::shim::L2CA_SetChnlDataRate(uint16_t cid,
+ tL2CAP_CHNL_DATA_RATE tx,
+ tL2CAP_CHNL_DATA_RATE rx) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+uint8_t bluetooth::shim::L2CA_GetChnlFcrMode(uint16_t lcid) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return 0;
+}
+
+bool bluetooth::shim::L2CA_SetFixedChannelTout(const RawAddress& rem_bda,
+ uint16_t fixed_cid,
+ uint16_t idle_tout) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+bool bluetooth::shim::L2CA_SetChnlFlushability(uint16_t cid,
+ bool is_flushable) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
+
+uint16_t bluetooth::shim::L2CA_FlushChannel(uint16_t lcid,
+ uint16_t num_to_flush) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return 0;
+}
+
+/**
+ * Misc APIs
+ */
+bool bluetooth::shim::L2CA_RegForNoCPEvt(tL2CA_NOCP_CB* p_cb,
+ const RawAddress& p_bda) {
+ LOG_INFO(LOG_TAG, "UNIMPLEMENTED %s", __func__);
+ return false;
+}
diff --git a/main/shim/l2c_api.h b/main/shim/l2c_api.h
new file mode 100644
index 0000000..83f3afa
--- /dev/null
+++ b/main/shim/l2c_api.h
@@ -0,0 +1,874 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <set>
+#include <unordered_map>
+
+#include "stack/include/l2c_api.h"
+#include "stack/l2cap/l2c_int.h"
+
+namespace bluetooth {
+namespace shim {
+
+/*******************************************************************************
+ *
+ * Function L2CA_Register
+ *
+ * Description Other layers call this function to register for L2CAP
+ * services.
+ *
+ * Returns PSM to use or zero if error. Typically, the PSM returned
+ * is the same as was passed in, but for an outgoing-only
+ * connection to a dynamic PSM, a "virtual" PSM is returned
+ * and should be used in the calls to L2CA_ConnectReq() and
+ * BTM_SetSecurityLevel().
+ *
+ ******************************************************************************/
+uint16_t L2CA_Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info,
+ bool enable_snoop);
+
+/*******************************************************************************
+ *
+ * Function L2CA_Deregister
+ *
+ * Description Other layers call this function to deregister for L2CAP
+ * services.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void L2CA_Deregister(uint16_t psm);
+
+/*******************************************************************************
+ *
+ * Function L2CA_AllocatePSM
+ *
+ * Description Other layers call this function to find an unused PSM for
+ * L2CAP services.
+ *
+ * Returns PSM to use.
+ *
+ ******************************************************************************/
+uint16_t L2CA_AllocatePSM(void);
+
+/*******************************************************************************
+ *
+ * Function L2CA_AllocateLePSM
+ *
+ * Description Other layers call this function to find an unused LE PSM for
+ * L2CAP services.
+ *
+ * Returns LE_PSM to use if success. Otherwise returns 0.
+ *
+ ******************************************************************************/
+uint16_t L2CA_AllocateLePSM(void);
+
+/*******************************************************************************
+ *
+ * Function L2CA_FreeLePSM
+ *
+ * Description Free an assigned LE PSM.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void L2CA_FreeLePSM(uint16_t psm);
+
+/*******************************************************************************
+ *
+ * Function L2CA_ConnectReq
+ *
+ * Description Higher layers call this function to create an L2CAP
+ * connection.
+ * Note that the connection is not established at this time,
+ * but connection establishment gets started. The callback
+ * will be invoked when connection establishes or fails.
+ *
+ * Returns the CID of the connection, or 0 if it failed to start
+ *
+ ******************************************************************************/
+uint16_t L2CA_ConnectReq(uint16_t psm, const RawAddress& p_bd_addr);
+
+/*******************************************************************************
+ *
+ * Function L2CA_ConnectRsp
+ *
+ * Description Higher layers call this function to accept an incoming
+ * L2CAP connection, for which they had gotten an connect
+ * indication callback.
+ *
+ * Returns true for success, false for failure
+ *
+ ******************************************************************************/
+bool L2CA_ConnectRsp(const RawAddress& p_bd_addr, uint8_t id, uint16_t lcid,
+ uint16_t result, uint16_t status);
+
+/*******************************************************************************
+ *
+ * Function L2CA_ErtmConnectReq
+ *
+ * Description Higher layers call this function to create an L2CAP
+ * connection that needs to use Enhanced Retransmission Mode.
+ * Note that the connection is not established at this time,
+ * but connection establishment gets started. The callback
+ * will be invoked when connection establishes or fails.
+ *
+ * Returns the CID of the connection, or 0 if it failed to start
+ *
+ ******************************************************************************/
+uint16_t L2CA_ErtmConnectReq(uint16_t psm, const RawAddress& p_bd_addr,
+ tL2CAP_ERTM_INFO* p_ertm_info);
+
+/*******************************************************************************
+ *
+ * Function L2CA_RegisterLECoc
+ *
+ * Description Other layers call this function to register for L2CAP
+ * Connection Oriented Channel.
+ *
+ * Returns PSM to use or zero if error. Typically, the PSM returned
+ * is the same as was passed in, but for an outgoing-only
+ * connection to a dynamic PSM, a "virtual" PSM is returned
+ * and should be used in the calls to L2CA_ConnectLECocReq()
+ * and BTM_SetSecurityLevel().
+ *
+ ******************************************************************************/
+uint16_t L2CA_RegisterLECoc(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info);
+
+/*******************************************************************************
+ *
+ * Function L2CA_DeregisterLECoc
+ *
+ * Description Other layers call this function to deregister for L2CAP
+ * Connection Oriented Channel.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+void L2CA_DeregisterLECoc(uint16_t psm);
+
+/*******************************************************************************
+ *
+ * Function L2CA_ConnectLECocReq
+ *
+ * Description Higher layers call this function to create an L2CAP LE COC.
+ * Note that the connection is not established at this time,
+ * but connection establishment gets started. The callback
+ * will be invoked when connection establishes or fails.
+ *
+ * Returns the CID of the connection, or 0 if it failed to start
+ *
+ ******************************************************************************/
+uint16_t L2CA_ConnectLECocReq(uint16_t psm, const RawAddress& p_bd_addr,
+ tL2CAP_LE_CFG_INFO* p_cfg);
+
+/*******************************************************************************
+ *
+ * Function L2CA_ConnectLECocRsp
+ *
+ * Description Higher layers call this function to accept an incoming
+ * L2CAP LE COC connection, for which they had gotten a connect
+ * indication callback.
+ *
+ * Returns true for success, false for failure
+ *
+ ******************************************************************************/
+bool L2CA_ConnectLECocRsp(const RawAddress& p_bd_addr, uint8_t id,
+ uint16_t lcid, uint16_t result, uint16_t status,
+ tL2CAP_LE_CFG_INFO* p_cfg);
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetPeerLECocConfig
+ *
+ * Description Get peers configuration for LE Connection Oriented Channel.
+ *
+ * Return value: true if peer is connected
+ *
+ ******************************************************************************/
+bool L2CA_GetPeerLECocConfig(uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg);
+
+// This function sets the callback routines for the L2CAP connection referred to
+// by |local_cid|. The callback routines can only be modified for outgoing
+// connections established by |L2CA_ConnectReq| or accepted incoming
+// connections. |callbacks| must not be NULL. This function returns true if the
+// callbacks could be updated, false if not (e.g. |local_cid| was not found).
+bool L2CA_SetConnectionCallbacks(uint16_t local_cid,
+ const tL2CAP_APPL_INFO* callbacks);
+
+/*******************************************************************************
+ *
+ * Function L2CA_ErtmConnectRsp
+ *
+ * Description Higher layers call this function to accept an incoming
+ * L2CAP connection, for which they had gotten an connect
+ * indication callback, and for which the higher layer wants
+ * to use Enhanced Retransmission Mode.
+ *
+ * Returns true for success, false for failure
+ *
+ ******************************************************************************/
+bool L2CA_ErtmConnectRsp(const RawAddress& p_bd_addr, uint8_t id, uint16_t lcid,
+ uint16_t result, uint16_t status,
+ tL2CAP_ERTM_INFO* p_ertm_info);
+
+/*******************************************************************************
+ *
+ * Function L2CA_ConfigReq
+ *
+ * Description Higher layers call this function to send configuration.
+ *
+ * Returns true if configuration sent, else false
+ *
+ ******************************************************************************/
+bool L2CA_ConfigReq(uint16_t cid, tL2CAP_CFG_INFO* p_cfg);
+
+/*******************************************************************************
+ *
+ * Function L2CA_ConfigRsp
+ *
+ * Description Higher layers call this function to send a configuration
+ * response.
+ *
+ * Returns true if configuration response sent, else false
+ *
+ ******************************************************************************/
+bool L2CA_ConfigRsp(uint16_t cid, tL2CAP_CFG_INFO* p_cfg);
+
+/*******************************************************************************
+ *
+ * Function L2CA_DisconnectReq
+ *
+ * Description Higher layers call this function to disconnect a channel.
+ *
+ * Returns true if disconnect sent, else false
+ *
+ ******************************************************************************/
+bool L2CA_DisconnectReq(uint16_t cid);
+
+/*******************************************************************************
+ *
+ * Function L2CA_DisconnectRsp
+ *
+ * Description Higher layers call this function to acknowledge the
+ * disconnection of a channel.
+ *
+ * Returns void
+ *
+ ******************************************************************************/
+bool L2CA_DisconnectRsp(uint16_t cid);
+
+/*******************************************************************************
+ *
+ * Function L2CA_DataWrite
+ *
+ * Description Higher layers call this function to write data.
+ *
+ * Returns L2CAP_DW_SUCCESS, if data accepted, else false
+ * L2CAP_DW_CONGESTED, if data accepted and the channel is
+ * congested
+ * L2CAP_DW_FAILED, if error
+ *
+ ******************************************************************************/
+uint8_t L2CA_DataWrite(uint16_t cid, BT_HDR* p_data);
+
+/*******************************************************************************
+ *
+ * Function L2CA_Ping
+ *
+ * Description Higher layers call this function to send an echo request.
+ *
+ * Returns true if echo request sent, else false.
+ *
+ ******************************************************************************/
+bool L2CA_Ping(const RawAddress& p_bd_addr, tL2CA_ECHO_RSP_CB* p_cb);
+
+/*******************************************************************************
+ *
+ * Function L2CA_Echo
+ *
+ * Description Higher layers call this function to send an echo request
+ * with application-specific data.
+ *
+ * Returns true if echo request sent, else false.
+ *
+ ******************************************************************************/
+bool L2CA_Echo(const RawAddress& p_bd_addr, BT_HDR* p_data,
+ tL2CA_ECHO_DATA_CB* p_callback);
+
+// Given a local channel identifier, |lcid|, this function returns the bound
+// remote channel identifier, |rcid|, and the ACL link handle, |handle|. If
+// |lcid| is not known or is invalid, this function returns false and does not
+// modify the values pointed at by |rcid| and |handle|. |rcid| and |handle| may
+// be NULL.
+bool L2CA_GetIdentifiers(uint16_t lcid, uint16_t* rcid, uint16_t* handle);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetIdleTimeout
+ *
+ * Description Higher layers call this function to set the idle timeout for
+ * a connection, or for all future connections. The "idle
+ * timeout" is the amount of time that a connection can remain
+ * up with no L2CAP channels on it. A timeout of zero means
+ * that the connection will be torn down immediately when the
+ * last channel is removed. A timeout of 0xFFFF means no
+ * timeout. Values are in seconds.
+ *
+ * Returns true if command succeeded, false if failed
+ *
+ ******************************************************************************/
+bool L2CA_SetIdleTimeout(uint16_t cid, uint16_t timeout, bool is_global);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetIdleTimeoutByBdAddr
+ *
+ * Description Higher layers call this function to set the idle timeout for
+ * a connection. The "idle timeout" is the amount of time that
+ * a connection can remain up with no L2CAP channels on it.
+ * A timeout of zero means that the connection will be torn
+ * down immediately when the last channel is removed.
+ * A timeout of 0xFFFF means no timeout. Values are in seconds.
+ * A bd_addr is the remote BD address. If bd_addr =
+ * RawAddress::kAny, then the idle timeouts for all active
+ * l2cap links will be changed.
+ *
+ * Returns true if command succeeded, false if failed
+ *
+ * NOTE This timeout applies to all logical channels active on the
+ * ACL link.
+ ******************************************************************************/
+bool L2CA_SetIdleTimeoutByBdAddr(const RawAddress& bd_addr, uint16_t timeout,
+ tBT_TRANSPORT transport);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetTraceLevel
+ *
+ * Description This function sets the trace level for L2CAP. If called with
+ * a value of 0xFF, it simply reads the current trace level.
+ *
+ * Returns the new (current) trace level
+ *
+ ******************************************************************************/
+uint8_t L2CA_SetTraceLevel(uint8_t trace_level);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetDesireRole
+ *
+ * Description This function sets the desire role for L2CAP.
+ * If the new role is L2CAP_ROLE_ALLOW_SWITCH, allow switch on
+ * HciCreateConnection.
+ * If the new role is L2CAP_ROLE_DISALLOW_SWITCH, do not allow
+ * switch on HciCreateConnection.
+ *
+ * If the new role is a valid role (HCI_ROLE_MASTER or
+ * HCI_ROLE_SLAVE), the desire role is set to the new value.
+ * Otherwise, it is not changed.
+ *
+ * Returns the new (current) role
+ *
+ ******************************************************************************/
+uint8_t L2CA_SetDesireRole(uint8_t new_role);
+
+/*******************************************************************************
+ *
+ * Function L2CA_LocalLoopbackReq
+ *
+ * Description This function sets up a CID for local loopback
+ *
+ * Returns CID of 0 if none.
+ *
+ ******************************************************************************/
+uint16_t L2CA_LocalLoopbackReq(uint16_t psm, uint16_t handle,
+ const RawAddress& p_bd_addr);
+
+/*******************************************************************************
+ *
+ * Function L2CA_FlushChannel
+ *
+ * Description This function flushes none, some or all buffers queued up
+ * for xmission for a particular CID. If called with
+ * L2CAP_FLUSH_CHANS_GET (0), it simply returns the number
+ * of buffers queued for that CID L2CAP_FLUSH_CHANS_ALL (0xffff)
+ * flushes all buffers. All other values specifies the maximum
+ * buffers to flush.
+ *
+ * Returns Number of buffers left queued for that CID
+ *
+ ******************************************************************************/
+uint16_t L2CA_FlushChannel(uint16_t lcid, uint16_t num_to_flush);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetAclPriority
+ *
+ * Description Sets the transmission priority for an ACL channel.
+ * (For initial implementation only two values are valid.
+ * L2CAP_PRIORITY_NORMAL and L2CAP_PRIORITY_HIGH).
+ *
+ * Returns true if a valid channel, else false
+ *
+ ******************************************************************************/
+bool L2CA_SetAclPriority(const RawAddress& bd_addr, uint8_t priority);
+
+/*******************************************************************************
+ *
+ * Function L2CA_FlowControl
+ *
+ * Description Higher layers call this function to flow control a channel.
+ *
+ * data_enabled - true data flows, false data is stopped
+ *
+ * Returns true if valid channel, else false
+ *
+ ******************************************************************************/
+bool L2CA_FlowControl(uint16_t cid, bool data_enabled);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SendTestSFrame
+ *
+ * Description Higher layers call this function to send a test S-frame.
+ *
+ * Returns true if valid Channel, else false
+ *
+ ******************************************************************************/
+bool L2CA_SendTestSFrame(uint16_t cid, uint8_t sup_type, uint8_t back_track);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetTxPriority
+ *
+ * Description Sets the transmission priority for a channel. (FCR Mode)
+ *
+ * Returns true if a valid channel, else false
+ *
+ ******************************************************************************/
+bool L2CA_SetTxPriority(uint16_t cid, tL2CAP_CHNL_PRIORITY priority);
+
+/*******************************************************************************
+ *
+ * Function L2CA_RegForNoCPEvt
+ *
+ * Description Register callback for Number of Completed Packets event.
+ *
+ * Input Param p_cb - callback for Number of completed packets event
+ * p_bda - BT address of remote device
+ *
+ * Returns
+ *
+ ******************************************************************************/
+bool L2CA_RegForNoCPEvt(tL2CA_NOCP_CB* p_cb, const RawAddress& p_bda);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetChnlDataRate
+ *
+ * Description Sets the tx/rx data rate for a channel.
+ *
+ * Returns true if a valid channel, else false
+ *
+ ******************************************************************************/
+bool L2CA_SetChnlDataRate(uint16_t cid, tL2CAP_CHNL_DATA_RATE tx,
+ tL2CAP_CHNL_DATA_RATE rx);
+
+typedef void(tL2CA_RESERVE_CMPL_CBACK)(void);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetFlushTimeout
+ *
+ * Description This function set the automatic flush time out in Baseband
+ * for ACL-U packets.
+ * BdAddr : the remote BD address of ACL link. If it is
+ * BT_DB_ANY then the flush time out will be applied
+ * to all ACL link.
+ * FlushTimeout: flush time out in ms
+ * 0x0000 : No automatic flush
+ * L2CAP_NO_RETRANSMISSION : No retransmission
+ * 0x0002 - 0xFFFE : flush time out, if
+ * (flush_tout * 8) + 3 / 5) <=
+ * HCI_MAX_AUTOMATIC_FLUSH_TIMEOUT
+ * (in 625us slot).
+ * Otherwise, return false.
+ * L2CAP_NO_AUTOMATIC_FLUSH : No automatic flush
+ *
+ * Returns true if command succeeded, false if failed
+ *
+ * NOTE This flush timeout applies to all logical channels active on
+ * the ACL link.
+ ******************************************************************************/
+bool L2CA_SetFlushTimeout(const RawAddress& bd_addr, uint16_t flush_tout);
+
+/*******************************************************************************
+ *
+ * Function L2CA_DataWriteEx
+ *
+ * Description Higher layers call this function to write data with extended
+ * flags.
+ * flags : L2CAP_FLUSHABLE_CH_BASED
+ * L2CAP_FLUSHABLE_PKT
+ * L2CAP_NON_FLUSHABLE_PKT
+ *
+ * Returns L2CAP_DW_SUCCESS, if data accepted, else false
+ * L2CAP_DW_CONGESTED, if data accepted and the channel is
+ * congested
+ * L2CAP_DW_FAILED, if error
+ *
+ ******************************************************************************/
+uint8_t L2CA_DataWriteEx(uint16_t cid, BT_HDR* p_data, uint16_t flags);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetChnlFlushability
+ *
+ * Description Higher layers call this function to set a channels
+ * flushability flags
+ *
+ * Returns true if CID found, else false
+ *
+ ******************************************************************************/
+bool L2CA_SetChnlFlushability(uint16_t cid, bool is_flushable);
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetPeerFeatures
+ *
+ * Description Get a peers features and fixed channel map
+ *
+ * Parameters: BD address of the peer
+ * Pointers to features and channel mask storage area
+ *
+ * Return value: true if peer is connected
+ *
+ ******************************************************************************/
+bool L2CA_GetPeerFeatures(const RawAddress& bd_addr, uint32_t* p_ext_feat,
+ uint8_t* p_chnl_mask);
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetBDAddrbyHandle
+ *
+ * Description Get BD address for the given HCI handle
+ *
+ * Parameters: HCI handle
+ * BD address of the peer
+ *
+ * Return value: true if found lcb for the given handle, false otherwise
+ *
+ ******************************************************************************/
+bool L2CA_GetBDAddrbyHandle(uint16_t handle, RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetChnlFcrMode
+ *
+ * Description Get the channel FCR mode
+ *
+ * Parameters: Local CID
+ *
+ * Return value: Channel mode
+ *
+ ******************************************************************************/
+uint8_t L2CA_GetChnlFcrMode(uint16_t lcid);
+
+/*******************************************************************************
+ *
+ * Function L2CA_UcdRegister
+ *
+ * Description Register PSM on UCD.
+ *
+ * Parameters: tL2CAP_UCD_CB_INFO
+ *
+ * Return value: true if successs
+ *
+ ******************************************************************************/
+bool L2CA_UcdRegister(uint16_t psm, tL2CAP_UCD_CB_INFO* p_cb_info);
+
+/*******************************************************************************
+ *
+ * Function L2CA_UcdDeregister
+ *
+ * Description Deregister PSM on UCD.
+ *
+ * Parameters: PSM
+ *
+ * Return value: true if successs
+ *
+ ******************************************************************************/
+bool L2CA_UcdDeregister(uint16_t psm);
+
+/*******************************************************************************
+ *
+ * Function L2CA_UcdDiscover
+ *
+ * Description Discover UCD of remote device.
+ *
+ * Parameters: PSM
+ * BD_ADDR of remote device
+ * info_type : L2CAP_UCD_INFO_TYPE_RECEPTION
+ * L2CAP_UCD_INFO_TYPE_MTU
+ *
+ *
+ * Return value: true if successs
+ *
+ ******************************************************************************/
+bool L2CA_UcdDiscover(uint16_t psm, const RawAddress& rem_bda,
+ uint8_t info_type);
+
+/*******************************************************************************
+ *
+ * Function L2CA_UcdDataWrite
+ *
+ * Description Send UCD to remote device
+ *
+ * Parameters: PSM
+ * BD Address of remote
+ * Pointer to buffer of type BT_HDR
+ * flags : L2CAP_FLUSHABLE_CH_BASED
+ * L2CAP_FLUSHABLE_PKT
+ * L2CAP_NON_FLUSHABLE_PKT
+ *
+ * Return value L2CAP_DW_SUCCESS, if data accepted
+ * L2CAP_DW_FAILED, if error
+ *
+ ******************************************************************************/
+uint16_t L2CA_UcdDataWrite(uint16_t psm, const RawAddress& rem_bda,
+ BT_HDR* p_buf, uint16_t flags);
+
+/*******************************************************************************
+ *
+ * Function L2CA_UcdSetIdleTimeout
+ *
+ * Description Set UCD Idle timeout.
+ *
+ * Parameters: BD Addr
+ * Timeout in second
+ *
+ * Return value: true if successs
+ *
+ ******************************************************************************/
+bool L2CA_UcdSetIdleTimeout(const RawAddress& rem_bda, uint16_t timeout);
+
+/*******************************************************************************
+ *
+ * Function L2CA_UCDSetTxPriority
+ *
+ * Description Sets the transmission priority for a connectionless channel.
+ *
+ * Returns true if a valid channel, else false
+ *
+ ******************************************************************************/
+bool L2CA_UCDSetTxPriority(const RawAddress& rem_bda,
+ tL2CAP_CHNL_PRIORITY priority);
+
+/*******************************************************************************
+ *
+ * Function L2CA_RegisterFixedChannel
+ *
+ * Description Register a fixed channel.
+ *
+ * Parameters: Fixed Channel #
+ * Channel Callbacks and config
+ *
+ * Return value: true if registered OK
+ *
+ ******************************************************************************/
+bool L2CA_RegisterFixedChannel(uint16_t fixed_cid,
+ tL2CAP_FIXED_CHNL_REG* p_freg);
+
+/*******************************************************************************
+ *
+ * Function L2CA_ConnectFixedChnl
+ *
+ * Description Connect an fixed signalling channel to a remote device.
+ *
+ * Parameters: Fixed CID
+ * BD Address of remote
+ *
+ * Return value: true if connection started
+ *
+ ******************************************************************************/
+bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, const RawAddress& bd_addr);
+bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, const RawAddress& bd_addr,
+ uint8_t initiating_phys);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SendFixedChnlData
+ *
+ * Description Write data on a fixed signalling channel.
+ *
+ * Parameters: Fixed CID
+ * BD Address of remote
+ * Pointer to buffer of type BT_HDR
+ *
+ * Return value L2CAP_DW_SUCCESS, if data accepted
+ * L2CAP_DW_FAILED, if error
+ *
+ ******************************************************************************/
+uint16_t L2CA_SendFixedChnlData(uint16_t fixed_cid, const RawAddress& rem_bda,
+ BT_HDR* p_buf);
+
+/*******************************************************************************
+ *
+ * Function L2CA_RemoveFixedChnl
+ *
+ * Description Remove a fixed channel to a remote device.
+ *
+ * Parameters: Fixed CID
+ * BD Address of remote
+ * Idle timeout to use (or 0xFFFF if don't care)
+ *
+ * Return value: true if channel removed
+ *
+ ******************************************************************************/
+bool L2CA_RemoveFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda);
+
+/*******************************************************************************
+ *
+ * Function L2CA_SetFixedChannelTout
+ *
+ * Description Higher layers call this function to set the idle timeout for
+ * a fixed channel. The "idle timeout" is the amount of time
+ * that a connection can remain up with no L2CAP channels on
+ * it. A timeout of zero means that the connection will be torn
+ * down immediately when the last channel is removed.
+ * A timeout of 0xFFFF means no timeout. Values are in seconds.
+ * A bd_addr is the remote BD address. If bd_addr =
+ * RawAddress::kAny, then the idle timeouts for all active
+ * l2cap links will be changed.
+ *
+ * Returns true if command succeeded, false if failed
+ *
+ ******************************************************************************/
+bool L2CA_SetFixedChannelTout(const RawAddress& rem_bda, uint16_t fixed_cid,
+ uint16_t idle_tout);
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetCurrentConfig
+ *
+ * Description This function returns configurations of L2CAP channel
+ * pp_our_cfg : pointer of our saved configuration options
+ * p_our_cfg_bits : valid config in bitmap
+ * pp_peer_cfg: pointer of peer's saved configuration options
+ * p_peer_cfg_bits : valid config in bitmap
+ *
+ * Returns true if successful
+ *
+ ******************************************************************************/
+bool L2CA_GetCurrentConfig(uint16_t lcid, tL2CAP_CFG_INFO** pp_our_cfg,
+ tL2CAP_CH_CFG_BITS* p_our_cfg_bits,
+ tL2CAP_CFG_INFO** pp_peer_cfg,
+ tL2CAP_CH_CFG_BITS* p_peer_cfg_bits);
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetConnectionConfig
+ *
+ * Description This function polulates the mtu, remote cid & lm_handle for
+ * a given local L2CAP channel
+ *
+ * Returns true if successful
+ *
+ ******************************************************************************/
+bool L2CA_GetConnectionConfig(uint16_t lcid, uint16_t* mtu, uint16_t* rcid,
+ uint16_t* handle);
+
+/*******************************************************************************
+ *
+ * Function L2CA_CancelBleConnectReq
+ *
+ * Description Cancel a pending connection attempt to a BLE device.
+ *
+ * Parameters: BD Address of remote
+ *
+ * Return value: true if connection was cancelled
+ *
+ ******************************************************************************/
+bool L2CA_CancelBleConnectReq(const RawAddress& rem_bda);
+
+/*******************************************************************************
+ *
+ * Function L2CA_UpdateBleConnParams
+ *
+ * Description Update BLE connection parameters.
+ *
+ * Parameters: BD Address of remote
+ *
+ * Return value: true if update started
+ *
+ ******************************************************************************/
+bool L2CA_UpdateBleConnParams(const RawAddress& rem_bdRa, uint16_t min_int,
+ uint16_t max_int, uint16_t latency,
+ uint16_t timeout);
+bool L2CA_UpdateBleConnParams(const RawAddress& rem_bda, uint16_t min_int,
+ uint16_t max_int, uint16_t latency,
+ uint16_t timeout, uint16_t min_ce_len,
+ uint16_t max_ce_len);
+
+/*******************************************************************************
+ *
+ * Function L2CA_EnableUpdateBleConnParams
+ *
+ * Description Update BLE connection parameters.
+ *
+ * Parameters: BD Address of remote
+ * enable flag
+ *
+ * Return value: true if update started
+ *
+ ******************************************************************************/
+bool L2CA_EnableUpdateBleConnParams(const RawAddress& rem_bda, bool enable);
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetBleConnRole
+ *
+ * Description This function returns the connection role.
+ *
+ * Returns link role.
+ *
+ ******************************************************************************/
+uint8_t L2CA_GetBleConnRole(const RawAddress& bd_addr);
+
+/*******************************************************************************
+ *
+ * Function L2CA_GetDisconnectReason
+ *
+ * Description This function returns the disconnect reason code.
+ *
+ * Parameters: BD Address of remote
+ * Physical transport for the L2CAP connection (BR/EDR or LE)
+ *
+ * Returns disconnect reason
+ *
+ ******************************************************************************/
+uint16_t L2CA_GetDisconnectReason(const RawAddress& remote_bda,
+ tBT_TRANSPORT transport);
+
+void L2CA_AdjustConnectionIntervals(uint16_t* min_interval,
+ uint16_t* max_interval,
+ uint16_t floor_interval);
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/main/shim/l2cap.cc b/main/shim/l2cap.cc
new file mode 100644
index 0000000..98db9cb
--- /dev/null
+++ b/main/shim/l2cap.cc
@@ -0,0 +1,383 @@
+/*
+ * Copyright 2019 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.
+ */
+#define LOG_TAG "bt_shim_l2cap"
+
+#include <cstdint>
+
+#include "main/shim/entry.h"
+#include "main/shim/l2cap.h"
+#include "main/shim/shim.h"
+#include "osi/include/allocator.h"
+#include "osi/include/log.h"
+
+constexpr size_t kBtHdrSize = sizeof(BT_HDR);
+constexpr uint16_t kInvalidConnectionInterfaceDescriptor = 0;
+constexpr bool kDisconnectResponseRequired = false;
+constexpr uint16_t kConnectionSuccess = 0;
+
+bool bluetooth::legacy::shim::PsmData::IsPsmAllocated(uint16_t psm) const {
+ return psm_to_callback_map_.find(psm) != psm_to_callback_map_.end();
+}
+
+bool bluetooth::legacy::shim::PsmData::IsPsmRegistered(uint16_t psm) const {
+ return IsPsmAllocated(psm) && psm_to_callback_map_.at(psm) != nullptr;
+}
+
+void bluetooth::legacy::shim::PsmData::AllocatePsm(uint16_t psm) {
+ RegisterPsm(psm, nullptr);
+}
+
+void bluetooth::legacy::shim::PsmData::RegisterPsm(
+ uint16_t psm, const tL2CAP_APPL_INFO* callbacks) {
+ psm_to_callback_map_[psm] = callbacks;
+}
+
+void bluetooth::legacy::shim::PsmData::UnregisterPsm(uint16_t psm) {
+ psm_to_callback_map_[psm] = nullptr;
+}
+
+void bluetooth::legacy::shim::PsmData::DeallocatePsm(uint16_t psm) {
+ psm_to_callback_map_.erase(psm);
+}
+
+const tL2CAP_APPL_INFO* bluetooth::legacy::shim::PsmData::Callbacks(
+ uint16_t psm) {
+ if (psm_to_callback_map_.find(psm) == psm_to_callback_map_.end()) {
+ LOG_WARN(LOG_TAG, "Accessing unknown psm:%hd:", psm);
+ return nullptr;
+ }
+ return psm_to_callback_map_[psm];
+}
+
+bluetooth::legacy::shim::L2cap::L2cap()
+ : classic_dynamic_psm_(kInitialClassicDynamicPsm),
+ le_dynamic_psm_(kInitialLeDynamicPsm),
+ classic_virtual_psm_(kInitialClassicVirtualPsm) {}
+
+bluetooth::legacy::shim::PsmData& bluetooth::legacy::shim::L2cap::Le() {
+ return le_;
+}
+
+bluetooth::legacy::shim::PsmData& bluetooth::legacy::shim::L2cap::Classic() {
+ return classic_;
+}
+
+bool bluetooth::legacy::shim::L2cap::ConnectionExists(uint16_t cid) const {
+ return cid_to_psm_map_.find(cid) != cid_to_psm_map_.end();
+}
+
+uint16_t bluetooth::legacy::shim::L2cap::ConvertClientToRealPsm(
+ uint16_t client_psm, bool is_outgoing_only_connection) {
+ if (!is_outgoing_only_connection) {
+ return client_psm;
+ }
+ return GetNextVirtualPsm(client_psm);
+}
+
+uint16_t bluetooth::legacy::shim::L2cap::ConvertClientToRealPsm(
+ uint16_t client_psm) {
+ if (client_psm_to_real_psm_map_.find(client_psm) ==
+ client_psm_to_real_psm_map_.end()) {
+ return client_psm;
+ }
+ return client_psm_to_real_psm_map_.at(client_psm);
+}
+
+void bluetooth::legacy::shim::L2cap::RemoveClientPsm(uint16_t client_psm) {
+ if (client_psm_to_real_psm_map_.find(client_psm) !=
+ client_psm_to_real_psm_map_.end()) {
+ client_psm_to_real_psm_map_.erase(client_psm);
+ }
+}
+
+uint16_t bluetooth::legacy::shim::L2cap::GetNextVirtualPsm(uint16_t real_psm) {
+ if (real_psm < kInitialClassicDynamicPsm) {
+ return real_psm;
+ }
+
+ while (Classic().IsPsmAllocated(classic_virtual_psm_)) {
+ classic_virtual_psm_ += 2;
+ if (classic_virtual_psm_ >= kFinalClassicVirtualPsm) {
+ classic_virtual_psm_ = kInitialClassicVirtualPsm;
+ }
+ }
+ return classic_virtual_psm_;
+}
+
+uint16_t bluetooth::legacy::shim::L2cap::GetNextDynamicLePsm() {
+ while (Le().IsPsmAllocated(le_dynamic_psm_)) {
+ le_dynamic_psm_++;
+ if (le_dynamic_psm_ > kFinalLeDynamicPsm) {
+ le_dynamic_psm_ = kInitialLeDynamicPsm;
+ }
+ }
+ return le_dynamic_psm_;
+}
+
+uint16_t bluetooth::legacy::shim::L2cap::GetNextDynamicClassicPsm() {
+ while (Classic().IsPsmAllocated(classic_dynamic_psm_)) {
+ classic_dynamic_psm_ += 2;
+ if (classic_dynamic_psm_ > kFinalClassicDynamicPsm) {
+ classic_dynamic_psm_ = kInitialClassicDynamicPsm;
+ } else if (classic_dynamic_psm_ & 0x0100) {
+ /* the upper byte must be even */
+ classic_dynamic_psm_ += 0x0100;
+ }
+
+ /* if psm is in range of reserved BRCM Aware features */
+ if ((BRCM_RESERVED_PSM_START <= classic_dynamic_psm_) &&
+ (classic_dynamic_psm_ <= BRCM_RESERVED_PSM_END)) {
+ classic_dynamic_psm_ = BRCM_RESERVED_PSM_END + 2;
+ }
+ }
+ return classic_dynamic_psm_;
+}
+
+void bluetooth::legacy::shim::L2cap::RegisterService(
+ uint16_t psm, const tL2CAP_APPL_INFO* callbacks, bool enable_snoop) {
+ LOG_DEBUG(LOG_TAG, "Registering service on psm:%hd", psm);
+
+ if (!enable_snoop) {
+ LOG_WARN(LOG_TAG, "UNIMPLEMENTED Cannot disable snooping on psm:%d", psm);
+ }
+
+ Classic().RegisterPsm(psm, callbacks);
+
+ std::promise<void> register_completed;
+ auto completed = register_completed.get_future();
+ bluetooth::shim::GetL2cap()->RegisterService(
+ psm,
+ std::bind(
+ &bluetooth::legacy::shim::L2cap::OnRemoteInitiatedConnectionCreated,
+ this, std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3),
+ std::move(register_completed));
+ completed.wait();
+ LOG_DEBUG(LOG_TAG, "Successfully registered service on psm:%hd", psm);
+}
+
+void bluetooth::legacy::shim::L2cap::OnRemoteInitiatedConnectionCreated(
+ std::string string_address, uint16_t psm, uint16_t cid) {
+ RawAddress raw_address;
+ RawAddress::FromString(string_address, raw_address);
+
+ LOG_DEBUG(LOG_TAG,
+ "Sending connection indicator to upper stack from device:%s "
+ "psm:%hd cid:%hd",
+ string_address.c_str(), psm, cid);
+
+ CHECK(!ConnectionExists(cid));
+ cid_to_psm_map_[cid] = psm;
+ SetCallbacks(cid, Classic().Callbacks(psm));
+ const tL2CAP_APPL_INFO* callbacks = Classic().Callbacks(psm);
+ CHECK(callbacks != nullptr);
+ callbacks->pL2CA_ConnectInd_Cb(raw_address, cid, psm /* UNUSED */,
+ 0 /* UNUSED */);
+}
+
+void bluetooth::legacy::shim::L2cap::UnregisterService(uint16_t psm) {
+ if (!Classic().IsPsmRegistered(psm)) {
+ LOG_WARN(LOG_TAG,
+ "Service must be registered in order to unregister psm:%hd", psm);
+ return;
+ }
+ LOG_DEBUG(LOG_TAG, "Unregistering service on psm:%hd", psm);
+ // TODO(cmanton) Check for open channels before unregistering
+ bluetooth::shim::GetL2cap()->UnregisterService(psm);
+ Classic().UnregisterPsm(psm);
+ Classic().DeallocatePsm(psm);
+}
+
+uint16_t bluetooth::legacy::shim::L2cap::CreateConnection(
+ uint16_t psm, const RawAddress& raw_address) {
+ if (!Classic().IsPsmRegistered(psm)) {
+ LOG_WARN(LOG_TAG, "Service must be registered in order to connect psm:%hd",
+ psm);
+ return kInvalidConnectionInterfaceDescriptor;
+ }
+
+ std::promise<uint16_t> connect_completed;
+ auto completed = connect_completed.get_future();
+ LOG_DEBUG(LOG_TAG,
+ "Starting local initiated connection to psm:%hd address:%s", psm,
+ raw_address.ToString().c_str());
+
+ bluetooth::shim::GetL2cap()->CreateConnection(
+ psm, raw_address.ToString(),
+ std::bind(
+ &bluetooth::legacy::shim::L2cap::OnLocalInitiatedConnectionCreated,
+ this, std::placeholders::_1, std::placeholders::_2,
+ std::placeholders::_3),
+ std::move(connect_completed));
+
+ uint16_t cid = completed.get();
+ if (cid == kInvalidConnectionInterfaceDescriptor) {
+ LOG_WARN(LOG_TAG,
+ "Failed to allocate resources to connect to psm:%hd address:%s",
+ psm, raw_address.ToString().c_str());
+ } else {
+ LOG_DEBUG(LOG_TAG,
+ "Successfully started connection to psm:%hd address:%s"
+ " connection_interface_descriptor:%hd",
+ psm, raw_address.ToString().c_str(), cid);
+ CHECK(!ConnectionExists(cid));
+ cid_to_psm_map_[cid] = psm;
+ SetCallbacks(cid, Classic().Callbacks(psm));
+ }
+ return cid;
+}
+
+void bluetooth::legacy::shim::L2cap::OnLocalInitiatedConnectionCreated(
+ std::string string_address, uint16_t psm, uint16_t cid) {
+ LOG_DEBUG(LOG_TAG,
+ "Sending connection confirm to the upper stack but really "
+ "a connection to %s has already been done cid:%hd",
+ string_address.c_str(), cid);
+ // TODO(cmanton) Make sure the device is correct for locally initiated
+ const tL2CAP_APPL_INFO* callbacks = Classic().Callbacks(psm);
+ CHECK(callbacks != nullptr);
+ callbacks->pL2CA_ConnectCfm_Cb(cid, kConnectionSuccess);
+};
+
+bool bluetooth::legacy::shim::L2cap::Write(uint16_t cid, BT_HDR* bt_hdr) {
+ CHECK(bt_hdr != nullptr);
+ const uint8_t* data = bt_hdr->data + bt_hdr->offset;
+ size_t len = bt_hdr->len;
+ if (!ConnectionExists(cid) || len == 0) {
+ return false;
+ }
+ LOG_DEBUG(LOG_TAG, "Writing data cid:%hd len:%zd", cid, len);
+ bluetooth::shim::GetL2cap()->Write(cid, data, len);
+ return true;
+}
+
+bool bluetooth::legacy::shim::L2cap::WriteFlushable(uint16_t cid,
+ BT_HDR* bt_hdr) {
+ CHECK(bt_hdr != nullptr);
+ const uint8_t* data = bt_hdr->data + bt_hdr->offset;
+ size_t len = bt_hdr->len;
+ if (!ConnectionExists(cid) || len == 0) {
+ return false;
+ }
+ bluetooth::shim::GetL2cap()->WriteFlushable(cid, data, len);
+ return true;
+}
+
+bool bluetooth::legacy::shim::L2cap::WriteNonFlushable(uint16_t cid,
+ BT_HDR* bt_hdr) {
+ CHECK(bt_hdr != nullptr);
+ const uint8_t* data = bt_hdr->data + bt_hdr->offset;
+ size_t len = bt_hdr->len;
+ if (!ConnectionExists(cid) || len == 0) {
+ return false;
+ }
+ bluetooth::shim::GetL2cap()->WriteNonFlushable(cid, data, len);
+ return true;
+}
+
+bool bluetooth::legacy::shim::L2cap::SetCallbacks(
+ uint16_t cid, const tL2CAP_APPL_INFO* callbacks) {
+ CHECK(callbacks != nullptr);
+ CHECK(ConnectionExists(cid));
+ LOG_ASSERT(cid_to_callback_map_.find(cid) == cid_to_callback_map_.end())
+ << "Already have callbacks registered for "
+ "connection_interface_descriptor:"
+ << cid;
+ cid_to_callback_map_[cid] = callbacks;
+
+ bluetooth::shim::GetL2cap()->SetReadDataReadyCallback(
+ cid, [this](uint16_t cid, std::vector<const uint8_t> data) {
+ LOG_DEBUG(LOG_TAG, "OnDataReady cid:%hd len:%zd", cid, data.size());
+ BT_HDR* bt_hdr =
+ static_cast<BT_HDR*>(osi_calloc(data.size() + kBtHdrSize));
+ std::copy(data.begin(), data.end(), bt_hdr->data);
+ bt_hdr->len = data.size();
+ CHECK(cid_to_callback_map_.find(cid) != cid_to_callback_map_.end());
+ cid_to_callback_map_[cid]->pL2CA_DataInd_Cb(cid, bt_hdr);
+ });
+
+ bluetooth::shim::GetL2cap()->SetConnectionClosedCallback(
+ cid, [this](uint16_t cid, int error_code) {
+ LOG_DEBUG(LOG_TAG, "OnChannel closed callback cid:%hd", cid);
+ CHECK(cid_to_callback_map_.find(cid) != cid_to_callback_map_.end());
+ cid_to_callback_map_[cid]->pL2CA_DisconnectInd_Cb(
+ cid, kDisconnectResponseRequired);
+ cid_to_callback_map_.erase(cid);
+ cid_to_psm_map_.erase(cid);
+ });
+ return true;
+}
+
+bool bluetooth::legacy::shim::L2cap::ConnectResponse(
+ const RawAddress& raw_address, uint8_t signal_id, uint16_t cid,
+ uint16_t result, uint16_t status, tL2CAP_ERTM_INFO* ertm_info) {
+ CHECK(ConnectionExists(cid));
+ LOG_DEBUG(LOG_TAG,
+ "%s Silently dropping client connect response as channel is "
+ "already connected",
+ __func__);
+ return true;
+}
+
+bool bluetooth::legacy::shim::L2cap::ConfigRequest(
+ uint16_t cid, const tL2CAP_CFG_INFO* config_info) {
+ CHECK(ConnectionExists(cid));
+ LOG_INFO(LOG_TAG, "Received config request from upper layer cid:%hd", cid);
+
+ bluetooth::shim::GetL2cap()->SendLoopbackResponse([this, cid]() {
+ CHECK(ConnectionExists(cid));
+ const tL2CAP_APPL_INFO* callbacks = cid_to_callback_map_[cid];
+ CHECK(callbacks != nullptr);
+ tL2CAP_CFG_INFO cfg_info{
+ .result = L2CAP_CFG_OK,
+ .mtu_present = false,
+ .qos_present = false,
+ .flush_to_present = false,
+ .fcr_present = false,
+ .fcs_present = false,
+ .ext_flow_spec_present = false,
+ .flags = 0,
+ };
+ callbacks->pL2CA_ConfigCfm_Cb(cid, &cfg_info);
+ callbacks->pL2CA_ConfigInd_Cb(cid, &cfg_info);
+ });
+ return true;
+}
+
+bool bluetooth::legacy::shim::L2cap::ConfigResponse(
+ uint16_t cid, const tL2CAP_CFG_INFO* config_info) {
+ CHECK(ConnectionExists(cid));
+ LOG_DEBUG(
+ LOG_TAG,
+ "%s Silently dropping client config response as channel is already open",
+ __func__);
+ return true;
+}
+
+bool bluetooth::legacy::shim::L2cap::DisconnectRequest(uint16_t cid) {
+ CHECK(ConnectionExists(cid));
+ cid_to_callback_map_.erase(cid);
+ bluetooth::shim::GetL2cap()->CloseConnection(cid);
+ return true;
+}
+
+bool bluetooth::legacy::shim::L2cap::DisconnectResponse(uint16_t cid) {
+ LOG_DEBUG(LOG_TAG,
+ "%s Silently dropping client disconnect response as channel is "
+ "already disconnected",
+ __func__);
+ return true;
+}
diff --git a/main/shim/l2cap.h b/main/shim/l2cap.h
new file mode 100644
index 0000000..2fbe0d6
--- /dev/null
+++ b/main/shim/l2cap.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <unordered_map>
+
+#include "stack/include/l2c_api.h"
+
+namespace bluetooth {
+namespace legacy {
+namespace shim {
+
+static constexpr uint16_t kInitialClassicDynamicPsm = 0x1001;
+static constexpr uint16_t kFinalClassicDynamicPsm = 0xfeff;
+static constexpr uint16_t kInitialClassicVirtualPsm = kInitialClassicDynamicPsm;
+static constexpr uint16_t kFinalClassicVirtualPsm = 0x8000;
+static constexpr uint16_t kInitialLeDynamicPsm = 0x0080;
+static constexpr uint16_t kFinalLeDynamicPsm = 0x00ff;
+
+using PsmData = struct {
+ bool IsPsmAllocated(uint16_t psm) const;
+ bool IsPsmRegistered(uint16_t psm) const;
+
+ void AllocatePsm(uint16_t psm);
+ void RegisterPsm(uint16_t psm, const tL2CAP_APPL_INFO* callbacks);
+
+ void UnregisterPsm(uint16_t psm);
+ void DeallocatePsm(uint16_t psm);
+
+ const tL2CAP_APPL_INFO* Callbacks(uint16_t psm);
+
+ private:
+ std::unordered_map<uint16_t, const tL2CAP_APPL_INFO*> psm_to_callback_map_;
+};
+
+class L2cap {
+ public:
+ void RegisterService(uint16_t psm, const tL2CAP_APPL_INFO* callbacks,
+ bool enable_snoop);
+ void UnregisterService(uint16_t psm);
+
+ uint16_t CreateConnection(uint16_t psm, const RawAddress& raw_address);
+
+ bool Write(uint16_t cid, BT_HDR* bt_hdr);
+ bool WriteFlushable(uint16_t cid, BT_HDR* bt_hdr);
+ bool WriteNonFlushable(uint16_t cid, BT_HDR* bt_hdr);
+
+ void OnLocalInitiatedConnectionCreated(std::string string_address,
+ uint16_t psm, uint16_t cid);
+ void OnRemoteInitiatedConnectionCreated(std::string string_addresss,
+ uint16_t psm, uint16_t cid);
+
+ uint16_t GetNextDynamicClassicPsm();
+ uint16_t GetNextDynamicLePsm();
+
+ uint16_t ConvertClientToRealPsm(uint16_t psm,
+ bool is_outgoing_only_connection);
+ uint16_t ConvertClientToRealPsm(uint16_t psm);
+ void RemoveClientPsm(uint16_t client_psm);
+
+ // Legacy API entry points
+ bool ConnectResponse(const RawAddress& raw_address, uint8_t signal_id,
+ uint16_t cid, uint16_t result, uint16_t status,
+ tL2CAP_ERTM_INFO* ertm_info);
+ bool ConfigRequest(uint16_t cid, const tL2CAP_CFG_INFO* config_info);
+ bool ConfigResponse(uint16_t cid, const tL2CAP_CFG_INFO* config_info);
+ bool DisconnectRequest(uint16_t cid);
+ bool DisconnectResponse(uint16_t cid);
+
+ L2cap();
+
+ PsmData& Classic();
+ PsmData& Le();
+
+ private:
+ uint16_t GetNextVirtualPsm(uint16_t real_psm);
+ bool SetCallbacks(uint16_t cid, const tL2CAP_APPL_INFO* callbacks);
+
+ PsmData classic_;
+ PsmData le_;
+
+ bool ConnectionExists(uint16_t cid) const;
+
+ uint16_t classic_dynamic_psm_;
+ uint16_t le_dynamic_psm_;
+ uint16_t classic_virtual_psm_;
+
+ std::unordered_map<uint16_t,
+ std::function<void(std::function<void(uint16_t c)>)>>
+ cid_to_postable_map_;
+ std::unordered_map<uint16_t, uint16_t> cid_to_psm_map_;
+ std::unordered_map<uint16_t, uint16_t> client_psm_to_real_psm_map_;
+ std::unordered_map<uint16_t, const tL2CAP_APPL_INFO*> cid_to_callback_map_;
+};
+
+} // namespace shim
+} // namespace legacy
+} // namespace bluetooth
diff --git a/main/shim/l2cap_test.cc b/main/shim/l2cap_test.cc
new file mode 100644
index 0000000..bf28f3c
--- /dev/null
+++ b/main/shim/l2cap_test.cc
@@ -0,0 +1,331 @@
+/*
+ * Copyright 2019 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 <gtest/gtest.h>
+#include <cstdint>
+
+#define LOG_TAG "bt_shim_test"
+
+#include "osi/include/log.h"
+#include "shim/l2cap.h"
+#include "shim/test_stack.h"
+#include "types/raw_address.h"
+
+TestStack test_stack_;
+
+bluetooth::shim::IStack* bluetooth::shim::GetGabeldorscheStack() {
+ return (bluetooth::shim::IStack*)&test_stack_;
+}
+
+namespace bluetooth {
+namespace legacy {
+
+namespace {
+
+constexpr uint16_t kPsm = 123;
+constexpr uint16_t kCid = 987;
+constexpr size_t kDataBufferSize = 1024;
+
+uint8_t bt_hdr_data[] = {
+ 0x00, 0x00, /* event */
+ 0x08, 0x00, /* len */
+ 0x00, 0x00, /* offset */
+ 0x00, 0x00, /* layer specific */
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, /* data */
+ 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, /* data */
+};
+
+class L2capTest;
+L2capTest* l2cap_test_ = nullptr;
+
+class L2capTest : public ::testing::Test {
+ public:
+ static shim::L2cap* l2cap_;
+
+ struct {
+ int L2caConnectCfmCb;
+ int L2caConnectPndCb;
+ int L2caConfigIndCb;
+ int L2caConfigCfmCb;
+ int L2caDisconnectIndCb;
+ int L2caDisconnectCfmCb;
+ int L2caQosViolationIndCb;
+ int L2caDataIndCb;
+ int L2caCongestionStatusCb;
+ int L2caTxCompleteCb;
+ int L2caCreditsReceivedCb;
+ } cnt_{
+ .L2caConnectCfmCb = 0,
+ .L2caConnectPndCb = 0,
+ .L2caConfigIndCb = 0,
+ .L2caConfigCfmCb = 0,
+ .L2caDisconnectIndCb = 0,
+ .L2caDisconnectCfmCb = 0,
+ .L2caQosViolationIndCb = 0,
+ .L2caDataIndCb = 0,
+ .L2caCongestionStatusCb = 0,
+ .L2caTxCompleteCb = 0,
+ .L2caCreditsReceivedCb = 0,
+ };
+
+ protected:
+ void SetUp() override {
+ l2cap_ = new shim::L2cap();
+ l2cap_test_ = this;
+ }
+
+ void TearDown() override {
+ delete l2cap_;
+ l2cap_ = nullptr;
+ }
+
+ uint8_t data_buffer_[kDataBufferSize];
+};
+
+shim::L2cap* L2capTest::l2cap_ = nullptr;
+// Indication of remotely initiated connection response sent
+void L2caConnectIndCb(const RawAddress& raw_address, uint16_t a, uint16_t b,
+ uint8_t c) {
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+// Confirms locally initiated connection request completed
+void L2caConnectCfmCb(uint16_t cid, uint16_t result) {
+ l2cap_test_->cnt_.L2caConnectCfmCb++;
+ LOG_INFO(LOG_TAG, "%s cid:%hd result:%hd", __func__, cid, result);
+}
+
+void L2caConnectPndCb(uint16_t cid) {
+ l2cap_test_->cnt_.L2caConnectPndCb++;
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+// Indication of remotely initiated configuration response sent
+void L2caConfigIndCb(uint16_t cid, tL2CAP_CFG_INFO* callbacks) {
+ l2cap_test_->cnt_.L2caConfigIndCb++;
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+// Confirms locally initiated config request completed
+void L2caConfigCfmCb(uint16_t cid, tL2CAP_CFG_INFO* callbacks) {
+ l2cap_test_->cnt_.L2caConfigCfmCb++;
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+// Indication of remotely initiated disconnection response sent
+void L2caDisconnectIndCb(uint16_t cid, bool needs_ack) {
+ l2cap_test_->cnt_.L2caDisconnectIndCb++;
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+// Confirms locally initiated disconnect request completed
+void L2caDisconnectCfmCb(uint16_t cid, uint16_t result) {
+ l2cap_test_->cnt_.L2caDisconnectCfmCb++;
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+void L2caQosViolationIndCb(const RawAddress& raw_address) {
+ l2cap_test_->cnt_.L2caQosViolationIndCb++;
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+void L2caDataIndCb(uint16_t cid, BT_HDR* bt_hdr) {
+ l2cap_test_->cnt_.L2caDataIndCb++;
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+void L2caCongestionStatusCb(uint16_t cid, bool is_congested) {
+ l2cap_test_->cnt_.L2caCongestionStatusCb++;
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+void L2caTxCompleteCb(uint16_t cid, uint16_t sdu_cnt) {
+ l2cap_test_->cnt_.L2caTxCompleteCb++;
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+void L2caCreditsReceivedCb(uint16_t cid, uint16_t credits_received,
+ uint16_t credit_count) {
+ l2cap_test_->cnt_.L2caCreditsReceivedCb++;
+ LOG_INFO(LOG_TAG, "%s", __func__);
+}
+
+tL2CAP_APPL_INFO test_callbacks{
+ .pL2CA_ConnectInd_Cb = L2caConnectIndCb,
+ .pL2CA_ConnectCfm_Cb = L2caConnectCfmCb,
+ .pL2CA_ConnectPnd_Cb = L2caConnectPndCb,
+ .pL2CA_ConfigInd_Cb = L2caConfigIndCb,
+ .pL2CA_ConfigCfm_Cb = L2caConfigCfmCb,
+ .pL2CA_DisconnectInd_Cb = L2caDisconnectIndCb,
+ .pL2CA_DisconnectCfm_Cb = L2caDisconnectCfmCb,
+ .pL2CA_QoSViolationInd_Cb = L2caQosViolationIndCb,
+ .pL2CA_DataInd_Cb = L2caDataIndCb,
+ .pL2CA_CongestionStatus_Cb = L2caCongestionStatusCb,
+ .pL2CA_TxComplete_Cb = L2caTxCompleteCb,
+ .pL2CA_CreditsReceived_Cb = L2caCreditsReceivedCb,
+};
+
+TEST_F(L2capTest, RegisterService) {
+ l2cap_->RegisterService(kPsm, &test_callbacks, false);
+ CHECK(test_stack_.test_l2cap_.registered_service_.count(kPsm) == 1);
+}
+
+TEST_F(L2capTest, UnregisterService) {
+ l2cap_->RegisterService(kPsm, &test_callbacks, false);
+ CHECK(test_stack_.test_l2cap_.registered_service_.count(kPsm) == 1);
+ l2cap_->UnregisterService(kPsm);
+ CHECK(test_stack_.test_l2cap_.registered_service_.count(kPsm) == 0);
+}
+
+TEST_F(L2capTest, CreateConnection_NotRegistered) {
+ RawAddress raw_address;
+ std::string string_address("11:22:33:44:55:66");
+ RawAddress::FromString(string_address, raw_address);
+ uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
+ CHECK(cid == 0);
+}
+
+TEST_F(L2capTest, CreateConnection_Registered) {
+ test_stack_.test_l2cap_.cid_ = kCid;
+ l2cap_->RegisterService(kPsm, &test_callbacks, false);
+
+ RawAddress raw_address;
+ std::string string_address("11:22:33:44:55:66");
+ RawAddress::FromString(string_address, raw_address);
+ uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
+ CHECK(cid != 0);
+}
+
+TEST_F(L2capTest, CreateConnection_ConnectResponse) {
+ test_stack_.test_l2cap_.cid_ = kCid;
+ l2cap_->RegisterService(kPsm, &test_callbacks, false);
+
+ RawAddress raw_address;
+ std::string string_address("11:22:33:44:55:66");
+ RawAddress::FromString(string_address, raw_address);
+ uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
+ CHECK(cid != 0);
+
+ CHECK(l2cap_->ConnectResponse(raw_address, 0, cid, 0, 0, nullptr));
+}
+
+TEST_F(L2capTest, CreateConnection_ConfigRequest) {
+ test_stack_.test_l2cap_.cid_ = kCid;
+ l2cap_->RegisterService(kPsm, &test_callbacks, false);
+
+ RawAddress raw_address;
+ std::string string_address("11:22:33:44:55:66");
+ RawAddress::FromString(string_address, raw_address);
+ uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
+ CHECK(cid != 0);
+
+ // Simulate a successful connection response
+ l2cap_->OnLocalInitiatedConnectionCreated("11:22:33:44:55:66", kPsm, kCid);
+ CHECK(cnt_.L2caConnectCfmCb == 1);
+
+ CHECK(l2cap_->ConfigRequest(cid, nullptr));
+}
+
+TEST_F(L2capTest, CreateConnection_ConfigResponse) {
+ test_stack_.test_l2cap_.cid_ = kCid;
+ l2cap_->RegisterService(kPsm, &test_callbacks, false);
+
+ RawAddress raw_address;
+ std::string string_address("11:22:33:44:55:66");
+ RawAddress::FromString(string_address, raw_address);
+ uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
+ CHECK(cid != 0);
+
+ // Simulate a successful connection response
+ l2cap_->OnLocalInitiatedConnectionCreated("11:22:33:44:55:66", kPsm, kCid);
+ CHECK(cnt_.L2caConnectCfmCb == 1);
+
+ CHECK(l2cap_->ConfigResponse(cid, nullptr));
+}
+
+TEST_F(L2capTest, CreateConnection_DisconnectRequest) {
+ test_stack_.test_l2cap_.cid_ = kCid;
+ l2cap_->RegisterService(kPsm, &test_callbacks, false);
+
+ RawAddress raw_address;
+ std::string string_address("11:22:33:44:55:66");
+ RawAddress::FromString(string_address, raw_address);
+ uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
+ CHECK(cid != 0);
+
+ // Simulate a successful connection response
+ l2cap_->OnLocalInitiatedConnectionCreated("11:22:33:44:55:66", kPsm, kCid);
+ CHECK(cnt_.L2caConnectCfmCb == 1);
+
+ CHECK(l2cap_->DisconnectRequest(cid));
+}
+
+TEST_F(L2capTest, CreateConnection_DisconnectResponse) {
+ test_stack_.test_l2cap_.cid_ = kCid;
+ l2cap_->RegisterService(kPsm, &test_callbacks, false);
+
+ RawAddress raw_address;
+ std::string string_address("11:22:33:44:55:66");
+ RawAddress::FromString(string_address, raw_address);
+ uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
+ CHECK(cid != 0);
+
+ // Simulate a successful connection response
+ l2cap_->OnLocalInitiatedConnectionCreated("11:22:33:44:55:66", kPsm, kCid);
+ CHECK(cnt_.L2caConnectCfmCb == 1);
+
+ CHECK(l2cap_->DisconnectResponse(cid));
+}
+
+TEST_F(L2capTest, CreateConnection_WithHandshake) {
+ test_stack_.test_l2cap_.cid_ = kCid;
+ l2cap_->RegisterService(kPsm, &test_callbacks, false);
+
+ RawAddress raw_address;
+ std::string string_address("11:22:33:44:55:66");
+ RawAddress::FromString(string_address, raw_address);
+ uint16_t cid = l2cap_->CreateConnection(kPsm, raw_address);
+ CHECK(cid != 0);
+
+ // Simulate a successful connection response
+ l2cap_->OnLocalInitiatedConnectionCreated("11:22:33:44:55:66", kPsm, kCid);
+ CHECK(cnt_.L2caConnectCfmCb == 1);
+
+ CHECK(l2cap_->ConfigRequest(cid, nullptr) == true);
+ CHECK(cnt_.L2caConfigCfmCb == 1);
+ CHECK(cnt_.L2caConfigIndCb == 1);
+
+ BT_HDR* bt_hdr = (BT_HDR*)bt_hdr_data;
+
+ test_stack_.test_l2cap_.data_buffer_ = data_buffer_;
+ test_stack_.test_l2cap_.data_buffer_size_ = kDataBufferSize;
+
+ l2cap_->Write(cid, bt_hdr);
+
+ CHECK(data_buffer_[0] == 0x11);
+ CHECK(data_buffer_[1] == 0x22);
+ CHECK(data_buffer_[2] == 0x33);
+ CHECK(data_buffer_[3] == 0x44);
+ CHECK(data_buffer_[4] == 0x55);
+ CHECK(data_buffer_[5] == 0x66);
+ CHECK(data_buffer_[6] == 0x77);
+ CHECK(data_buffer_[7] == 0x88);
+ CHECK(data_buffer_[8] == 0x00);
+}
+
+} // namespace
+} // namespace legacy
+} // namespace bluetooth
diff --git a/main/shim/shim.cc b/main/shim/shim.cc
new file mode 100644
index 0000000..9af17d6
--- /dev/null
+++ b/main/shim/shim.cc
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019 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 <cstdint>
+
+#include "main/shim/entry.h"
+#include "main/shim/shim.h"
+#include "osi/include/properties.h"
+
+static const char* kPropertyKey = "bluetooth.gd.enabled";
+
+static bool gd_shim_enabled_ = false;
+static bool gd_shim_property_checked_ = false;
+
+EXPORT_SYMBOL extern const module_t gd_shim_module = {
+ .name = GD_SHIM_MODULE,
+ .init = nullptr,
+ .start_up = bluetooth::shim::StartGabeldorscheStack,
+ .shut_down = bluetooth::shim::StopGabeldorscheStack,
+ .clean_up = NULL,
+ .dependencies = {NULL}};
+
+bool bluetooth::shim::is_gd_shim_enabled() {
+ if (!gd_shim_property_checked_) {
+ gd_shim_property_checked_ = true;
+ gd_shim_enabled_ = (osi_property_get_int32(kPropertyKey, 0) == 1);
+ }
+ return gd_shim_enabled_;
+}
diff --git a/main/shim/shim.h b/main/shim/shim.h
new file mode 100644
index 0000000..38fb208
--- /dev/null
+++ b/main/shim/shim.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+/**
+ * Gabeldorsche related legacy-only-stack-side expansion and support code.
+ */
+#include "btcore/include/module.h"
+#include "main/shim/entry.h"
+
+static const char GD_SHIM_MODULE[] = "gd_shim_module";
+
+namespace bluetooth {
+namespace shim {
+
+bool is_gd_shim_enabled();
+
+} // namespace shim
+} // namespace bluetooth
diff --git a/main/shim/test_stack.cc b/main/shim/test_stack.cc
new file mode 100644
index 0000000..9d38541
--- /dev/null
+++ b/main/shim/test_stack.cc
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2019 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 <cstdint>
+#include <future>
+
+#include "gd/shim/only_include_this_file_into_legacy_stack___ever.h"
+#include "main/shim/entry.h"
+#include "main/shim/test_stack.h"
+#include "osi/include/log.h"
+
+#define ASSERT(condition) \
+ do { \
+ if (!(condition)) { \
+ LOG_ALWAYS_FATAL("assertion '" #condition "' failed"); \
+ } \
+ } while (false)
+
+void TestGdShimL2cap::RegisterService(
+ uint16_t psm, bluetooth::shim::ConnectionOpenCallback on_open,
+ std::promise<void> completed) {
+ completed.set_value();
+ registered_service_.insert(psm);
+}
+
+void TestGdShimL2cap::UnregisterService(uint16_t psm) {
+ registered_service_.erase(psm);
+}
+
+void TestGdShimL2cap::CreateConnection(
+ uint16_t psm, const std::string address,
+ bluetooth::shim::ConnectionOpenCallback on_open,
+ std::promise<uint16_t> completed) {
+ completed.set_value(cid_);
+}
+
+void TestGdShimL2cap::CloseConnection(uint16_t cid) {}
+
+void TestGdShimL2cap::SetReadDataReadyCallback(
+ uint16_t cid, bluetooth::shim::ReadDataReadyCallback on_data_ready) {}
+
+void TestGdShimL2cap::SetConnectionClosedCallback(
+ uint16_t cid, bluetooth::shim::ConnectionClosedCallback on_closed) {}
+
+void TestGdShimL2cap::Write(uint16_t cid, const uint8_t* data, size_t len) {
+ ASSERT(data_buffer_ != nullptr);
+ ASSERT(data_buffer_size_ > len);
+ memcpy(data_buffer_, data, len);
+}
+
+void TestGdShimL2cap::WriteFlushable(uint16_t cid, const uint8_t* data,
+ size_t len) {}
+
+void TestGdShimL2cap::WriteNonFlushable(uint16_t cid, const uint8_t* data,
+ size_t len) {}
+
+void TestGdShimL2cap::SendLoopbackResponse(std::function<void()> function) {
+ function();
+}
+
+void TestStack::Start() {}
+
+void TestStack::Stop() {}
+
+bluetooth::shim::IAdvertising* TestStack::GetAdvertising() { return nullptr; }
+
+bluetooth::shim::IController* TestStack::GetController() { return nullptr; }
+
+bluetooth::shim::IConnectability* TestStack::GetConnectability() {
+ return nullptr;
+}
+
+bluetooth::shim::IDiscoverability* TestStack::GetDiscoverability() {
+ return nullptr;
+}
+
+bluetooth::shim::IHciLayer* TestStack::GetHciLayer() { return nullptr; }
+
+bluetooth::shim::IInquiry* TestStack::GetInquiry() { return nullptr; }
+
+bluetooth::shim::IL2cap* TestStack::GetL2cap() { return &test_l2cap_; }
+
+bluetooth::shim::IName* TestStack::GetName() { return nullptr; }
+
+bluetooth::shim::IPage* TestStack::GetPage() { return nullptr; }
+
+bluetooth::shim::IScanning* TestStack::GetScanning() { return nullptr; }
diff --git a/main/shim/test_stack.h b/main/shim/test_stack.h
new file mode 100644
index 0000000..92027b1
--- /dev/null
+++ b/main/shim/test_stack.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2019 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 <cstdint>
+#include <future>
+#include <set>
+
+#include "gd/shim/only_include_this_file_into_legacy_stack___ever.h"
+#include "main/shim/entry.h"
+
+class TestGdShimL2cap : public bluetooth::shim::IL2cap {
+ public:
+ uint16_t cid_{0};
+ bool write_success_{false};
+ bool is_congested_{false};
+ uint8_t* data_buffer_{nullptr};
+ size_t data_buffer_size_{0};
+ std::set<uint16_t /* psm */> registered_service_;
+
+ void RegisterService(uint16_t psm,
+ bluetooth::shim::ConnectionOpenCallback on_open,
+ std::promise<void> completed) override;
+ void UnregisterService(uint16_t psm);
+ void CreateConnection(uint16_t psm, const std::string address,
+ bluetooth::shim::ConnectionOpenCallback on_open,
+ std::promise<uint16_t> completed) override;
+ void CloseConnection(uint16_t cid);
+ void SetReadDataReadyCallback(
+ uint16_t cid,
+ bluetooth::shim::ReadDataReadyCallback on_data_ready) override;
+ void SetConnectionClosedCallback(
+ uint16_t cid,
+ bluetooth::shim::ConnectionClosedCallback on_closed) override;
+ void Write(uint16_t cid, const uint8_t* data, size_t len) override;
+ void WriteFlushable(uint16_t cid, const uint8_t* data, size_t len) override;
+ void WriteNonFlushable(uint16_t cid, const uint8_t* data,
+ size_t len) override;
+ void SendLoopbackResponse(std::function<void()>) override;
+};
+
+class TestStack : public bluetooth::shim::IStack {
+ public:
+ TestStack() = default;
+
+ bluetooth::shim::IAdvertising* GetAdvertising();
+ bluetooth::shim::IController* GetController();
+ bluetooth::shim::IConnectability* GetConnectability();
+ bluetooth::shim::IDiscoverability* GetDiscoverability();
+ bluetooth::shim::IHciLayer* GetHciLayer();
+ bluetooth::shim::IInquiry* GetInquiry();
+ bluetooth::shim::IL2cap* GetL2cap();
+ bluetooth::shim::IName* GetName();
+ bluetooth::shim::IPage* GetPage();
+ bluetooth::shim::IScanning* GetScanning();
+
+ TestGdShimL2cap test_l2cap_;
+
+ void Start();
+ void Stop();
+};
diff --git a/osi/Android.bp b/osi/Android.bp
index e6c95d0..bcdaf5f 100644
--- a/osi/Android.bp
+++ b/osi/Android.bp
@@ -6,7 +6,7 @@
"system/bt/internal_include",
"system/bt/utils/include",
"system/bt/stack/include",
- ]
+ ],
}
// Static libraries required by other modules
@@ -19,7 +19,7 @@
],
host_supported: true,
shared: {
- enabled: false
+ enabled: false,
},
}
@@ -31,7 +31,7 @@
],
host_supported: true,
shared: {
- enabled: false
+ enabled: false,
},
}
diff --git a/osi/test/alarm_test.cc b/osi/test/alarm_test.cc
index dad54ef..fb55dc7 100644
--- a/osi/test/alarm_test.cc
+++ b/osi/test/alarm_test.cc
@@ -46,7 +46,7 @@
class AlarmTest : public AlarmTestHarness {
protected:
- virtual void SetUp() {
+ void SetUp() override {
AlarmTestHarness::SetUp();
cb_counter = 0;
cb_misordered_counter = 0;
@@ -54,7 +54,7 @@
semaphore = semaphore_new(0);
}
- virtual void TearDown() {
+ void TearDown() override {
semaphore_free(semaphore);
AlarmTestHarness::TearDown();
}
diff --git a/osi/test/config_test.cc b/osi/test/config_test.cc
index 7cf4db8..32858fd 100644
--- a/osi/test/config_test.cc
+++ b/osi/test/config_test.cc
@@ -52,7 +52,7 @@
class ConfigTest : public AllocationTestHarness {
protected:
- virtual void SetUp() {
+ void SetUp() override {
AllocationTestHarness::SetUp();
FILE* fp = fopen(CONFIG_FILE, "wt");
fwrite(CONFIG_FILE_CONTENT, 1, sizeof(CONFIG_FILE_CONTENT), fp);
diff --git a/osi/test/hash_map_utils_test.cc b/osi/test/hash_map_utils_test.cc
index 1e312d4..d5df2d7 100644
--- a/osi/test/hash_map_utils_test.cc
+++ b/osi/test/hash_map_utils_test.cc
@@ -27,8 +27,8 @@
class HashMapUtilsTest : public AllocationTestHarness {
protected:
- virtual void SetUp() { AllocationTestHarness::SetUp(); }
- virtual void TearDown() {
+ void SetUp() override { AllocationTestHarness::SetUp(); }
+ void TearDown() override {
map.clear();
AllocationTestHarness::TearDown();
}
diff --git a/osi/test/wakelock_test.cc b/osi/test/wakelock_test.cc
index 0e027be..a1dfc05 100644
--- a/osi/test/wakelock_test.cc
+++ b/osi/test/wakelock_test.cc
@@ -45,7 +45,7 @@
class WakelockTest : public AllocationTestHarness {
protected:
- virtual void SetUp() {
+ void SetUp() override {
AllocationTestHarness::SetUp();
// TODO (jamuraa): maybe use base::CreateNewTempDirectory instead?
@@ -69,7 +69,7 @@
creat(unlock_path_.c_str(), S_IRWXU);
}
- virtual void TearDown() {
+ void TearDown() override {
is_wake_lock_acquired = false;
wakelock_cleanup();
wakelock_set_os_callouts(NULL);
diff --git a/profile/avrcp/Android.bp b/profile/avrcp/Android.bp
index d452cb0..515f513 100644
--- a/profile/avrcp/Android.bp
+++ b/profile/avrcp/Android.bp
@@ -2,7 +2,7 @@
name: "avrcp-target-service",
defaults: [
"fluoride_defaults",
- "clang_file_coverage"
+ "clang_file_coverage",
],
host_supported: true,
include_dirs: [
@@ -62,3 +62,35 @@
cflags: ["-DBUILDCFG"],
}
+
+cc_fuzz {
+ name: "avrcp_device_fuzz",
+ host_supported: true,
+ defaults: [
+ "fluoride_defaults_fuzzable",
+ ],
+ srcs: [
+ "tests/avrcp_device_fuzz/avrcp_device_fuzz.cc",
+ ],
+ include_dirs: [
+ "system/bt",
+ "system/bt/packet/tests",
+ "system/bt/btcore/include",
+ "system/bt/internal_include",
+ "system/bt/stack/include",
+ ],
+ static_libs: [
+ "avrcp-target-service",
+ "lib-bt-packets",
+ "libbase",
+ "libchrome",
+ "libcutils",
+ "libevent",
+ "liblog",
+ "libstatslog",
+ ],
+ header_libs: ["libbluetooth_headers"],
+ corpus: [
+ "tests/avrcp_device_fuzz/corpus/*",
+ ],
+}
diff --git a/profile/avrcp/connection_handler.cc b/profile/avrcp/connection_handler.cc
index 686f89b..7b2765a 100644
--- a/profile/avrcp/connection_handler.cc
+++ b/profile/avrcp/connection_handler.cc
@@ -534,6 +534,11 @@
// doesn't need to be processed. In the future, this is the only place sending
// the packet so none of these layer specific fields will be used.
pkt->event = 0xFFFF;
+ /* Handle for AVRCP fragment */
+ uint16_t op_code = (uint16_t)(::bluetooth::Packet::Specialize<Packet>(packet)->GetOpcode());
+ if (!browse && (op_code == (uint16_t)(Opcode::VENDOR))) {
+ pkt->event = op_code;
+ }
// TODO (apanicke): This layer specific stuff can go away once we move over
// to the new service.
diff --git a/profile/avrcp/tests/avrcp_connection_handler_test.cc b/profile/avrcp/tests/avrcp_connection_handler_test.cc
index 4f542f6..5a811b2 100644
--- a/profile/avrcp/tests/avrcp_connection_handler_test.cc
+++ b/profile/avrcp/tests/avrcp_connection_handler_test.cc
@@ -25,12 +25,13 @@
#include "connection_handler.h"
using ::testing::_;
+using ::testing::DoAll;
+using ::testing::MockFunction;
+using ::testing::NiceMock;
using ::testing::Return;
using ::testing::SaveArg;
using ::testing::SaveArgPointee;
using ::testing::SetArgPointee;
-using ::testing::MockFunction;
-using ::testing::NiceMock;
using ::testing::StrictMock;
namespace bluetooth {
@@ -55,7 +56,7 @@
.p_next_attr = nullptr,
.attr_id = 0,
.attr_len_type = 0,
- .attr_value.v.u16 = 0,
+ .attr_value = {.v = {.u16 = 0}},
};
if (browsing) fake_features.attr_value.v.u16 |= AVRC_SUPF_CT_BROWSE;
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc b/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc
new file mode 100644
index 0000000..24a794d
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/avrcp_device_fuzz.cc
@@ -0,0 +1,86 @@
+#include <cstddef>
+#include <cstdint>
+
+#include "avrcp_packet.h"
+#include "device.h"
+#include "packet_test_helper.h"
+#include "stack_config.h"
+
+namespace bluetooth {
+namespace avrcp {
+class FakeMediaInterface : public MediaInterface {
+ public:
+ virtual void SendKeyEvent(uint8_t key, KeyState state) {}
+ using SongInfoCallback = base::Callback<void(SongInfo)>;
+ virtual void GetSongInfo(SongInfoCallback info_cb) {}
+ using PlayStatusCallback = base::Callback<void(PlayStatus)>;
+ virtual void GetPlayStatus(PlayStatusCallback status_cb) {}
+ using NowPlayingCallback =
+ base::Callback<void(std::string, std::vector<SongInfo>)>;
+ virtual void GetNowPlayingList(NowPlayingCallback now_playing_cb) {}
+ using MediaListCallback =
+ base::Callback<void(uint16_t curr_player, std::vector<MediaPlayerInfo>)>;
+ virtual void GetMediaPlayerList(MediaListCallback list_cb) {}
+ using FolderItemsCallback = base::Callback<void(std::vector<ListItem>)>;
+ virtual void GetFolderItems(uint16_t player_id, std::string media_id,
+ FolderItemsCallback folder_cb) {}
+ using SetBrowsedPlayerCallback = base::Callback<void(
+ bool success, std::string root_id, uint32_t num_items)>;
+ virtual void SetBrowsedPlayer(uint16_t player_id,
+ SetBrowsedPlayerCallback browse_cb) {}
+ virtual void PlayItem(uint16_t player_id, bool now_playing,
+ std::string media_id) {}
+ virtual void SetActiveDevice(const RawAddress& address) {}
+ virtual void RegisterUpdateCallback(MediaCallbacks* callback) {}
+ virtual void UnregisterUpdateCallback(MediaCallbacks* callback) {}
+};
+
+class FakeVolumeInterface : public VolumeInterface {
+ public:
+ virtual void DeviceConnected(const RawAddress& bdaddr) {}
+ virtual void DeviceConnected(const RawAddress& bdaddr, VolumeChangedCb cb) {}
+ virtual void DeviceDisconnected(const RawAddress& bdaddr) {}
+ virtual void SetVolume(int8_t volume) {}
+};
+
+class FakeA2dpInterface : public A2dpInterface {
+ public:
+ virtual RawAddress active_peer() { return RawAddress(); }
+ virtual bool is_peer_in_silence_mode(const RawAddress& peer_address) {
+ return false;
+ }
+};
+
+bool get_pts_avrcp_test(void) { return false; }
+
+const stack_config_t interface = {
+ nullptr, get_pts_avrcp_test, nullptr, nullptr, nullptr, nullptr, nullptr,
+ nullptr};
+
+void Callback(uint8_t, bool, std::unique_ptr<::bluetooth::PacketBuilder>) {}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
+ FakeMediaInterface fmi;
+ FakeVolumeInterface fvi;
+ FakeA2dpInterface fai;
+
+ std::vector<uint8_t> Packet(Data, Data + Size);
+ Device device(RawAddress::kAny, true,
+ base::Bind([](uint8_t, bool,
+ std::unique_ptr<::bluetooth::PacketBuilder>) {}),
+ 0xFFFF, 0xFFFF);
+ device.RegisterInterfaces(&fmi, &fai, &fvi);
+
+ auto browse_request = TestPacketType<BrowsePacket>::Make(Packet);
+ device.BrowseMessageReceived(1, browse_request);
+
+ auto avrcp_request = TestPacketType<avrcp::Packet>::Make(Packet);
+ device.MessageReceived(1, avrcp_request);
+ return 0;
+}
+} // namespace avrcp
+} // namespace bluetooth
+
+const stack_config_t* stack_config_get_interface(void) {
+ return &bluetooth::avrcp::interface;
+}
\ No newline at end of file
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_error_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_error_response
new file mode 100644
index 0000000..f5f982c
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_error_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_request
new file mode 100644
index 0000000..581327a
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_response
new file mode 100644
index 0000000..10c7576
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_up_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_up_request
new file mode 100644
index 0000000..a222657
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/change_path_up_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/changed_play_pos_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/changed_play_pos_notification
new file mode 100644
index 0000000..6ee7661
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/changed_play_pos_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/changed_volume_changed_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/changed_volume_changed_notification
new file mode 100644
index 0000000..31d50fb
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/changed_volume_changed_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/general_reject_invalid_command_packet b/profile/avrcp/tests/avrcp_device_fuzz/corpus/general_reject_invalid_command_packet
new file mode 100644
index 0000000..83fa427
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/general_reject_invalid_command_packet
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request
new file mode 100644
index 0000000..3968c03
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request_company_id b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request_company_id
new file mode 100644
index 0000000..f3966ed
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request_company_id
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request_unknown b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request_unknown
new file mode 100644
index 0000000..eada547
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_request_unknown
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_response_company_id b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_response_company_id
new file mode 100644
index 0000000..21889ca
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_response_company_id
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_response_events_supported b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_response_events_supported
new file mode 100644
index 0000000..d2cf8a8
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_capabilities_response_events_supported
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_element_attributes_request_full b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_element_attributes_request_full
new file mode 100644
index 0000000..d79c1d3
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_element_attributes_request_full
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_element_attributes_request_partial b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_element_attributes_request_partial
new file mode 100644
index 0000000..c37c9b6
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_element_attributes_request_partial
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_elements_attributes_response_full b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_elements_attributes_response_full
new file mode 100644
index 0000000..2e63feb
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_elements_attributes_response_full
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_error_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_error_response
new file mode 100644
index 0000000..a09361b
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_error_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_folder_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_folder_response
new file mode 100644
index 0000000..f58889a
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_folder_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_media_player_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_media_player_response
new file mode 100644
index 0000000..ed25c8c
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_media_player_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request
new file mode 100644
index 0000000..098fa05
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_no_attrs b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_no_attrs
new file mode 100644
index 0000000..7e27ff9
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_no_attrs
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_now_playing b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_now_playing
new file mode 100644
index 0000000..9eaa355
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_now_playing
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_title b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_title
new file mode 100644
index 0000000..0108fc7
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_title
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_vfs b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_vfs
new file mode 100644
index 0000000..e8cc867
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_request_vfs
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_song_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_song_response
new file mode 100644
index 0000000..f7472e0
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_folder_items_song_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_request_all_attributes b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_request_all_attributes
new file mode 100644
index 0000000..7d706b8
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_request_all_attributes
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_request_all_attributes_invalid b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_request_all_attributes_invalid
new file mode 100644
index 0000000..d55d0c4
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_request_all_attributes_invalid
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_song_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_song_response
new file mode 100644
index 0000000..3553664
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_item_attributes_song_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_play_status_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_play_status_request
new file mode 100644
index 0000000..2311a47
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_play_status_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_play_status_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_play_status_response
new file mode 100644
index 0000000..240136f
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_play_status_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_media_players b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_media_players
new file mode 100644
index 0000000..a5b85b7
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_media_players
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_now_playing b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_now_playing
new file mode 100644
index 0000000..a4a6654
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_now_playing
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_vfs b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_vfs
new file mode 100644
index 0000000..0f9ad75
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_request_vfs
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_response
new file mode 100644
index 0000000..742da96
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/get_total_number_of_items_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_addressed_player_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_addressed_player_notification
new file mode 100644
index 0000000..2f6044b
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_addressed_player_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_available_players_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_available_players_notification
new file mode 100644
index 0000000..b643cf4
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_available_players_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_now_playing_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_now_playing_notification
new file mode 100644
index 0000000..ea6675e
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_now_playing_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_play_status_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_play_status_notification
new file mode 100644
index 0000000..0fb233d
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_play_status_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_track_changed_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_track_changed_notification
new file mode 100644
index 0000000..b23cf6e
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_track_changed_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_uids_notificaiton b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_uids_notificaiton
new file mode 100644
index 0000000..cac9b4a
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_uids_notificaiton
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_volume_changed_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_volume_changed_notification
new file mode 100644
index 0000000..101bae6
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/interim_volume_changed_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/pass_through_command_play_pushed b/profile/avrcp/tests/avrcp_device_fuzz/corpus/pass_through_command_play_pushed
new file mode 100644
index 0000000..9e002d2
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/pass_through_command_play_pushed
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/pass_through_command_play_released b/profile/avrcp/tests/avrcp_device_fuzz/corpus/pass_through_command_play_released
new file mode 100644
index 0000000..5c100e8
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/pass_through_command_play_released
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/play_item_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/play_item_request
new file mode 100644
index 0000000..538a7c0
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/play_item_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/play_item_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/play_item_response
new file mode 100644
index 0000000..1180bcc
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/play_item_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_notification_invalid b/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_notification_invalid
new file mode 100644
index 0000000..2a213f0
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_notification_invalid
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_play_status_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_play_status_notification
new file mode 100644
index 0000000..fa40de4
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_play_status_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_volume_changed_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_volume_changed_notification
new file mode 100644
index 0000000..3e7209b
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/register_volume_changed_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/reject_player_app_settings_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/reject_player_app_settings_response
new file mode 100644
index 0000000..82cc047
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/reject_player_app_settings_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/rejected_volume_changed_notification b/profile/avrcp/tests/avrcp_device_fuzz/corpus/rejected_volume_changed_notification
new file mode 100644
index 0000000..5119a2d
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/rejected_volume_changed_notification
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_absolute_volume_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_absolute_volume_request
new file mode 100644
index 0000000..5403b84
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_absolute_volume_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_absolute_volume_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_absolute_volume_response
new file mode 100644
index 0000000..b30cde2
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_absolute_volume_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_id_1_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_id_1_request
new file mode 100644
index 0000000..ebe224e
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_id_1_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_request
new file mode 100644
index 0000000..a38cfb7
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_response
new file mode 100644
index 0000000..4230524
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_addressed_player_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_browsed_player_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_browsed_player_request
new file mode 100644
index 0000000..667137b
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_browsed_player_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_browsed_player_response b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_browsed_player_response
new file mode 100644
index 0000000..c3a3c93
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/set_browsed_player_response
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_browse_packet b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_browse_packet
new file mode 100644
index 0000000..b866ef0
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_browse_packet
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_change_path_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_change_path_request
new file mode 100644
index 0000000..365d337
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_change_path_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_capabilities_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_capabilities_request
new file mode 100644
index 0000000..c7c5b33
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_capabilities_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_element_attributes_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_element_attributes_request
new file mode 100644
index 0000000..102d788
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_element_attributes_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_folder_items_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_folder_items_request
new file mode 100644
index 0000000..4ab0aa8
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_folder_items_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_item_attributes_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_item_attributes_request
new file mode 100644
index 0000000..7467555
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_item_attributes_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_total_number_of_items_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_total_number_of_items_request
new file mode 100644
index 0000000..bc634e2
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_get_total_number_of_items_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_play_item_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_play_item_request
new file mode 100644
index 0000000..a138dc4
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_play_item_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_set_addressed_player_request b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_set_addressed_player_request
new file mode 100644
index 0000000..4872d6b
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_set_addressed_player_request
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_vendor_packet b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_vendor_packet
new file mode 100644
index 0000000..0c2a66e
--- /dev/null
+++ b/profile/avrcp/tests/avrcp_device_fuzz/corpus/short_vendor_packet
Binary files differ
diff --git a/profile/avrcp/tests/avrcp_device_test.cc b/profile/avrcp/tests/avrcp_device_test.cc
index c608da6..d221e1b 100644
--- a/profile/avrcp/tests/avrcp_device_test.cc
+++ b/profile/avrcp/tests/avrcp_device_test.cc
@@ -57,7 +57,7 @@
// Add more tests to increase code coverage.
class AvrcpDeviceTest : public ::testing::Test {
public:
- virtual void SetUp() override {
+ void SetUp() override {
// NOTE: We use a wrapper lambda for the MockFunction in order to
// add a const qualifier to the response. Otherwise the MockFunction
// type doesn't match the callback type and a compiler error occurs.
@@ -71,7 +71,7 @@
test_device = new Device(RawAddress::kAny, true, cb, 0xFFFF, 0xFFFF);
}
- virtual void TearDown() override {
+ void TearDown() override {
delete test_device;
Mock::VerifyAndClear(&response_cb);
}
diff --git a/profile/sdp/Android.bp b/profile/sdp/Android.bp
index 9254337..5abd77b 100644
--- a/profile/sdp/Android.bp
+++ b/profile/sdp/Android.bp
@@ -1,40 +1,40 @@
cc_library_static {
- name: "sdp_service",
- defaults: [
- "fluoride_defaults",
- "clang_file_coverage"
- ],
- host_supported: true,
- include_dirs: [
- "system/bt/",
- ],
- srcs: [
- "common/data_element_reader.cc",
- ],
- static_libs: [
- "lib-bt-packets",
- "libbluetooth-types",
- ],
+ name: "sdp_service",
+ defaults: [
+ "fluoride_defaults",
+ "clang_file_coverage",
+ ],
+ host_supported: true,
+ include_dirs: [
+ "system/bt/",
+ ],
+ srcs: [
+ "common/data_element_reader.cc",
+ ],
+ static_libs: [
+ "lib-bt-packets",
+ "libbluetooth-types",
+ ],
}
cc_test {
- name: "bluetooth_test_sdp",
- test_suites: ["general-tests"],
- defaults: [
- "fluoride_defaults",
- "clang_coverage_bin",
- ],
- host_supported: true,
- include_dirs: [
- "system/bt/",
- ],
- srcs: [
- "common/test/data_element_reader_test.cc",
- ],
- static_libs: [
- "libgmock",
- "sdp_service",
- "lib-bt-packets",
- "libbluetooth-types",
- ],
+ name: "bluetooth_test_sdp",
+ test_suites: ["general-tests"],
+ defaults: [
+ "fluoride_defaults",
+ "clang_coverage_bin",
+ ],
+ host_supported: true,
+ include_dirs: [
+ "system/bt/",
+ ],
+ srcs: [
+ "common/test/data_element_reader_test.cc",
+ ],
+ static_libs: [
+ "libgmock",
+ "sdp_service",
+ "lib-bt-packets",
+ "libbluetooth-types",
+ ],
}
diff --git a/proto/Android.bp b/proto/Android.bp
index 0f97c72..c8a852d 100644
--- a/proto/Android.bp
+++ b/proto/Android.bp
@@ -16,4 +16,3 @@
},
srcs: ["bluetooth/metrics/bluetooth.proto"],
}
-
diff --git a/service/Android.bp b/service/Android.bp
index d57119a..4b21d0d 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -8,7 +8,7 @@
include_dirs: [
"system/bt",
],
- header_libs: [ "libbluetooth_headers" ],
+ header_libs: ["libbluetooth_headers"],
}
// Source variables
@@ -80,9 +80,9 @@
name: "bluetoothtbd",
defaults: ["fluoride_service_defaults"],
srcs: btserviceBinderDaemonSrc +
- btserviceLinuxSrc +
- btserviceDaemonSrc +
- ["main.cc"],
+ btserviceLinuxSrc +
+ btserviceDaemonSrc +
+ ["main.cc"],
static_libs: [
"libbluetooth-binder-common",
"libbtcore",
@@ -108,9 +108,9 @@
test_suites: ["device-tests"],
defaults: ["fluoride_service_defaults"],
srcs: btserviceBaseTestSrc +
- btserviceDaemonSrc + [
- "test/main.cc",
- ],
+ btserviceDaemonSrc + [
+ "test/main.cc",
+ ],
aidl: {
include_dirs: [
"system/bt/service/common",
diff --git a/service/common/Android.bp b/service/common/Android.bp
index fa63cf9..e3bde74 100644
--- a/service/common/Android.bp
+++ b/service/common/Android.bp
@@ -7,7 +7,7 @@
"-fvisibility=default",
],
host_supported: true,
- header_libs: [ "libbluetooth_headers" ],
+ header_libs: ["libbluetooth_headers"],
srcs: [
"bluetooth/a2dp_codec_config.cc",
"bluetooth/adapter_state.cc",
@@ -40,7 +40,7 @@
/* we export all classes, so change default visibility, instead of having EXPORT_SYMBOL on each class*/
"-fvisibility=default",
],
- header_libs: [ "libbluetooth_headers" ],
+ header_libs: ["libbluetooth_headers"],
srcs: [
"android/bluetooth/IBluetooth.aidl",
"android/bluetooth/IBluetoothA2dpSink.aidl",
@@ -94,5 +94,5 @@
],
static_libs: [
"libbluetooth-types",
- ]
+ ],
}
diff --git a/service/gatt_server.cc b/service/gatt_server.cc
index 52fd1ed..08c4f83 100644
--- a/service/gatt_server.cc
+++ b/service/gatt_server.cc
@@ -68,18 +68,20 @@
std::vector<btgatt_db_element_t> svc;
- svc.push_back({.type = (service.primary() ? BTGATT_DB_PRIMARY_SERVICE
- : BTGATT_DB_SECONDARY_SERVICE),
- .uuid = service.uuid()});
+ svc.push_back({
+ .uuid = service.uuid(),
+ .type = (service.primary() ? BTGATT_DB_PRIMARY_SERVICE
+ : BTGATT_DB_SECONDARY_SERVICE),
+ });
for (const auto& characteristic : service.characteristics()) {
- svc.push_back({.type = BTGATT_DB_CHARACTERISTIC,
- .uuid = characteristic.uuid(),
+ svc.push_back({.uuid = characteristic.uuid(),
+ .type = BTGATT_DB_CHARACTERISTIC,
.properties = characteristic.properties(),
.permissions = characteristic.permissions()});
for (const auto& descriptor : characteristic.descriptors())
- svc.push_back({.type = BTGATT_DB_DESCRIPTOR,
- .uuid = descriptor.uuid(),
+ svc.push_back({.uuid = descriptor.uuid(),
+ .type = BTGATT_DB_DESCRIPTOR,
.permissions = descriptor.permissions()});
}
diff --git a/service/gatt_server_old.cc b/service/gatt_server_old.cc
index b583d93..cfc394c 100644
--- a/service/gatt_server_old.cc
+++ b/service/gatt_server_old.cc
@@ -136,8 +136,10 @@
g_internal->server_if = server_if;
- pending_svc_decl.push_back(
- {.type = BTGATT_DB_PRIMARY_SERVICE, .uuid = app_uuid});
+ pending_svc_decl.push_back({
+ .uuid = app_uuid,
+ .type = BTGATT_DB_PRIMARY_SERVICE,
+ });
}
void ServiceAddedCallback(int status, int server_if,
@@ -502,8 +504,8 @@
bt_status_t ServerInternals::AddCharacteristic(const Uuid& uuid,
uint8_t properties,
uint16_t permissions) {
- pending_svc_decl.push_back({.type = BTGATT_DB_CHARACTERISTIC,
- .uuid = uuid,
+ pending_svc_decl.push_back({.uuid = uuid,
+ .type = BTGATT_DB_CHARACTERISTIC,
.properties = properties,
.permissions = permissions});
return BT_STATUS_SUCCESS;
diff --git a/service/test/gatt_server_unittest.cc b/service/test/gatt_server_unittest.cc
index 7d7fec2..e19742d 100644
--- a/service/test/gatt_server_unittest.cc
+++ b/service/test/gatt_server_unittest.cc
@@ -267,14 +267,14 @@
desc_handle_ = 0x0004;
std::vector<btgatt_db_element_t> service_with_handles = {
- {.type = BTGATT_DB_PRIMARY_SERVICE,
- .uuid = uuid0,
+ {.uuid = uuid0,
+ .type = BTGATT_DB_PRIMARY_SERVICE,
.attribute_handle = srvc_handle_},
- {.type = BTGATT_DB_CHARACTERISTIC,
- .uuid = uuid1,
+ {.uuid = uuid1,
+ .type = BTGATT_DB_CHARACTERISTIC,
.attribute_handle = char_handle_},
- {.type = BTGATT_DB_DESCRIPTOR,
- .uuid = uuid2,
+ {.uuid = uuid2,
+ .type = BTGATT_DB_DESCRIPTOR,
.attribute_handle = desc_handle_},
};
diff --git a/service/test/low_energy_client_unittest.cc b/service/test/low_energy_client_unittest.cc
index 3bf566c..ce3c7c0 100644
--- a/service/test/low_energy_client_unittest.cc
+++ b/service/test/low_energy_client_unittest.cc
@@ -58,13 +58,13 @@
int connection_state_count() const { return connection_state_count_; }
void OnConnectionState(LowEnergyClient* client, int status,
- const char* address, bool connected) {
+ const char* address, bool connected) override {
ASSERT_TRUE(client);
connection_state_count_++;
}
void OnMtuChanged(LowEnergyClient* client, int status, const char* address,
- int mtu) {
+ int mtu) override {
ASSERT_TRUE(client);
last_mtu_ = mtu;
}
diff --git a/service/test/low_energy_scanner_unittest.cc b/service/test/low_energy_scanner_unittest.cc
index c8b16f3..9a7875d 100644
--- a/service/test/low_energy_scanner_unittest.cc
+++ b/service/test/low_energy_scanner_unittest.cc
@@ -72,12 +72,12 @@
MOCK_METHOD1(StopSync, void(uint16_t));
void ScanFilterAdd(int filter_index, std::vector<ApcfCommand> filters,
- FilterConfigCallback cb){};
+ FilterConfigCallback cb) override{};
void ScanFilterParamSetup(
uint8_t client_if, uint8_t action, uint8_t filt_index,
std::unique_ptr<btgatt_filt_param_setup_t> filt_param,
- FilterParamSetupCallback cb) {
+ FilterParamSetupCallback cb) override {
ScanFilterParamSetupImpl(client_if, action, filt_index, filt_param.get(),
std::move(cb));
}
@@ -92,7 +92,8 @@
int scan_result_count() const { return scan_result_count_; }
const ScanResult& last_scan_result() const { return last_scan_result_; }
- void OnScanResult(LowEnergyScanner* scanner, const ScanResult& scan_result) {
+ void OnScanResult(LowEnergyScanner* scanner,
+ const ScanResult& scan_result) override {
ASSERT_TRUE(scanner);
scan_result_count_++;
last_scan_result_ = scan_result;
diff --git a/stack/Android.bp b/stack/Android.bp
index f7f5a45..b573aaf 100644
--- a/stack/Android.bp
+++ b/stack/Android.bp
@@ -46,7 +46,6 @@
"system/bt/bta/sys",
"system/bt/utils/include",
],
- cflags: ["-Wno-implicit-fallthrough"],
srcs: crypto_toolbox_srcs + [
"a2dp/a2dp_aac.cc",
"a2dp/a2dp_aac_decoder.cc",
@@ -202,23 +201,45 @@
"test/stack_a2dp_test.cc",
],
shared_libs: [
- "libcrypto",
+ "android.hardware.bluetooth@1.0",
+ "android.hardware.bluetooth@1.1",
+ "android.hardware.bluetooth.a2dp@1.0",
+ "android.hardware.bluetooth.audio@2.0",
+ "libaudioclient",
+ "libcutils",
+ "libdl",
+ "libfmq",
"libhidlbase",
"liblog",
+ "libprocessgroup",
"libprotobuf-cpp-lite",
- "libcutils",
"libutils",
+ "libtinyxml2",
+ "libz",
+ "libcrypto",
+ "android.hardware.keymaster@4.0",
+ "android.hardware.keymaster@3.0",
+ "libkeymaster4support",
+ "libkeystore_aidl",
+ "libkeystore_binder",
+ "libkeystore_parcelables",
],
static_libs: [
+ "libbt-audio-hal-interface",
+ "libbtcore",
"libbt-bta",
"libbt-stack",
"libbt-common",
"libbt-sbc-decoder",
"libbt-sbc-encoder",
+ "libbt-utils",
+ "libbtif",
"libFraunhoferAAC",
+ "libg722codec",
"libbtdevice",
"libbt-hci",
"libosi",
+ "libudrv-uipc",
"libbt-protos-lite",
],
whole_static_libs: [
diff --git a/stack/avrc/avrc_api.cc b/stack/avrc/avrc_api.cc
index e2f109a..62b7fe4 100644
--- a/stack/avrc/avrc_api.cc
+++ b/stack/avrc/avrc_api.cc
@@ -32,6 +32,7 @@
#include "btu.h"
#include "osi/include/fixed_queue.h"
#include "osi/include/osi.h"
+#include "osi/include/properties.h"
/*****************************************************************************
* Global data
@@ -1113,27 +1114,32 @@
AVRC_TRACE_DEBUG("%s handle = %u label = %u ctype = %u len = %d", __func__,
handle, label, ctype, p_pkt->len);
-
+ /* Handle for AVRCP fragment */
+ bool is_new_avrcp = osi_property_get_bool("persist.bluetooth.enablenewavrcp", true);
if (ctype >= AVRC_RSP_NOT_IMPL) cr = AVCT_RSP;
if (p_pkt->event == AVRC_OP_VENDOR) {
- /* add AVRCP Vendor Dependent headers */
- p_start = ((uint8_t*)(p_pkt + 1) + p_pkt->offset);
- p_pkt->offset -= AVRC_VENDOR_HDR_SIZE;
- p_pkt->len += AVRC_VENDOR_HDR_SIZE;
- p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
- *p_data++ = (ctype & AVRC_CTYPE_MASK);
- *p_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
- *p_data++ = AVRC_OP_VENDOR;
- AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
+ if (is_new_avrcp) {
+ p_start = (uint8_t*)(p_pkt + 1) + p_pkt->offset + AVRC_VENDOR_HDR_SIZE;
+ } else {
+ /* add AVRCP Vendor Dependent headers */
+ p_start = ((uint8_t*)(p_pkt + 1) + p_pkt->offset);
+ p_pkt->offset -= AVRC_VENDOR_HDR_SIZE;
+ p_pkt->len += AVRC_VENDOR_HDR_SIZE;
+ p_data = (uint8_t*)(p_pkt + 1) + p_pkt->offset;
+ *p_data++ = (ctype & AVRC_CTYPE_MASK);
+ *p_data++ = (AVRC_SUB_PANEL << AVRC_SUBTYPE_SHIFT);
+ *p_data++ = AVRC_OP_VENDOR;
+ AVRC_CO_ID_TO_BE_STREAM(p_data, AVRC_CO_METADATA);
- /* Check if this is a AVRC_PDU_REQUEST_CONTINUATION_RSP */
- if (cr == AVCT_CMD) {
- msg_mask |= AVRC_MSG_MASK_IS_VENDOR_CMD;
+ /* Check if this is a AVRC_PDU_REQUEST_CONTINUATION_RSP */
+ if (cr == AVCT_CMD) {
+ msg_mask |= AVRC_MSG_MASK_IS_VENDOR_CMD;
- if ((*p_start == AVRC_PDU_REQUEST_CONTINUATION_RSP) ||
- (*p_start == AVRC_PDU_ABORT_CONTINUATION_RSP)) {
- msg_mask |= AVRC_MSG_MASK_IS_CONTINUATION_RSP;
+ if ((*p_start == AVRC_PDU_REQUEST_CONTINUATION_RSP) ||
+ (*p_start == AVRC_PDU_ABORT_CONTINUATION_RSP)) {
+ msg_mask |= AVRC_MSG_MASK_IS_CONTINUATION_RSP;
+ }
}
}
} else if (p_pkt->event == AVRC_OP_PASS_THRU) {
diff --git a/stack/avrc/avrc_bld_tg.cc b/stack/avrc/avrc_bld_tg.cc
index b28c9e2..1dac160 100644
--- a/stack/avrc/avrc_bld_tg.cc
+++ b/stack/avrc/avrc_bld_tg.cc
@@ -1338,8 +1338,7 @@
case AVRC_OP_VENDOR:
/* reserved 0, packet_type 0 */
UINT8_TO_BE_STREAM(p_data, 0);
- /* continue to the next "case to add length */
-
+ [[fallthrough]];
case AVRC_OP_BROWSE:
/* add fixed lenth - 0 */
UINT16_TO_BE_STREAM(p_data, 0);
diff --git a/stack/avrc/avrc_pars_ct.cc b/stack/avrc/avrc_pars_ct.cc
index 80dc882..39ed921 100644
--- a/stack/avrc/avrc_pars_ct.cc
+++ b/stack/avrc/avrc_pars_ct.cc
@@ -806,7 +806,7 @@
if (len < min_len) goto length_error;
BE_STREAM_TO_UINT32(p_result->get_play_status.song_len, p);
BE_STREAM_TO_UINT32(p_result->get_play_status.song_pos, p);
- BE_STREAM_TO_UINT8(p_result->get_play_status.status, p);
+ BE_STREAM_TO_UINT8(p_result->get_play_status.play_status, p);
break;
case AVRC_PDU_SET_ADDRESSED_PLAYER:
diff --git a/stack/btm/ble_advertiser_hci_interface.cc b/stack/btm/ble_advertiser_hci_interface.cc
index dddf8d4..fbf8d27 100644
--- a/stack/btm/ble_advertiser_hci_interface.cc
+++ b/stack/btm/ble_advertiser_hci_interface.cc
@@ -97,7 +97,7 @@
class BleAdvertiserVscHciInterfaceImpl : public BleAdvertiserHciInterface {
void SendAdvCmd(const base::Location& posted_from, uint8_t param_len,
uint8_t* param_buf, status_cb command_complete) {
- btu_hcif_send_cmd_with_cb(posted_from, HCI_BLE_MULTI_ADV_OCF, param_buf,
+ btu_hcif_send_cmd_with_cb(posted_from, HCI_BLE_MULTI_ADV, param_buf,
param_len,
base::Bind(&btm_ble_multi_adv_vsc_cmpl_cback,
param_buf[0], command_complete));
diff --git a/stack/btm/btm_acl.cc b/stack/btm/btm_acl.cc
index be0c937..2a417b9 100644
--- a/stack/btm/btm_acl.cc
+++ b/stack/btm/btm_acl.cc
@@ -2608,7 +2608,7 @@
} else {
if (!BTM_ACL_IS_CONNECTED(bda)) {
VLOG(1) << "connecting_bda: " << btm_cb.connecting_bda;
- if (btm_cb.paging && bda != btm_cb.connecting_bda) {
+ if (btm_cb.paging && bda == btm_cb.connecting_bda) {
fixed_queue_enqueue(btm_cb.page_queue, p);
} else {
p_dev_rec = btm_find_or_alloc_dev(bda);
diff --git a/stack/btm/btm_ble.cc b/stack/btm/btm_ble.cc
index 3f67876..1c4aa37 100644
--- a/stack/btm/btm_ble.cc
+++ b/stack/btm/btm_ble.cc
@@ -39,8 +39,10 @@
#include "gap_api.h"
#include "gatt_api.h"
#include "hcimsgs.h"
-#include "log/log.h"
#include "l2c_int.h"
+#include "log/log.h"
+#include "main/shim/btm_api.h"
+#include "main/shim/shim.h"
#include "osi/include/log.h"
#include "osi/include/osi.h"
#include "stack/crypto_toolbox/crypto_toolbox.h"
@@ -69,6 +71,11 @@
******************************************************************************/
bool BTM_SecAddBleDevice(const RawAddress& bd_addr, BD_NAME bd_name,
tBT_DEVICE_TYPE dev_type, tBLE_ADDR_TYPE addr_type) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_SecAddBleDevice(bd_addr, bd_name, dev_type,
+ addr_type);
+ }
+
BTM_TRACE_DEBUG("%s: dev_type=0x%x", __func__, dev_type);
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
@@ -130,6 +137,10 @@
******************************************************************************/
bool BTM_SecAddBleKey(const RawAddress& bd_addr, tBTM_LE_KEY_VALUE* p_le_key,
tBTM_LE_KEY_TYPE key_type) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_SecAddBleKey(bd_addr, p_le_key, key_type);
+ }
+
tBTM_SEC_DEV_REC* p_dev_rec;
BTM_TRACE_DEBUG("BTM_SecAddBleKey");
p_dev_rec = btm_find_dev(bd_addr);
@@ -170,6 +181,10 @@
*
******************************************************************************/
void BTM_BleLoadLocalKeys(uint8_t key_type, tBTM_BLE_LOCAL_KEYS* p_key) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_BleLoadLocalKeys(key_type, p_key);
+ }
+
tBTM_DEVCB* p_devcb = &btm_cb.devcb;
BTM_TRACE_DEBUG("%s", __func__);
if (p_key != NULL) {
@@ -192,14 +207,27 @@
/** Returns local device encryption root (ER) */
const Octet16& BTM_GetDeviceEncRoot() {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_GetDeviceEncRoot();
+ }
return btm_cb.devcb.ble_encryption_key_value;
}
/** Returns local device identity root (IR). */
-const Octet16& BTM_GetDeviceIDRoot() { return btm_cb.devcb.id_keys.irk; }
+const Octet16& BTM_GetDeviceIDRoot() {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_GetDeviceIDRoot();
+ }
+ return btm_cb.devcb.id_keys.irk;
+}
/** Return local device DHK. */
-const Octet16& BTM_GetDeviceDHK() { return btm_cb.devcb.id_keys.dhk; }
+const Octet16& BTM_GetDeviceDHK() {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_GetDeviceDHK();
+ }
+ return btm_cb.devcb.id_keys.dhk;
+}
/*******************************************************************************
*
@@ -214,6 +242,10 @@
void BTM_ReadConnectionAddr(const RawAddress& remote_bda,
RawAddress& local_conn_addr,
tBLE_ADDR_TYPE* p_addr_type) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_ReadConnectionAddr(remote_bda, local_conn_addr,
+ p_addr_type);
+ }
tACL_CONN* p_acl = btm_bda_to_acl(remote_bda, BT_TRANSPORT_LE);
if (p_acl == NULL) {
@@ -238,6 +270,9 @@
*
******************************************************************************/
bool BTM_IsBleConnection(uint16_t conn_handle) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_IsBleConnection(conn_handle);
+ }
uint8_t xx;
tACL_CONN* p;
@@ -268,6 +303,10 @@
bool BTM_ReadRemoteConnectionAddr(const RawAddress& pseudo_addr,
RawAddress& conn_addr,
tBLE_ADDR_TYPE* p_addr_type) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_ReadRemoteConnectionAddr(pseudo_addr, conn_addr,
+ p_addr_type);
+ }
bool st = true;
#if (BLE_PRIVACY_SPT == TRUE)
tACL_CONN* p = btm_bda_to_acl(pseudo_addr, BT_TRANSPORT_LE);
@@ -306,6 +345,9 @@
*
******************************************************************************/
void BTM_SecurityGrant(const RawAddress& bd_addr, uint8_t res) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_SecurityGrant(bd_addr, res);
+ }
tSMP_STATUS res_smp =
(res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_REPEATED_ATTEMPTS;
BTM_TRACE_DEBUG("BTM_SecurityGrant");
@@ -330,6 +372,9 @@
******************************************************************************/
void BTM_BlePasskeyReply(const RawAddress& bd_addr, uint8_t res,
uint32_t passkey) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_BlePasskeyReply(bd_addr, res, passkey);
+ }
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
tSMP_STATUS res_smp =
(res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_PASSKEY_ENTRY_FAIL;
@@ -357,6 +402,9 @@
*
******************************************************************************/
void BTM_BleConfirmReply(const RawAddress& bd_addr, uint8_t res) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_BleConfirmReply(bd_addr, res);
+ }
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
tSMP_STATUS res_smp =
(res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_PASSKEY_ENTRY_FAIL;
@@ -388,6 +436,9 @@
******************************************************************************/
void BTM_BleOobDataReply(const RawAddress& bd_addr, uint8_t res, uint8_t len,
uint8_t* p_data) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_BleOobDataReply(bd_addr, res, len, p_data);
+ }
tSMP_STATUS res_smp = (res == BTM_SUCCESS) ? SMP_SUCCESS : SMP_OOB_FAIL;
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
@@ -417,6 +468,10 @@
******************************************************************************/
void BTM_BleSecureConnectionOobDataReply(const RawAddress& bd_addr,
uint8_t* p_c, uint8_t* p_r) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_BleSecureConnectionOobDataReply(bd_addr, p_c,
+ p_r);
+ }
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
BTM_TRACE_DEBUG("%s:", __func__);
@@ -453,6 +508,10 @@
*
******************************************************************************/
void BTM_BleSetConnScanParams(uint32_t scan_interval, uint32_t scan_window) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_BleSetConnScanParams(scan_interval,
+ scan_window);
+ }
tBTM_BLE_CB* p_ble_cb = &btm_cb.ble_ctr_cb;
bool new_param = false;
@@ -498,6 +557,10 @@
void BTM_BleSetPrefConnParams(const RawAddress& bd_addr, uint16_t min_conn_int,
uint16_t max_conn_int, uint16_t slave_latency,
uint16_t supervision_tout) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_BleSetPrefConnParams(
+ bd_addr, min_conn_int, max_conn_int, slave_latency, supervision_tout);
+ }
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
BTM_TRACE_API(
@@ -617,6 +680,10 @@
******************************************************************************/
bool BTM_ReadConnectedTransportAddress(RawAddress* remote_bda,
tBT_TRANSPORT transport) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_ReadConnectedTransportAddress(remote_bda,
+ transport);
+ }
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(*remote_bda);
/* if no device can be located, return */
@@ -655,6 +722,9 @@
*
******************************************************************************/
void BTM_BleReceiverTest(uint8_t rx_freq, tBTM_CMPL_CB* p_cmd_cmpl_cback) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_BleReceiverTest(rx_freq, p_cmd_cmpl_cback);
+ }
btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
btsnd_hcic_ble_receiver_test(rx_freq);
@@ -676,6 +746,10 @@
void BTM_BleTransmitterTest(uint8_t tx_freq, uint8_t test_data_len,
uint8_t packet_payload,
tBTM_CMPL_CB* p_cmd_cmpl_cback) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_BleTransmitterTest(
+ tx_freq, test_data_len, packet_payload, p_cmd_cmpl_cback);
+ }
btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
btsnd_hcic_ble_transmitter_test(tx_freq, test_data_len, packet_payload);
}
@@ -691,6 +765,9 @@
*
******************************************************************************/
void BTM_BleTestEnd(tBTM_CMPL_CB* p_cmd_cmpl_cback) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_BleTestEnd(p_cmd_cmpl_cback);
+ }
btm_cb.devcb.p_le_test_cmd_cmpl_cb = p_cmd_cmpl_cback;
btsnd_hcic_ble_test_end();
@@ -720,6 +797,9 @@
*
******************************************************************************/
bool BTM_UseLeLink(const RawAddress& bd_addr) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_UseLeLink(bd_addr);
+ }
tACL_CONN* p;
tBT_DEVICE_TYPE dev_type;
tBLE_ADDR_TYPE addr_type;
@@ -751,6 +831,9 @@
******************************************************************************/
tBTM_STATUS BTM_SetBleDataLength(const RawAddress& bd_addr,
uint16_t tx_pdu_length) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_SetBleDataLength(bd_addr, tx_pdu_length);
+ }
tACL_CONN* p_acl = btm_bda_to_acl(bd_addr, BT_TRANSPORT_LE);
uint16_t tx_time = BTM_BLE_DATA_TX_TIME_MAX_LEGACY;
@@ -819,6 +902,9 @@
void BTM_BleReadPhy(
const RawAddress& bd_addr,
base::Callback<void(uint8_t tx_phy, uint8_t rx_phy, uint8_t status)> cb) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_BleReadPhy(bd_addr, cb);
+ }
BTM_TRACE_DEBUG("%s", __func__);
tACL_CONN* p_acl = btm_bda_to_acl(bd_addr, BT_TRANSPORT_LE);
@@ -866,6 +952,9 @@
******************************************************************************/
tBTM_STATUS BTM_BleSetDefaultPhy(uint8_t all_phys, uint8_t tx_phys,
uint8_t rx_phys) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_BleSetDefaultPhy(all_phys, tx_phys, rx_phys);
+ }
BTM_TRACE_DEBUG("%s: all_phys = 0x%02x, tx_phys = 0x%02x, rx_phys = 0x%02x",
__func__, all_phys, tx_phys, rx_phys);
@@ -905,6 +994,10 @@
******************************************************************************/
void BTM_BleSetPhy(const RawAddress& bd_addr, uint8_t tx_phys, uint8_t rx_phys,
uint16_t phy_options) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_BleSetPhy(bd_addr, tx_phys, rx_phys,
+ phy_options);
+ }
tACL_CONN* p_acl = btm_bda_to_acl(bd_addr, BT_TRANSPORT_LE);
if (p_acl == NULL) {
@@ -1670,7 +1763,9 @@
if (p_dev_rec->p_callback && enc_cback) {
if (encr_enable)
btm_sec_dev_rec_cback_event(p_dev_rec, BTM_SUCCESS, true);
- else if (p_dev_rec->role_master)
+ else if (p_dev_rec->sec_flags & ~BTM_SEC_LE_LINK_KEY_KNOWN) {
+ btm_sec_dev_rec_cback_event(p_dev_rec, BTM_FAILED_ON_SECURITY, true);
+ } else if (p_dev_rec->role_master)
btm_sec_dev_rec_cback_event(p_dev_rec, BTM_ERR_PROCESSING, true);
}
/* to notify GATT to send data if any request is pending */
@@ -2033,6 +2128,10 @@
******************************************************************************/
bool BTM_BleDataSignature(const RawAddress& bd_addr, uint8_t* p_text,
uint16_t len, BLE_SIGNATURE signature) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_BleDataSignature(bd_addr, p_text, len,
+ signature);
+ }
tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bd_addr);
BTM_TRACE_DEBUG("%s", __func__);
@@ -2091,6 +2190,10 @@
******************************************************************************/
bool BTM_BleVerifySignature(const RawAddress& bd_addr, uint8_t* p_orig,
uint16_t len, uint32_t counter, uint8_t* p_comp) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_BleVerifySignature(bd_addr, p_orig, len,
+ counter, p_comp);
+ }
bool verified = false;
tBTM_SEC_DEV_REC* p_rec = btm_find_dev(bd_addr);
uint8_t p_mac[BTM_CMAC_TLEN_SIZE];
@@ -2128,6 +2231,10 @@
bool BTM_GetLeSecurityState(const RawAddress& bd_addr,
uint8_t* p_le_dev_sec_flags,
uint8_t* p_le_key_size) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_GetLeSecurityState(bd_addr, p_le_dev_sec_flags,
+ p_le_key_size);
+ }
tBTM_SEC_DEV_REC* p_dev_rec;
uint16_t dev_rec_sec_flags;
@@ -2184,6 +2291,9 @@
*
******************************************************************************/
bool BTM_BleSecurityProcedureIsRunning(const RawAddress& bd_addr) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_BleSecurityProcedureIsRunning(bd_addr);
+ }
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
if (p_dev_rec == NULL) {
@@ -2208,6 +2318,9 @@
*
******************************************************************************/
extern uint8_t BTM_BleGetSupportedKeySize(const RawAddress& bd_addr) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_BleGetSupportedKeySize(bd_addr);
+ }
#if (L2CAP_LE_COC_INCLUDED == TRUE)
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev(bd_addr);
tBTM_LE_EVT_DATA btm_le_evt_data;
diff --git a/stack/btm/btm_ble_adv_filter.cc b/stack/btm/btm_ble_adv_filter.cc
index f69f1a2..708e7c2 100644
--- a/stack/btm/btm_ble_adv_filter.cc
+++ b/stack/btm/btm_ble_adv_filter.cc
@@ -316,7 +316,7 @@
/* send local name filter */
btu_hcif_send_cmd_with_cb(
- FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param, len,
+ FROM_HERE, HCI_BLE_ADV_FILTER, param, len,
base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_LOCAL_NAME, cb));
memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
@@ -379,7 +379,7 @@
}
btu_hcif_send_cmd_with_cb(
- FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param, len,
+ FROM_HERE, HCI_BLE_ADV_FILTER, param, len,
base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_MANU_DATA, cb));
memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
@@ -417,7 +417,7 @@
}
btu_hcif_send_cmd_with_cb(
- FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param, len,
+ FROM_HERE, HCI_BLE_ADV_FILTER, param, len,
base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_SRVC_DATA, cb));
memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
@@ -520,7 +520,7 @@
/* send address filter */
btu_hcif_send_cmd_with_cb(
- FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param, len,
+ FROM_HERE, HCI_BLE_ADV_FILTER, param, len,
base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_ADDR, cb));
memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
@@ -591,7 +591,7 @@
}
/* send UUID filter update */
- btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param, len,
+ btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_ADV_FILTER, param, len,
base::Bind(&btm_flt_update_cb, evt_type, cb));
memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
}
@@ -716,7 +716,7 @@
UINT8_TO_STREAM(p, BTM_BLE_PF_LOGIC_OR);
btu_hcif_send_cmd_with_cb(
- FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param, len,
+ FROM_HERE, HCI_BLE_ADV_FILTER, param, len,
base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_FEAT_SEL, cb));
memset(&btm_ble_adv_filt_cb.cur_filter_target, 0, sizeof(tBLE_BD_ADDR));
@@ -801,7 +801,7 @@
BTM_BLE_ADV_FILT_TRACK_NUM;
btu_hcif_send_cmd_with_cb(
- FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param, len,
+ FROM_HERE, HCI_BLE_ADV_FILTER, param, len,
base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_FEAT_SEL, cb));
} else if (BTM_BLE_SCAN_COND_DELETE == action) {
/* select feature based on control block settings */
@@ -811,7 +811,7 @@
UINT8_TO_STREAM(p, filt_index);
btu_hcif_send_cmd_with_cb(
- FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param,
+ FROM_HERE, HCI_BLE_ADV_FILTER, param,
(uint8_t)(BTM_BLE_ADV_FILT_META_HDR_LENGTH),
base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_FEAT_SEL, cb));
} else if (BTM_BLE_SCAN_COND_CLEAR == action) {
@@ -823,7 +823,7 @@
UINT8_TO_STREAM(p, BTM_BLE_SCAN_COND_CLEAR);
btu_hcif_send_cmd_with_cb(
- FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param,
+ FROM_HERE, HCI_BLE_ADV_FILTER, param,
(uint8_t)(BTM_BLE_ADV_FILT_META_HDR_LENGTH - 1),
base::Bind(&btm_flt_update_cb, BTM_BLE_META_PF_FEAT_SEL, cb));
}
@@ -874,7 +874,7 @@
UINT8_TO_STREAM(p, BTM_BLE_META_PF_ENABLE);
UINT8_TO_STREAM(p, enable);
- btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_ADV_FILTER_OCF, param,
+ btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_ADV_FILTER, param,
BTM_BLE_PCF_ENABLE_LEN,
base::Bind(&enable_cmpl_cback, p_stat_cback));
}
diff --git a/stack/btm/btm_ble_batchscan.cc b/stack/btm/btm_ble_batchscan.cc
index 89b3e6c..f7d5d3c5 100644
--- a/stack/btm/btm_ble_batchscan.cc
+++ b/stack/btm/btm_ble_batchscan.cc
@@ -240,7 +240,7 @@
UINT8_TO_STREAM(pp, BTM_BLE_BATCH_SCAN_READ_RESULTS);
UINT8_TO_STREAM(pp, scan_mode);
- btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN_OCF, param, len, cb);
+ btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN, param, len, cb);
}
/* read reports. data is accumulated in |data_all|, number of records is
@@ -311,7 +311,7 @@
UINT8_TO_STREAM(pp, batch_scan_trunc_max);
UINT8_TO_STREAM(pp, batch_scan_notify_threshold);
- btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN_OCF, param, len, cb);
+ btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN, param, len, cb);
}
/* This function writes the batch scan params in controller */
@@ -336,7 +336,7 @@
UINT8_TO_STREAM(p, addr_type);
UINT8_TO_STREAM(p, discard_rule);
- btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN_OCF, param, len, cb);
+ btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN, param, len, cb);
}
/* This function enables the customer specific feature in controller */
@@ -349,7 +349,7 @@
UINT8_TO_STREAM(p, BTM_BLE_BATCH_SCAN_ENB_DISAB_CUST_FEATURE);
UINT8_TO_STREAM(p, 0x01 /* enable */);
- btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN_OCF, param, len, cb);
+ btu_hcif_send_cmd_with_cb(FROM_HERE, HCI_BLE_BATCH_SCAN, param, len, cb);
}
} // namespace
diff --git a/stack/btm/btm_ble_bgconn.cc b/stack/btm/btm_ble_bgconn.cc
index 209f49f..dbeb103 100644
--- a/stack/btm/btm_ble_bgconn.cc
+++ b/stack/btm/btm_ble_bgconn.cc
@@ -311,6 +311,14 @@
BTM_TRACE_DEBUG("%s white_list_size = %d", __func__, white_list_size);
}
+uint8_t BTM_GetWhiteListSize() {
+ const controller_t* controller = controller_get_interface();
+ if (!controller->supports_ble()) {
+ return 0;
+ }
+ return controller->get_ble_white_list_size();
+}
+
bool BTM_SetLeConnectionModeToFast() {
VLOG(2) << __func__;
tBTM_BLE_CB* p_cb = &btm_cb.ble_ctr_cb;
diff --git a/stack/btm/btm_ble_bgconn.h b/stack/btm/btm_ble_bgconn.h
index 45ab2ec..407f513 100644
--- a/stack/btm/btm_ble_bgconn.h
+++ b/stack/btm/btm_ble_bgconn.h
@@ -25,6 +25,9 @@
/** Removes the device from white list */
extern void BTM_WhiteListRemove(const RawAddress& address);
+/** Get max white list size supports of the Bluetooth controller */
+extern uint8_t BTM_GetWhiteListSize();
+
/** Clear the whitelist, end any pending whitelist connections */
extern void BTM_WhiteListClear();
@@ -37,4 +40,4 @@
/* Use slow scan window/interval for LE connection establishment.
* This does not send any requests to controller, instead it changes the
* parameters that will be used after next add/remove request */
-extern void BTM_SetLeConnectionModeToSlow();
\ No newline at end of file
+extern void BTM_SetLeConnectionModeToSlow();
diff --git a/stack/btm/btm_ble_cont_energy.cc b/stack/btm/btm_ble_cont_energy.cc
index 4e87308..23fe709 100644
--- a/stack/btm/btm_ble_cont_energy.cc
+++ b/stack/btm/btm_ble_cont_energy.cc
@@ -93,7 +93,7 @@
}
ble_energy_info_cb.p_ener_cback = p_ener_cback;
- BTM_VendorSpecificCommand(HCI_BLE_ENERGY_INFO_OCF, 0, NULL,
+ BTM_VendorSpecificCommand(HCI_BLE_ENERGY_INFO, 0, NULL,
btm_ble_cont_energy_cmpl_cback);
return BTM_CMD_STARTED;
}
diff --git a/stack/btm/btm_ble_gap.cc b/stack/btm/btm_ble_gap.cc
index 05cac15..3bb29d1 100644
--- a/stack/btm/btm_ble_gap.cc
+++ b/stack/btm/btm_ble_gap.cc
@@ -475,7 +475,7 @@
*
* Function btm_vsc_brcm_features_complete
*
- * Description Command Complete callback for HCI_BLE_VENDOR_CAP_OCF
+ * Description Command Complete callback for HCI_BLE_VENDOR_CAP
*
* Returns void
*
@@ -488,7 +488,7 @@
BTM_TRACE_DEBUG("%s", __func__);
/* Check status of command complete event */
- CHECK(p_vcs_cplt_params->opcode == HCI_BLE_VENDOR_CAP_OCF);
+ CHECK(p_vcs_cplt_params->opcode == HCI_BLE_VENDOR_CAP);
CHECK(p_vcs_cplt_params->param_len > 0);
p = p_vcs_cplt_params->p_param_buf;
@@ -498,7 +498,7 @@
BTM_TRACE_DEBUG("%s: Status = 0x%02x (0 is success)", __func__, status);
return;
}
- CHECK(p_vcs_cplt_params->param_len > BTM_VSC_CHIP_CAPABILITY_RSP_LEN);
+ CHECK(p_vcs_cplt_params->param_len >= BTM_VSC_CHIP_CAPABILITY_RSP_LEN);
STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.adv_inst_max, p);
STREAM_TO_UINT8(btm_cb.cmn_ble_vsc_cb.rpa_offloading, p);
STREAM_TO_UINT16(btm_cb.cmn_ble_vsc_cb.tot_scan_results_strg, p);
@@ -587,7 +587,7 @@
BTM_TRACE_DEBUG("BTM_BleReadControllerFeatures");
p_ctrl_le_feature_rd_cmpl_cback = p_vsc_cback;
- BTM_VendorSpecificCommand(HCI_BLE_VENDOR_CAP_OCF, 0, NULL,
+ BTM_VendorSpecificCommand(HCI_BLE_VENDOR_CAP, 0, NULL,
btm_ble_vendor_capability_vsc_cmpl_cback);
}
#else
diff --git a/stack/btm/btm_ble_multi_adv.cc b/stack/btm/btm_ble_multi_adv.cc
index 22d2e17..120b384 100644
--- a/stack/btm/btm_ble_multi_adv.cc
+++ b/stack/btm/btm_ble_multi_adv.cc
@@ -170,7 +170,7 @@
weak_factory_.GetWeakPtr()));
}
- ~BleAdvertisingManagerImpl() { adv_inst.clear(); }
+ ~BleAdvertisingManagerImpl() override { adv_inst.clear(); }
void GetOwnAddress(uint8_t inst_id, GetAddressCallback cb) override {
cb.Run(adv_inst[inst_id].own_address_type, adv_inst[inst_id].own_address);
diff --git a/stack/btm/btm_devctl.cc b/stack/btm/btm_devctl.cc
index bc3fb56..5d4a4aa 100644
--- a/stack/btm/btm_devctl.cc
+++ b/stack/btm/btm_devctl.cc
@@ -43,6 +43,9 @@
#include "stack/gatt/connection_manager.h"
#include "gatt_int.h"
+#include "main/shim/btm_api.h"
+#include "main/shim/controller.h"
+#include "main/shim/shim.h"
extern bluetooth::common::MessageLoopThread bt_startup_thread;
@@ -231,8 +234,13 @@
/* Clear the callback, so application would not hang on reset */
btm_db_reset();
- module_start_up_callbacked_wrapper(get_module(CONTROLLER_MODULE),
- &bt_startup_thread, reset_complete);
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ module_start_up_callbacked_wrapper(get_module(GD_CONTROLLER_MODULE),
+ &bt_startup_thread, reset_complete);
+ } else {
+ module_start_up_callbacked_wrapper(get_module(CONTROLLER_MODULE),
+ &bt_startup_thread, reset_complete);
+ }
}
/*******************************************************************************
@@ -272,6 +280,7 @@
******************************************************************************/
static void btm_decode_ext_features_page(uint8_t page_number,
const uint8_t* p_features) {
+ CHECK(p_features != nullptr);
BTM_TRACE_DEBUG("btm_decode_ext_features_page page: %d", page_number);
switch (page_number) {
/* Extended (Legacy) Page 0 */
diff --git a/stack/btm/btm_inq.cc b/stack/btm/btm_inq.cc
index 1a5d7f5..aaadd2b 100644
--- a/stack/btm/btm_inq.cc
+++ b/stack/btm/btm_inq.cc
@@ -42,6 +42,8 @@
#include "btu.h"
#include "hcidefs.h"
#include "hcimsgs.h"
+#include "main/shim/btm_api.h"
+#include "main/shim/shim.h"
using bluetooth::Uuid;
@@ -142,6 +144,10 @@
******************************************************************************/
tBTM_STATUS BTM_SetDiscoverability(uint16_t inq_mode, uint16_t window,
uint16_t interval) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_SetDiscoverability(inq_mode, window, interval);
+ }
+
uint8_t scan_mode = 0;
uint16_t service_class;
uint8_t* p_cod;
@@ -252,6 +258,10 @@
*
******************************************************************************/
tBTM_STATUS BTM_SetInquiryScanType(uint16_t scan_type) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_SetInquiryScanType(scan_type);
+ }
+
BTM_TRACE_API("BTM_SetInquiryScanType");
if (scan_type != BTM_SCAN_TYPE_STANDARD &&
scan_type != BTM_SCAN_TYPE_INTERLACED)
@@ -285,6 +295,10 @@
*
******************************************************************************/
tBTM_STATUS BTM_SetPageScanType(uint16_t scan_type) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_SetPageScanType(scan_type);
+ }
+
BTM_TRACE_API("BTM_SetPageScanType");
if (scan_type != BTM_SCAN_TYPE_STANDARD &&
scan_type != BTM_SCAN_TYPE_INTERLACED)
@@ -321,6 +335,10 @@
*
******************************************************************************/
tBTM_STATUS BTM_SetInquiryMode(uint8_t mode) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_SetInquiryMode(mode);
+ }
+
const controller_t* controller = controller_get_interface();
BTM_TRACE_API("BTM_SetInquiryMode");
if (mode == BTM_INQ_RESULT_STANDARD) {
@@ -356,6 +374,10 @@
*
******************************************************************************/
uint16_t BTM_ReadDiscoverability(uint16_t* p_window, uint16_t* p_interval) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_ReadDiscoverability(p_window, p_interval);
+ }
+
BTM_TRACE_API("BTM_ReadDiscoverability");
if (p_window) *p_window = btm_cb.btm_inq_vars.inq_scan_window;
@@ -405,6 +427,11 @@
tBTM_STATUS BTM_SetPeriodicInquiryMode(tBTM_INQ_PARMS* p_inqparms,
uint16_t max_delay, uint16_t min_delay,
tBTM_INQ_RESULTS_CB* p_results_cb) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_SetPeriodicInquiryMode(p_inqparms, max_delay,
+ min_delay, p_results_cb);
+ }
+
tBTM_STATUS status;
tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
@@ -492,6 +519,10 @@
*
******************************************************************************/
tBTM_STATUS BTM_CancelPeriodicInquiry(void) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_CancelPeriodicInquiry();
+ }
+
tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
tBTM_STATUS status = BTM_SUCCESS;
BTM_TRACE_API("BTM_CancelPeriodicInquiry called");
@@ -534,6 +565,10 @@
******************************************************************************/
tBTM_STATUS BTM_SetConnectability(uint16_t page_mode, uint16_t window,
uint16_t interval) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_SetConnectability(page_mode, window, interval);
+ }
+
uint8_t scan_mode = 0;
tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
@@ -608,6 +643,10 @@
*
******************************************************************************/
uint16_t BTM_ReadConnectability(uint16_t* p_window, uint16_t* p_interval) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_ReadConnectability(p_window, p_interval);
+ }
+
BTM_TRACE_API("BTM_ReadConnectability");
if (p_window) *p_window = btm_cb.btm_inq_vars.page_scan_window;
@@ -630,6 +669,10 @@
*
******************************************************************************/
uint16_t BTM_IsInquiryActive(void) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_IsInquiryActive();
+ }
+
BTM_TRACE_API("BTM_IsInquiryActive");
return (btm_cb.btm_inq_vars.inq_active);
@@ -647,6 +690,10 @@
*
******************************************************************************/
tBTM_STATUS BTM_CancelInquiry(void) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_CancelInquiry();
+ }
+
tBTM_STATUS status = BTM_SUCCESS;
tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
BTM_TRACE_API("BTM_CancelInquiry called");
@@ -733,6 +780,19 @@
tBTM_CMPL_CB* p_cmpl_cb) {
tBTM_INQUIRY_VAR_ST* p_inq = &btm_cb.btm_inq_vars;
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ p_inq->state = BTM_INQ_ACTIVE_STATE;
+ p_inq->p_inq_cmpl_cb = p_cmpl_cb;
+ p_inq->p_inq_results_cb = p_results_cb;
+ p_inq->inq_cmpl_info.num_resp = 0; /* Clear the results counter */
+ p_inq->inq_active = p_inqparms->mode;
+
+ btm_acl_update_busy_level(BTM_BLI_INQ_EVT);
+
+ return bluetooth::shim::BTM_StartInquiry(p_inqparms, p_results_cb,
+ p_cmpl_cb);
+ }
+
BTM_TRACE_API("BTM_StartInquiry: mode: %d, dur: %d, rsps: %d, flt: %d",
p_inqparms->mode, p_inqparms->duration, p_inqparms->max_resps,
p_inqparms->filter_cond_type);
@@ -878,6 +938,11 @@
tBTM_STATUS BTM_ReadRemoteDeviceName(const RawAddress& remote_bda,
tBTM_CMPL_CB* p_cb,
tBT_TRANSPORT transport) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_ReadRemoteDeviceName(remote_bda, p_cb,
+ transport);
+ }
+
VLOG(1) << __func__ << ": bd addr " << remote_bda;
/* Use LE transport when LE is the only available option */
if (transport == BT_TRANSPORT_LE) {
@@ -1039,6 +1104,10 @@
*
******************************************************************************/
tBTM_STATUS BTM_ReadInquiryRspTxPower(tBTM_CMPL_CB* p_cb) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::BTM_ReadInquiryRspTxPower(p_cb);
+ }
+
if (btm_cb.devcb.p_inq_tx_power_cmpl_cb) return (BTM_BUSY);
btm_cb.devcb.p_inq_tx_power_cmpl_cb = p_cb;
@@ -1655,7 +1724,6 @@
}
p_i = btm_inq_db_find(bda);
-
/* Only process the num_resp is smaller than max_resps.
If results are queued to BTU task while canceling inquiry,
or when more than one result is in this response, > max_resp
@@ -1675,8 +1743,8 @@
/* Check if this address has already been processed for this inquiry */
if (btm_inq_find_bdaddr(bda)) {
- /* BTM_TRACE_DEBUG("BDA seen before [%02x%02x %02x%02x %02x%02x]",
- bda[0], bda[1], bda[2], bda[3], bda[4], bda[5]);*/
+ /* BTM_TRACE_DEBUG("BDA seen before %s", bda.ToString().c_str()); */
+
/* By default suppose no update needed */
i_rssi = (int8_t)rssi;
@@ -1783,9 +1851,12 @@
p_eir_data = NULL;
/* If a callback is registered, call it with the results */
- if (p_inq_results_cb)
+ if (p_inq_results_cb) {
(p_inq_results_cb)((tBTM_INQ_RESULTS*)p_cur, p_eir_data,
HCI_EXT_INQ_RESPONSE_LEN);
+ } else {
+ BTM_TRACE_DEBUG("No callback is registered");
+ }
}
}
}
diff --git a/stack/btm/btm_sec.cc b/stack/btm/btm_sec.cc
index 1ff4eed..935903d 100644
--- a/stack/btm/btm_sec.cc
+++ b/stack/btm/btm_sec.cc
@@ -3774,6 +3774,7 @@
tBTM_PAIRING_STATE old_state = btm_cb.pairing_state;
tBTM_SEC_DEV_REC* p_dev_rec = btm_find_dev_by_handle(handle);
bool are_bonding = false;
+ bool was_authenticating = false;
if (p_dev_rec) {
VLOG(2) << __func__ << ": Security Manager: in state: "
@@ -3814,16 +3815,35 @@
if (!p_dev_rec) return;
- if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
- (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) &&
- (p_dev_rec->bd_addr == btm_cb.pairing_bda))
- are_bonding = true;
+ if (p_dev_rec->sec_state == BTM_SEC_STATE_AUTHENTICATING) {
+ p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
+ was_authenticating = true;
+ /* There can be a race condition, when we are starting authentication
+ * and the peer device is doing encryption.
+ * If first we receive encryption change up, then initiated
+ * authentication can not be performed.
+ * According to the spec we can not do authentication on the
+ * encrypted link, so device is correct.
+ */
+ if ((status == HCI_ERR_COMMAND_DISALLOWED) &&
+ ((p_dev_rec->sec_flags & (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED)) ==
+ (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED))) {
+ status = HCI_SUCCESS;
+ }
+ if (status == HCI_SUCCESS) {
+ p_dev_rec->sec_flags |= BTM_SEC_AUTHENTICATED;
+ }
+ }
if ((btm_cb.pairing_state != BTM_PAIR_STATE_IDLE) &&
- (p_dev_rec->bd_addr == btm_cb.pairing_bda))
+ (p_dev_rec->bd_addr == btm_cb.pairing_bda)) {
+ if (btm_cb.pairing_flags & BTM_PAIR_FLAGS_WE_STARTED_DD) {
+ are_bonding = true;
+ }
btm_sec_change_pairing_state(BTM_PAIR_STATE_IDLE);
+ }
- if (p_dev_rec->sec_state != BTM_SEC_STATE_AUTHENTICATING) {
+ if (was_authenticating == false) {
if ((btm_cb.api.p_auth_complete_callback && status != HCI_SUCCESS) &&
(old_state != BTM_PAIR_STATE_IDLE)) {
(*btm_cb.api.p_auth_complete_callback)(p_dev_rec->bd_addr,
@@ -3833,17 +3853,6 @@
return;
}
- /* There can be a race condition, when we are starting authentication and
- ** the peer device is doing encryption.
- ** If first we receive encryption change up, then initiated authentication
- ** can not be performed. According to the spec we can not do authentication
- ** on the encrypted link, so device is correct.
- */
- if ((status == HCI_ERR_COMMAND_DISALLOWED) &&
- ((p_dev_rec->sec_flags & (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED)) ==
- (BTM_SEC_AUTHENTICATED | BTM_SEC_ENCRYPTED))) {
- status = HCI_SUCCESS;
- }
/* Currently we do not notify user if it is a keyboard which connects */
/* User probably Disabled the keyboard while it was asleap. Let her try */
if (btm_cb.api.p_auth_complete_callback) {
@@ -3854,8 +3863,6 @@
p_dev_rec->sec_bd_name, status);
}
- p_dev_rec->sec_state = BTM_SEC_STATE_IDLE;
-
/* If this is a bonding procedure can disconnect the link now */
if (are_bonding) {
p_dev_rec->security_required &= ~BTM_SEC_OUT_AUTHENTICATE;
@@ -3901,8 +3908,6 @@
return;
}
- p_dev_rec->sec_flags |= BTM_SEC_AUTHENTICATED;
-
if (p_dev_rec->pin_code_length >= 16 ||
p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB ||
p_dev_rec->link_key_type == BTM_LKEY_TYPE_AUTH_COMB_P_256) {
diff --git a/stack/btu/btu_hcif.cc b/stack/btu/btu_hcif.cc
index 4612422..2035cc6 100644
--- a/stack/btu/btu_hcif.cc
+++ b/stack/btu/btu_hcif.cc
@@ -57,6 +57,7 @@
using base::Location;
extern void btm_process_cancel_complete(uint8_t status, uint8_t mode);
+extern void btm_process_inq_results2(uint8_t* p, uint8_t inq_res_mode);
extern void btm_ble_test_command_complete(uint8_t* p);
extern void smp_cancel_start_encryption_attempt();
diff --git a/stack/btu/btu_task.cc b/stack/btu/btu_task.cc
index 49c9697..8838206 100644
--- a/stack/btu/btu_task.cc
+++ b/stack/btu/btu_task.cc
@@ -71,6 +71,11 @@
btu_hcif_send_cmd((uint8_t)(p_msg->event & BT_SUB_EVT_MASK), p_msg);
break;
+ case BT_EVT_TO_BTU_HCI_ISO:
+ // TODO: implement handler
+ osi_free(p_msg);
+ break;
+
default:
osi_free(p_msg);
break;
diff --git a/stack/crypto_toolbox/aes_cmac.cc b/stack/crypto_toolbox/aes_cmac.cc
index 8b8246e..72b07bd 100644
--- a/stack/crypto_toolbox/aes_cmac.cc
+++ b/stack/crypto_toolbox/aes_cmac.cc
@@ -38,7 +38,7 @@
uint16_t round;
} tCMAC_CB;
-tCMAC_CB cmac_cb;
+thread_local tCMAC_CB cmac_cb;
/* Rb for AES-128 as block cipher, LSB as [0] */
Octet16 const_Rb{0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
diff --git a/stack/crypto_toolbox/crypto_toolbox.cc b/stack/crypto_toolbox/crypto_toolbox.cc
index ae33bd9..d5c8e5d 100644
--- a/stack/crypto_toolbox/crypto_toolbox.cc
+++ b/stack/crypto_toolbox/crypto_toolbox.cc
@@ -34,7 +34,7 @@
return aes_cmac(salt, w.data(), w.size());
}
-Octet16 f4(uint8_t* u, uint8_t* v, const Octet16& x, uint8_t z) {
+Octet16 f4(const uint8_t* u, const uint8_t* v, const Octet16& x, uint8_t z) {
constexpr size_t msg_len = BT_OCTET32_LEN /* U size */ +
BT_OCTET32_LEN /* V size */ + 1 /* Z size */;
@@ -73,7 +73,7 @@
return aes_cmac(t, msg.data(), msg.size());
}
-void f5(uint8_t* w, const Octet16& n1, const Octet16& n2, uint8_t* a1,
+void f5(const uint8_t* w, const Octet16& n1, const Octet16& n2, uint8_t* a1,
uint8_t* a2, Octet16* mac_key, Octet16* ltk) {
DVLOG(2) << __func__ << "W=" << HexEncode(w, BT_OCTET32_LEN)
<< ", N1=" << HexEncode(n1.data(), n1.size())
@@ -123,7 +123,8 @@
return aes_cmac(w, msg.data(), msg.size());
}
-uint32_t g2(uint8_t* u, uint8_t* v, const Octet16& x, const Octet16& y) {
+uint32_t g2(const uint8_t* u, const uint8_t* v, const Octet16& x,
+ const Octet16& y) {
constexpr size_t msg_len = BT_OCTET32_LEN /* U size */ +
BT_OCTET32_LEN /* V size */
+ OCTET16_LEN /* Y size */;
diff --git a/stack/crypto_toolbox/crypto_toolbox.h b/stack/crypto_toolbox/crypto_toolbox.h
index 90d7392..b445fa2 100644
--- a/stack/crypto_toolbox/crypto_toolbox.h
+++ b/stack/crypto_toolbox/crypto_toolbox.h
@@ -23,14 +23,16 @@
extern Octet16 aes_128(const Octet16& key, const Octet16& message);
extern Octet16 aes_cmac(const Octet16& key, const uint8_t* message,
uint16_t length);
-extern Octet16 f4(uint8_t* u, uint8_t* v, const Octet16& x, uint8_t z);
-extern void f5(uint8_t* w, const Octet16& n1, const Octet16& n2, uint8_t* a1,
- uint8_t* a2, Octet16* mac_key, Octet16* ltk);
+extern Octet16 f4(const uint8_t* u, const uint8_t* v, const Octet16& x,
+ uint8_t z);
+extern void f5(const uint8_t* w, const Octet16& n1, const Octet16& n2,
+ uint8_t* a1, uint8_t* a2, Octet16* mac_key, Octet16* ltk);
extern Octet16 f6(const Octet16& w, const Octet16& n1, const Octet16& n2,
const Octet16& r, uint8_t* iocap, uint8_t* a1, uint8_t* a2);
extern Octet16 h6(const Octet16& w, std::array<uint8_t, 4> keyid);
extern Octet16 h7(const Octet16& salt, const Octet16& w);
-extern uint32_t g2(uint8_t* u, uint8_t* v, const Octet16& x, const Octet16& y);
+extern uint32_t g2(const uint8_t* u, const uint8_t* v, const Octet16& x,
+ const Octet16& y);
extern Octet16 ltk_to_link_key(const Octet16& ltk, bool use_h7);
extern Octet16 link_key_to_ltk(const Octet16& link_key, bool use_h7);
diff --git a/stack/gap/gap_ble.cc b/stack/gap/gap_ble.cc
index cce62d4..e71238f 100644
--- a/stack/gap/gap_ble.cc
+++ b/stack/gap/gap_ble.cc
@@ -411,23 +411,26 @@
Uuid addr_res_uuid = Uuid::From16Bit(GATT_UUID_GAP_CENTRAL_ADDR_RESOL);
btgatt_db_element_t service[] = {
- {.type = BTGATT_DB_PRIMARY_SERVICE, .uuid = svc_uuid},
- {.type = BTGATT_DB_CHARACTERISTIC,
- .uuid = name_uuid,
+ {
+ .uuid = svc_uuid,
+ .type = BTGATT_DB_PRIMARY_SERVICE,
+ },
+ {.uuid = name_uuid,
+ .type = BTGATT_DB_CHARACTERISTIC,
.properties = GATT_CHAR_PROP_BIT_READ,
.permissions = GATT_PERM_READ},
- {.type = BTGATT_DB_CHARACTERISTIC,
- .uuid = icon_uuid,
+ {.uuid = icon_uuid,
+ .type = BTGATT_DB_CHARACTERISTIC,
.properties = GATT_CHAR_PROP_BIT_READ,
.permissions = GATT_PERM_READ},
- {.type = BTGATT_DB_CHARACTERISTIC,
- .uuid = addr_res_uuid,
+ {.uuid = addr_res_uuid,
+ .type = BTGATT_DB_CHARACTERISTIC,
.properties = GATT_CHAR_PROP_BIT_READ,
.permissions = GATT_PERM_READ}
#if (BTM_PERIPHERAL_ENABLED == TRUE) /* Only needed for peripheral testing */
,
- {.type = BTGATT_DB_CHARACTERISTIC,
- .uuid = Uuid::From16Bit(GATT_UUID_GAP_PREF_CONN_PARAM),
+ {.uuid = Uuid::From16Bit(GATT_UUID_GAP_PREF_CONN_PARAM),
+ .type = BTGATT_DB_CHARACTERISTIC,
.properties = GATT_CHAR_PROP_BIT_READ,
.permissions = GATT_PERM_READ}
#endif
diff --git a/stack/gatt/connection_manager.cc b/stack/gatt/connection_manager.cc
index cfbb02e..9454be0 100644
--- a/stack/gatt/connection_manager.cc
+++ b/stack/gatt/connection_manager.cc
@@ -267,12 +267,11 @@
void dump(int fd) {
dprintf(fd, "\nconnection_manager state:\n");
if (bgconn_dev.empty()) {
- dprintf(fd, "\n\tno Low Energy connection attempts\n");
+ dprintf(fd, "\tno Low Energy connection attempts\n");
return;
}
- dprintf(fd, "\n\tdevices attempting connection: %d\n",
- (int)bgconn_dev.size());
+ dprintf(fd, "\tdevices attempting connection: %d", (int)bgconn_dev.size());
for (const auto& entry : bgconn_dev) {
dprintf(fd, "\n\t * %s: ", entry.first.ToString().c_str());
@@ -283,13 +282,14 @@
}
}
- if (entry.second.doing_bg_conn.empty()) {
+ if (!entry.second.doing_bg_conn.empty()) {
dprintf(fd, "\n\t\tapps doing background connect: ");
for (const auto& id : entry.second.doing_bg_conn) {
dprintf(fd, "%d, ", id);
}
}
}
+ dprintf(fd, "\n");
}
} // namespace connection_manager
diff --git a/stack/gatt/gatt_api.cc b/stack/gatt/gatt_api.cc
index 37bc614..5fe9a37 100644
--- a/stack/gatt/gatt_api.cc
+++ b/stack/gatt/gatt_api.cc
@@ -708,6 +708,7 @@
p_clcb->op_subtype = type;
p_clcb->auth_req = p_read->by_handle.auth_req;
p_clcb->counter = 0;
+ p_clcb->read_req_current_mtu = p_tcb->payload_size;
switch (type) {
case GATT_READ_BY_TYPE:
diff --git a/stack/gatt/gatt_attr.cc b/stack/gatt/gatt_attr.cc
index 8861a7a..1acfd81 100644
--- a/stack/gatt/gatt_attr.cc
+++ b/stack/gatt/gatt_attr.cc
@@ -285,11 +285,16 @@
Uuid char_uuid = Uuid::From16Bit(GATT_UUID_GATT_SRV_CHGD);
btgatt_db_element_t service[] = {
- {.type = BTGATT_DB_PRIMARY_SERVICE, .uuid = service_uuid},
- {.type = BTGATT_DB_CHARACTERISTIC,
- .uuid = char_uuid,
- .properties = GATT_CHAR_PROP_BIT_INDICATE,
- .permissions = 0}};
+ {
+ .uuid = service_uuid,
+ .type = BTGATT_DB_PRIMARY_SERVICE,
+ },
+ {
+ .uuid = char_uuid,
+ .type = BTGATT_DB_CHARACTERISTIC,
+ .properties = GATT_CHAR_PROP_BIT_INDICATE,
+ .permissions = 0,
+ }};
GATTS_AddService(gatt_cb.gatt_if, service,
sizeof(service) / sizeof(btgatt_db_element_t));
diff --git a/stack/gatt/gatt_cl.cc b/stack/gatt/gatt_cl.cc
index 27a4f4f..6bc01e1 100644
--- a/stack/gatt/gatt_cl.cc
+++ b/stack/gatt/gatt_cl.cc
@@ -913,11 +913,18 @@
memcpy(p_clcb->p_attr_buf + offset, p, len);
- /* send next request if needed */
+ /* full packet for read or read blob rsp */
+ bool packet_is_full;
+ if (tcb.payload_size == p_clcb->read_req_current_mtu) {
+ packet_is_full = (len == (tcb.payload_size - 1));
+ } else {
+ packet_is_full = (len == (p_clcb->read_req_current_mtu - 1) ||
+ len == (tcb.payload_size - 1));
+ p_clcb->read_req_current_mtu = tcb.payload_size;
+ }
- if (len == (tcb.payload_size -
- 1) && /* full packet for read or read blob rsp */
- len + offset < GATT_MAX_ATTR_LEN) {
+ /* send next request if needed */
+ if (packet_is_full && (len + offset < GATT_MAX_ATTR_LEN)) {
VLOG(1) << StringPrintf(
"full pkt issue read blob for remianing bytes old offset=%d "
"len=%d new offset=%d",
diff --git a/stack/gatt/gatt_int.h b/stack/gatt/gatt_int.h
index 2c00fd7..e072a47 100644
--- a/stack/gatt/gatt_int.h
+++ b/stack/gatt/gatt_int.h
@@ -323,6 +323,8 @@
bool in_use;
alarm_t* gatt_rsp_timer_ent; /* peer response timer */
uint8_t retry_count;
+ uint16_t read_req_current_mtu; /* This is the MTU value that the read was
+ initiated with */
};
typedef struct {
diff --git a/stack/include/bt_types.h b/stack/include/bt_types.h
index 7804328..01e8248 100644
--- a/stack/include/bt_types.h
+++ b/stack/include/bt_types.h
@@ -80,6 +80,9 @@
/* HCI command from upper layer */
#define BT_EVT_TO_BTU_HCI_CMD 0x1600
+/* ISO Data from HCI */
+#define BT_EVT_TO_BTU_HCI_ISO 0x1700
+
/* L2CAP segment(s) transmitted */
#define BT_EVT_TO_BTU_L2C_SEG_XMIT 0x1900
@@ -119,6 +122,8 @@
#define BT_EVT_TO_LM_HCI_ACL_ACK 0x2b00
/* LM Diagnostics commands */
#define BT_EVT_TO_LM_DIAG 0x2c00
+/* HCI ISO Data */
+#define BT_EVT_TO_LM_HCI_ISO 0x2d00
#define BT_EVT_TO_BTM_CMDS 0x2f00
#define BT_EVT_TO_BTM_PM_MDCHG_EVT (0x0001 | BT_EVT_TO_BTM_CMDS)
diff --git a/stack/include/btm_api_types.h b/stack/include/btm_api_types.h
old mode 100644
new mode 100755
index 965087c..d14b754
--- a/stack/include/btm_api_types.h
+++ b/stack/include/btm_api_types.h
@@ -611,7 +611,7 @@
constexpr uint8_t PHY_LE_NO_PACKET = 0x00;
constexpr uint8_t PHY_LE_1M = 0x01;
constexpr uint8_t PHY_LE_2M = 0x02;
-constexpr uint8_t PHY_LE_CODED = 0x03;
+constexpr uint8_t PHY_LE_CODED = 0x04;
constexpr uint8_t NO_ADI_PRESENT = 0xFF;
constexpr uint8_t TX_POWER_NOT_PRESENT = 0x7F;
diff --git a/stack/include/hcidefs.h b/stack/include/hcidefs.h
index ef87b5b..22df8af 100644
--- a/stack/include/hcidefs.h
+++ b/stack/include/hcidefs.h
@@ -396,35 +396,35 @@
#define HCI_BLE_WRITE_RF_COMPENS_POWER (0x004D | HCI_GRP_BLE_CMDS)
#define HCI_BLE_SET_PRIVACY_MODE (0x004E | HCI_GRP_BLE_CMDS)
-/* LE Get Vendor Capabilities Command OCF */
-#define HCI_BLE_VENDOR_CAP_OCF (0x0153 | HCI_GRP_VENDOR_SPECIFIC)
+/* LE Get Vendor Capabilities Command opcode */
+#define HCI_BLE_VENDOR_CAP (0x0153 | HCI_GRP_VENDOR_SPECIFIC)
-/* Multi adv OCF */
-#define HCI_BLE_MULTI_ADV_OCF (0x0154 | HCI_GRP_VENDOR_SPECIFIC)
+/* Multi adv opcode */
+#define HCI_BLE_MULTI_ADV (0x0154 | HCI_GRP_VENDOR_SPECIFIC)
-/* Batch scan OCF */
-#define HCI_BLE_BATCH_SCAN_OCF (0x0156 | HCI_GRP_VENDOR_SPECIFIC)
+/* Batch scan opcode */
+#define HCI_BLE_BATCH_SCAN (0x0156 | HCI_GRP_VENDOR_SPECIFIC)
-/* ADV filter OCF */
-#define HCI_BLE_ADV_FILTER_OCF (0x0157 | HCI_GRP_VENDOR_SPECIFIC)
+/* ADV filter opcode */
+#define HCI_BLE_ADV_FILTER (0x0157 | HCI_GRP_VENDOR_SPECIFIC)
-/* Tracking OCF */
-#define HCI_BLE_TRACK_ADV_OCF (0x0158 | HCI_GRP_VENDOR_SPECIFIC)
+/* Tracking opcode */
+#define HCI_BLE_TRACK_ADV (0x0158 | HCI_GRP_VENDOR_SPECIFIC)
-/* Energy info OCF */
-#define HCI_BLE_ENERGY_INFO_OCF (0x0159 | HCI_GRP_VENDOR_SPECIFIC)
+/* Energy info opcode */
+#define HCI_BLE_ENERGY_INFO (0x0159 | HCI_GRP_VENDOR_SPECIFIC)
-/* Extended BLE Scan parameters OCF */
-#define HCI_BLE_EXTENDED_SCAN_PARAMS_OCF (0x015A | HCI_GRP_VENDOR_SPECIFIC)
+/* Extended BLE Scan parameters opcode */
+#define HCI_BLE_EXTENDED_SCAN_PARAMS (0x015A | HCI_GRP_VENDOR_SPECIFIC)
-/* Controller debug info OCF */
-#define HCI_CONTROLLER_DEBUG_INFO_OCF (0x015B | HCI_GRP_VENDOR_SPECIFIC)
+/* Controller debug info opcode */
+#define HCI_CONTROLLER_DEBUG_INFO (0x015B | HCI_GRP_VENDOR_SPECIFIC)
-/* A2DP offload OCF */
-#define HCI_CONTROLLER_A2DP_OPCODE_OCF (0x015D | HCI_GRP_VENDOR_SPECIFIC)
+/* A2DP offload opcode */
+#define HCI_CONTROLLER_A2DP (0x015D | HCI_GRP_VENDOR_SPECIFIC)
-/* Bluetooth Quality Report OCF */
-#define HCI_CONTROLLER_BQR_OPCODE_OCF (0x015E | HCI_GRP_VENDOR_SPECIFIC)
+/* Bluetooth Quality Report opcode */
+#define HCI_CONTROLLER_BQR (0x015E | HCI_GRP_VENDOR_SPECIFIC)
/* subcode for multi adv feature */
#define BTM_BLE_MULTI_ADV_SET_PARAM 0x01
diff --git a/stack/l2cap/l2c_api.cc b/stack/l2cap/l2c_api.cc
index b5a9564..feab995 100644
--- a/stack/l2cap/l2c_api.cc
+++ b/stack/l2cap/l2c_api.cc
@@ -39,6 +39,8 @@
#include "hcimsgs.h"
#include "l2c_int.h"
#include "l2cdefs.h"
+#include "main/shim/l2c_api.h"
+#include "main/shim/shim.h"
#include "osi/include/allocator.h"
#include "osi/include/log.h"
@@ -60,6 +62,10 @@
******************************************************************************/
uint16_t L2CA_Register(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info,
bool enable_snoop) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_Register(psm, p_cb_info, enable_snoop);
+ }
+
tL2C_RCB* p_rcb;
uint16_t vpsm = psm;
@@ -123,6 +129,10 @@
*
******************************************************************************/
void L2CA_Deregister(uint16_t psm) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_Deregister(psm);
+ }
+
tL2C_RCB* p_rcb;
tL2C_CCB* p_ccb;
tL2C_LCB* p_lcb;
@@ -169,6 +179,10 @@
*
******************************************************************************/
uint16_t L2CA_AllocatePSM(void) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_AllocatePSM();
+ }
+
bool done = false;
uint16_t psm = l2cb.dyn_psm;
@@ -204,6 +218,10 @@
*
******************************************************************************/
uint16_t L2CA_AllocateLePSM(void) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_AllocateLePSM();
+ }
+
bool done = false;
uint16_t psm = l2cb.le_dyn_psm;
uint16_t count = 0;
@@ -250,6 +268,10 @@
*
******************************************************************************/
void L2CA_FreeLePSM(uint16_t psm) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_FreeLePSM(psm);
+ }
+
L2CAP_TRACE_API("%s: to free psm=%d", __func__, psm);
if ((psm < LE_DYNAMIC_PSM_START) || (psm > LE_DYNAMIC_PSM_END)) {
@@ -277,6 +299,10 @@
*
******************************************************************************/
uint16_t L2CA_ConnectReq(uint16_t psm, const RawAddress& p_bd_addr) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_ConnectReq(psm, p_bd_addr);
+ }
+
return L2CA_ErtmConnectReq(psm, p_bd_addr, nullptr);
}
@@ -299,6 +325,10 @@
******************************************************************************/
uint16_t L2CA_ErtmConnectReq(uint16_t psm, const RawAddress& p_bd_addr,
tL2CAP_ERTM_INFO* p_ertm_info) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_ErtmConnectReq(psm, p_bd_addr, p_ertm_info);
+ }
+
VLOG(1) << __func__ << "BDA " << p_bd_addr
<< StringPrintf(" PSM: 0x%04x allowed:0x%x preferred:%d", psm,
(p_ertm_info) ? p_ertm_info->allowed_modes : 0,
@@ -400,6 +430,10 @@
*
******************************************************************************/
uint16_t L2CA_RegisterLECoc(uint16_t psm, tL2CAP_APPL_INFO* p_cb_info) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_RegisterLECoc(psm, p_cb_info);
+ }
+
L2CAP_TRACE_API("%s called for LE PSM: 0x%04x", __func__, psm);
/* Verify that the required callback info has been filled in
@@ -464,6 +498,10 @@
*
******************************************************************************/
void L2CA_DeregisterLECoc(uint16_t psm) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_DeregisterLECoc(psm);
+ }
+
L2CAP_TRACE_API("%s called for PSM: 0x%04x", __func__, psm);
tL2C_RCB* p_rcb = l2cu_find_ble_rcb_by_psm(psm);
@@ -510,6 +548,10 @@
******************************************************************************/
uint16_t L2CA_ConnectLECocReq(uint16_t psm, const RawAddress& p_bd_addr,
tL2CAP_LE_CFG_INFO* p_cfg) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_ConnectLECocReq(psm, p_bd_addr, p_cfg);
+ }
+
VLOG(1) << __func__ << " BDA: " << p_bd_addr
<< StringPrintf(" PSM: 0x%04x", psm);
@@ -598,6 +640,11 @@
bool L2CA_ConnectLECocRsp(const RawAddress& p_bd_addr, uint8_t id,
uint16_t lcid, uint16_t result, uint16_t status,
tL2CAP_LE_CFG_INFO* p_cfg) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_ConnectLECocRsp(p_bd_addr, id, lcid, result,
+ status, p_cfg);
+ }
+
VLOG(1) << __func__ << " BDA: " << p_bd_addr
<< StringPrintf(" CID: 0x%04x Result: %d Status: %d", lcid, result,
status);
@@ -656,6 +703,10 @@
*
******************************************************************************/
bool L2CA_GetPeerLECocConfig(uint16_t lcid, tL2CAP_LE_CFG_INFO* peer_cfg) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_GetPeerLECocConfig(lcid, peer_cfg);
+ }
+
L2CAP_TRACE_API("%s CID: 0x%04x", __func__, lcid);
tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(NULL, lcid);
@@ -672,6 +723,10 @@
bool L2CA_SetConnectionCallbacks(uint16_t local_cid,
const tL2CAP_APPL_INFO* callbacks) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_SetConnectionCallbacks(local_cid, callbacks);
+ }
+
CHECK(callbacks != NULL);
CHECK(callbacks->pL2CA_ConnectInd_Cb == NULL);
CHECK(callbacks->pL2CA_ConnectCfm_Cb != NULL);
@@ -721,6 +776,11 @@
******************************************************************************/
bool L2CA_ConnectRsp(const RawAddress& p_bd_addr, uint8_t id, uint16_t lcid,
uint16_t result, uint16_t status) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_ConnectRsp(p_bd_addr, id, lcid, result,
+ status);
+ }
+
return L2CA_ErtmConnectRsp(p_bd_addr, id, lcid, result, status, NULL);
}
@@ -738,6 +798,11 @@
bool L2CA_ErtmConnectRsp(const RawAddress& p_bd_addr, uint8_t id, uint16_t lcid,
uint16_t result, uint16_t status,
tL2CAP_ERTM_INFO* p_ertm_info) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_ErtmConnectRsp(p_bd_addr, id, lcid, result,
+ status, p_ertm_info);
+ }
+
tL2C_LCB* p_lcb;
tL2C_CCB* p_ccb;
@@ -817,6 +882,10 @@
*
******************************************************************************/
bool L2CA_ConfigReq(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_ConfigReq(cid, p_cfg);
+ }
+
tL2C_CCB* p_ccb;
L2CAP_TRACE_API(
@@ -866,6 +935,10 @@
*
******************************************************************************/
bool L2CA_ConfigRsp(uint16_t cid, tL2CAP_CFG_INFO* p_cfg) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_ConfigRsp(cid, p_cfg);
+ }
+
tL2C_CCB* p_ccb;
L2CAP_TRACE_API(
@@ -909,6 +982,10 @@
*
******************************************************************************/
bool L2CA_DisconnectReq(uint16_t cid) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_DisconnectReq(cid);
+ }
+
tL2C_CCB* p_ccb;
L2CAP_TRACE_API("L2CA_DisconnectReq() CID: 0x%04x", cid);
@@ -936,6 +1013,10 @@
*
******************************************************************************/
bool L2CA_DisconnectRsp(uint16_t cid) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_DisconnectRsp(cid);
+ }
+
tL2C_CCB* p_ccb;
L2CAP_TRACE_API("L2CA_DisconnectRsp() CID: 0x%04x", cid);
@@ -962,6 +1043,10 @@
*
******************************************************************************/
bool L2CA_Ping(const RawAddress& p_bd_addr, tL2CA_ECHO_RSP_CB* p_callback) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_Ping(p_bd_addr, p_callback);
+ }
+
tL2C_LCB* p_lcb;
VLOG(1) << __func__ << " BDA: " << p_bd_addr;
@@ -1025,6 +1110,10 @@
******************************************************************************/
bool L2CA_Echo(const RawAddress& p_bd_addr, BT_HDR* p_data,
tL2CA_ECHO_DATA_CB* p_callback) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_Echo(p_bd_addr, p_data, p_callback);
+ }
+
tL2C_LCB* p_lcb;
uint8_t* pp;
@@ -1065,6 +1154,10 @@
}
bool L2CA_GetIdentifiers(uint16_t lcid, uint16_t* rcid, uint16_t* handle) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_GetIdentifiers(lcid, rcid, handle);
+ }
+
tL2C_CCB* control_block = l2cu_find_ccb_by_cid(NULL, lcid);
if (!control_block) return false;
@@ -1094,6 +1187,10 @@
* set up.
******************************************************************************/
bool L2CA_SetIdleTimeout(uint16_t cid, uint16_t timeout, bool is_global) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_SetIdleTimeout(cid, timeout, is_global);
+ }
+
tL2C_CCB* p_ccb;
tL2C_LCB* p_lcb;
@@ -1140,6 +1237,11 @@
******************************************************************************/
bool L2CA_SetIdleTimeoutByBdAddr(const RawAddress& bd_addr, uint16_t timeout,
tBT_TRANSPORT transport) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_SetIdleTimeoutByBdAddr(bd_addr, timeout,
+ transport);
+ }
+
tL2C_LCB* p_lcb;
if (RawAddress::kAny != bd_addr) {
@@ -1200,6 +1302,10 @@
*
******************************************************************************/
uint8_t L2CA_SetDesireRole(uint8_t new_role) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_SetDesireRole(new_role);
+ }
+
L2CAP_TRACE_API("L2CA_SetDesireRole() new:x%x, disallow_switch:%d", new_role,
l2cb.disallow_switch);
@@ -1230,6 +1336,10 @@
******************************************************************************/
uint16_t L2CA_LocalLoopbackReq(uint16_t psm, uint16_t handle,
const RawAddress& p_bd_addr) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_LocalLoopbackReq(psm, handle, p_bd_addr);
+ }
+
tL2C_LCB* p_lcb;
tL2C_CCB* p_ccb;
tL2C_RCB* p_rcb;
@@ -1288,6 +1398,10 @@
*
******************************************************************************/
bool L2CA_SetAclPriority(const RawAddress& bd_addr, uint8_t priority) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_SetAclPriority(bd_addr, priority);
+ }
+
VLOG(1) << __func__ << " BDA: " << bd_addr
<< ", priority: " << std::to_string(priority);
return (l2cu_set_acl_priority(bd_addr, priority, false));
@@ -1305,6 +1419,10 @@
*
******************************************************************************/
bool L2CA_FlowControl(uint16_t cid, bool data_enabled) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_FlowControl(cid, data_enabled);
+ }
+
tL2C_CCB* p_ccb;
bool on_off = !data_enabled;
@@ -1348,6 +1466,10 @@
*
******************************************************************************/
bool L2CA_SendTestSFrame(uint16_t cid, uint8_t sup_type, uint8_t back_track) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_SendTestSFrame(cid, sup_type, back_track);
+ }
+
tL2C_CCB* p_ccb;
L2CAP_TRACE_API(
@@ -1384,6 +1506,10 @@
*
******************************************************************************/
bool L2CA_SetTxPriority(uint16_t cid, tL2CAP_CHNL_PRIORITY priority) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_SetTxPriority(cid, priority);
+ }
+
tL2C_CCB* p_ccb;
L2CAP_TRACE_API("L2CA_SetTxPriority() CID: 0x%04x, priority:%d", cid,
@@ -1414,6 +1540,10 @@
******************************************************************************/
bool L2CA_SetChnlDataRate(uint16_t cid, tL2CAP_CHNL_DATA_RATE tx,
tL2CAP_CHNL_DATA_RATE rx) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_SetChnlDataRate(cid, tx, rx);
+ }
+
tL2C_CCB* p_ccb;
L2CAP_TRACE_API("L2CA_SetChnlDataRate() CID: 0x%04x, tx:%d, rx:%d", cid, tx,
@@ -1461,6 +1591,10 @@
* the ACL link.
******************************************************************************/
bool L2CA_SetFlushTimeout(const RawAddress& bd_addr, uint16_t flush_tout) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_SetFlushTimeout(bd_addr, flush_tout);
+ }
+
tL2C_LCB* p_lcb;
uint16_t hci_flush_to;
uint32_t temp;
@@ -1545,6 +1679,11 @@
******************************************************************************/
bool L2CA_GetPeerFeatures(const RawAddress& bd_addr, uint32_t* p_ext_feat,
uint8_t* p_chnl_mask) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_GetPeerFeatures(bd_addr, p_ext_feat,
+ p_chnl_mask);
+ }
+
tL2C_LCB* p_lcb;
/* We must already have a link to the remote */
@@ -1578,6 +1717,10 @@
*
******************************************************************************/
bool L2CA_GetBDAddrbyHandle(uint16_t handle, RawAddress& bd_addr) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_GetBDAddrbyHandle(handle, bd_addr);
+ }
+
tL2C_LCB* p_lcb = NULL;
bool found_dev = false;
@@ -1602,6 +1745,10 @@
*
******************************************************************************/
uint8_t L2CA_GetChnlFcrMode(uint16_t lcid) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_GetChnlFcrMode(lcid);
+ }
+
tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(NULL, lcid);
if (p_ccb) {
@@ -1629,6 +1776,10 @@
******************************************************************************/
bool L2CA_RegisterFixedChannel(uint16_t fixed_cid,
tL2CAP_FIXED_CHNL_REG* p_freg) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_RegisterFixedChannel(fixed_cid, p_freg);
+ }
+
if ((fixed_cid < L2CAP_FIRST_FIXED_CHNL) ||
(fixed_cid > L2CAP_LAST_FIXED_CHNL)) {
L2CAP_TRACE_ERROR("L2CA_RegisterFixedChannel() Invalid CID: 0x%04x",
@@ -1654,12 +1805,21 @@
*
******************************************************************************/
bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_ConnectFixedChnl(fixed_cid, rem_bda);
+ }
+
uint8_t phy = controller_get_interface()->get_le_all_initiating_phys();
return L2CA_ConnectFixedChnl(fixed_cid, rem_bda, phy);
}
bool L2CA_ConnectFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda,
uint8_t initiating_phys) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_ConnectFixedChnl(fixed_cid, rem_bda,
+ initiating_phys);
+ }
+
tL2C_LCB* p_lcb;
tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
@@ -1772,6 +1932,10 @@
******************************************************************************/
uint16_t L2CA_SendFixedChnlData(uint16_t fixed_cid, const RawAddress& rem_bda,
BT_HDR* p_buf) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_SendFixedChnlData(fixed_cid, rem_bda, p_buf);
+ }
+
tL2C_LCB* p_lcb;
tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
@@ -1885,6 +2049,10 @@
*
******************************************************************************/
bool L2CA_RemoveFixedChnl(uint16_t fixed_cid, const RawAddress& rem_bda) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_RemoveFixedChnl(fixed_cid, rem_bda);
+ }
+
tL2C_LCB* p_lcb;
tL2C_CCB* p_ccb;
tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
@@ -1952,6 +2120,11 @@
******************************************************************************/
bool L2CA_SetFixedChannelTout(const RawAddress& rem_bda, uint16_t fixed_cid,
uint16_t idle_tout) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_SetFixedChannelTout(rem_bda, fixed_cid,
+ idle_tout);
+ }
+
tL2C_LCB* p_lcb;
tBT_TRANSPORT transport = BT_TRANSPORT_BR_EDR;
@@ -1999,6 +2172,11 @@
tL2CAP_CH_CFG_BITS* p_our_cfg_bits,
tL2CAP_CFG_INFO** pp_peer_cfg,
tL2CAP_CH_CFG_BITS* p_peer_cfg_bits) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_GetCurrentConfig(
+ lcid, pp_our_cfg, p_our_cfg_bits, pp_peer_cfg, p_peer_cfg_bits);
+ }
+
tL2C_CCB* p_ccb;
L2CAP_TRACE_API("L2CA_GetCurrentConfig() CID: 0x%04x", lcid);
@@ -2041,6 +2219,10 @@
******************************************************************************/
bool L2CA_GetConnectionConfig(uint16_t lcid, uint16_t* mtu, uint16_t* rcid,
uint16_t* handle) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_GetConnectionConfig(lcid, mtu, rcid, handle);
+ }
+
tL2C_CCB* p_ccb = l2cu_find_ccb_by_cid(NULL, lcid);
;
@@ -2072,6 +2254,10 @@
*
******************************************************************************/
bool L2CA_RegForNoCPEvt(tL2CA_NOCP_CB* p_cb, const RawAddress& p_bda) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_RegForNoCPEvt(p_cb, p_bda);
+ }
+
tL2C_LCB* p_lcb;
/* Find the link that is associated with this remote bdaddr */
@@ -2098,6 +2284,10 @@
*
******************************************************************************/
uint8_t L2CA_DataWrite(uint16_t cid, BT_HDR* p_data) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_DataWrite(cid, p_data);
+ }
+
L2CAP_TRACE_API("L2CA_DataWrite() CID: 0x%04x Len: %d", cid, p_data->len);
return l2c_data_write(cid, p_data, L2CAP_FLUSHABLE_CH_BASED);
}
@@ -2113,8 +2303,11 @@
*
******************************************************************************/
bool L2CA_SetChnlFlushability(uint16_t cid, bool is_flushable) {
-#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_SetChnlFlushability(cid, is_flushable);
+ }
+#if (L2CAP_NON_FLUSHABLE_PB_INCLUDED == TRUE)
tL2C_CCB* p_ccb;
/* Find the channel control block. We don't know the link it is on. */
@@ -2152,6 +2345,10 @@
*
******************************************************************************/
uint8_t L2CA_DataWriteEx(uint16_t cid, BT_HDR* p_data, uint16_t flags) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_DataWriteEx(cid, p_data, flags);
+ }
+
L2CAP_TRACE_API("L2CA_DataWriteEx() CID: 0x%04x Len: %d Flags:0x%04X", cid,
p_data->len, flags);
return l2c_data_write(cid, p_data, flags);
@@ -2172,6 +2369,10 @@
*
******************************************************************************/
uint16_t L2CA_FlushChannel(uint16_t lcid, uint16_t num_to_flush) {
+ if (bluetooth::shim::is_gd_shim_enabled()) {
+ return bluetooth::shim::L2CA_FlushChannel(lcid, num_to_flush);
+ }
+
tL2C_CCB* p_ccb;
tL2C_LCB* p_lcb;
uint16_t num_left = 0, num_flushed1 = 0, num_flushed2 = 0;
diff --git a/stack/l2cap/l2c_fcr.cc b/stack/l2cap/l2c_fcr.cc
index 857a0bf..920448b 100644
--- a/stack/l2cap/l2c_fcr.cc
+++ b/stack/l2cap/l2c_fcr.cc
@@ -2163,23 +2163,29 @@
/* Peer wants ERTM and we support it */
if ((peer_mode == L2CAP_FCR_ERTM_MODE) &&
(p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_ERTM)) {
- L2CAP_TRACE_DEBUG("l2c_fcr_renegotiate_chan(Trying ERTM)");
+ L2CAP_TRACE_DEBUG("%s(Trying ERTM)", __func__);
p_ccb->our_cfg.fcr.mode = L2CAP_FCR_ERTM_MODE;
can_renegotiate = true;
- } else /* Falls through */
-
- case L2CAP_FCR_ERTM_MODE: {
+ } else if (p_ccb->ertm_info.allowed_modes &
+ L2CAP_FCR_CHAN_OPT_BASIC) {
/* We can try basic for any other peer mode if we support it */
- if (p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_BASIC) {
- L2CAP_TRACE_DEBUG("l2c_fcr_renegotiate_chan(Trying Basic)");
- can_renegotiate = true;
- p_ccb->our_cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
- }
- } break;
+ L2CAP_TRACE_DEBUG("%s(Trying Basic)", __func__);
+ can_renegotiate = true;
+ p_ccb->our_cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+ }
+ break;
+ case L2CAP_FCR_ERTM_MODE:
+ /* We can try basic for any other peer mode if we support it */
+ if (p_ccb->ertm_info.allowed_modes & L2CAP_FCR_CHAN_OPT_BASIC) {
+ L2CAP_TRACE_DEBUG("%s(Trying Basic)", __func__);
+ can_renegotiate = true;
+ p_ccb->our_cfg.fcr.mode = L2CAP_FCR_BASIC_MODE;
+ }
+ break;
- default:
- /* All other scenarios cannot be renegotiated */
- break;
+ default:
+ /* All other scenarios cannot be renegotiated */
+ break;
}
if (can_renegotiate) {
diff --git a/stack/l2cap/l2c_link.cc b/stack/l2cap/l2c_link.cc
index 60e9fd8..7f6d5b9 100644
--- a/stack/l2cap/l2c_link.cc
+++ b/stack/l2cap/l2c_link.cc
@@ -170,7 +170,12 @@
p_lcb->link_state = LST_CONNECTING;
}
- if (p_lcb->link_state != LST_CONNECTING) {
+ if ((p_lcb->link_state == LST_CONNECTED) &&
+ (status == HCI_ERR_CONNECTION_EXISTS)) {
+ L2CAP_TRACE_WARNING("%s: An ACL connection already exists. Handle:%d",
+ __func__, handle);
+ return (true);
+ } else if (p_lcb->link_state != LST_CONNECTING) {
L2CAP_TRACE_ERROR("L2CAP got conn_comp in bad state: %d status: 0x%d",
p_lcb->link_state, status);
diff --git a/stack/l2cap/l2cap_client.cc b/stack/l2cap/l2cap_client.cc
index 76e4138..b3f3737 100644
--- a/stack/l2cap/l2cap_client.cc
+++ b/stack/l2cap/l2cap_client.cc
@@ -70,8 +70,8 @@
.pL2CA_ConfigCfm_Cb = config_completed_cb,
.pL2CA_DisconnectInd_Cb = disconnect_request_cb,
.pL2CA_DisconnectCfm_Cb = disconnect_completed_cb,
- .pL2CA_CongestionStatus_Cb = congestion_cb,
.pL2CA_DataInd_Cb = read_ready_cb,
+ .pL2CA_CongestionStatus_Cb = congestion_cb,
.pL2CA_TxComplete_Cb = write_completed_cb,
};
diff --git a/stack/smp/p_256_curvepara.cc b/stack/smp/p_256_curvepara.cc
index 5fb71a3..ebdf266 100644
--- a/stack/smp/p_256_curvepara.cc
+++ b/stack/smp/p_256_curvepara.cc
@@ -25,53 +25,49 @@
#include <string.h>
#include "p_256_ecc_pp.h"
-void p_256_init_curve(uint32_t keyLength) {
- elliptic_curve_t* ec;
+void p_256_init_curve() {
+ elliptic_curve_t* ec = &curve_p256;
- if (keyLength == KEY_LENGTH_DWORDS_P256) {
- ec = &curve_p256;
+ ec->p[7] = 0xFFFFFFFF;
+ ec->p[6] = 0x00000001;
+ ec->p[5] = 0x0;
+ ec->p[4] = 0x0;
+ ec->p[3] = 0x0;
+ ec->p[2] = 0xFFFFFFFF;
+ ec->p[1] = 0xFFFFFFFF;
+ ec->p[0] = 0xFFFFFFFF;
- ec->p[7] = 0xFFFFFFFF;
- ec->p[6] = 0x00000001;
- ec->p[5] = 0x0;
- ec->p[4] = 0x0;
- ec->p[3] = 0x0;
- ec->p[2] = 0xFFFFFFFF;
- ec->p[1] = 0xFFFFFFFF;
- ec->p[0] = 0xFFFFFFFF;
+ memset(ec->omega, 0, KEY_LENGTH_DWORDS_P256);
+ memset(ec->a, 0, KEY_LENGTH_DWORDS_P256);
- memset(ec->omega, 0, KEY_LENGTH_DWORDS_P256);
- memset(ec->a, 0, KEY_LENGTH_DWORDS_P256);
+ ec->a_minus3 = true;
- ec->a_minus3 = true;
+ // b
+ ec->b[7] = 0x5ac635d8;
+ ec->b[6] = 0xaa3a93e7;
+ ec->b[5] = 0xb3ebbd55;
+ ec->b[4] = 0x769886bc;
+ ec->b[3] = 0x651d06b0;
+ ec->b[2] = 0xcc53b0f6;
+ ec->b[1] = 0x3bce3c3e;
+ ec->b[0] = 0x27d2604b;
- // b
- ec->b[7] = 0x5ac635d8;
- ec->b[6] = 0xaa3a93e7;
- ec->b[5] = 0xb3ebbd55;
- ec->b[4] = 0x769886bc;
- ec->b[3] = 0x651d06b0;
- ec->b[2] = 0xcc53b0f6;
- ec->b[1] = 0x3bce3c3e;
- ec->b[0] = 0x27d2604b;
+ // base point
+ ec->G.x[7] = 0x6b17d1f2;
+ ec->G.x[6] = 0xe12c4247;
+ ec->G.x[5] = 0xf8bce6e5;
+ ec->G.x[4] = 0x63a440f2;
+ ec->G.x[3] = 0x77037d81;
+ ec->G.x[2] = 0x2deb33a0;
+ ec->G.x[1] = 0xf4a13945;
+ ec->G.x[0] = 0xd898c296;
- // base point
- ec->G.x[7] = 0x6b17d1f2;
- ec->G.x[6] = 0xe12c4247;
- ec->G.x[5] = 0xf8bce6e5;
- ec->G.x[4] = 0x63a440f2;
- ec->G.x[3] = 0x77037d81;
- ec->G.x[2] = 0x2deb33a0;
- ec->G.x[1] = 0xf4a13945;
- ec->G.x[0] = 0xd898c296;
-
- ec->G.y[7] = 0x4fe342e2;
- ec->G.y[6] = 0xfe1a7f9b;
- ec->G.y[5] = 0x8ee7eb4a;
- ec->G.y[4] = 0x7c0f9e16;
- ec->G.y[3] = 0x2bce3357;
- ec->G.y[2] = 0x6b315ece;
- ec->G.y[1] = 0xcbb64068;
- ec->G.y[0] = 0x37bf51f5;
- }
+ ec->G.y[7] = 0x4fe342e2;
+ ec->G.y[6] = 0xfe1a7f9b;
+ ec->G.y[5] = 0x8ee7eb4a;
+ ec->G.y[4] = 0x7c0f9e16;
+ ec->G.y[3] = 0x2bce3357;
+ ec->G.y[2] = 0x6b315ece;
+ ec->G.y[1] = 0xcbb64068;
+ ec->G.y[0] = 0x37bf51f5;
}
diff --git a/stack/smp/p_256_ecc_pp.cc b/stack/smp/p_256_ecc_pp.cc
index ff5dbde..cef368a 100644
--- a/stack/smp/p_256_ecc_pp.cc
+++ b/stack/smp/p_256_ecc_pp.cc
@@ -38,7 +38,7 @@
}
// q=2q
-static void ECC_Double(Point* q, Point* p, uint32_t keyLength) {
+static void ECC_Double(Point* q, Point* p) {
uint32_t t1[KEY_LENGTH_DWORDS_P256];
uint32_t t2[KEY_LENGTH_DWORDS_P256];
uint32_t t3[KEY_LENGTH_DWORDS_P256];
@@ -49,8 +49,8 @@
uint32_t* z1;
uint32_t* z3;
- if (multiprecision_iszero(p->z, keyLength)) {
- multiprecision_init(q->z, keyLength);
+ if (multiprecision_iszero(p->z)) {
+ multiprecision_init(q->z);
return; // return infinity
}
@@ -61,33 +61,33 @@
y3 = q->y;
z3 = q->z;
- multiprecision_mersenns_squa_mod(t1, z1, keyLength); // t1=z1^2
- multiprecision_sub_mod(t2, x1, t1, keyLength); // t2=x1-t1
- multiprecision_add_mod(t1, x1, t1, keyLength); // t1=x1+t1
- multiprecision_mersenns_mult_mod(t2, t1, t2, keyLength); // t2=t2*t1
- multiprecision_lshift_mod(t3, t2, keyLength);
- multiprecision_add_mod(t2, t3, t2, keyLength); // t2=3t2
+ multiprecision_mersenns_squa_mod(t1, z1); // t1=z1^2
+ multiprecision_sub_mod(t2, x1, t1); // t2=x1-t1
+ multiprecision_add_mod(t1, x1, t1); // t1=x1+t1
+ multiprecision_mersenns_mult_mod(t2, t1, t2); // t2=t2*t1
+ multiprecision_lshift_mod(t3, t2);
+ multiprecision_add_mod(t2, t3, t2); // t2=3t2
- multiprecision_mersenns_mult_mod(z3, y1, z1, keyLength); // z3=y1*z1
- multiprecision_lshift_mod(z3, z3, keyLength);
+ multiprecision_mersenns_mult_mod(z3, y1, z1); // z3=y1*z1
+ multiprecision_lshift_mod(z3, z3);
- multiprecision_mersenns_squa_mod(y3, y1, keyLength); // y3=y1^2
- multiprecision_lshift_mod(y3, y3, keyLength);
- multiprecision_mersenns_mult_mod(t3, y3, x1, keyLength); // t3=y3*x1=x1*y1^2
- multiprecision_lshift_mod(t3, t3, keyLength);
- multiprecision_mersenns_squa_mod(y3, y3, keyLength); // y3=y3^2=y1^4
- multiprecision_lshift_mod(y3, y3, keyLength);
+ multiprecision_mersenns_squa_mod(y3, y1); // y3=y1^2
+ multiprecision_lshift_mod(y3, y3);
+ multiprecision_mersenns_mult_mod(t3, y3, x1); // t3=y3*x1=x1*y1^2
+ multiprecision_lshift_mod(t3, t3);
+ multiprecision_mersenns_squa_mod(y3, y3); // y3=y3^2=y1^4
+ multiprecision_lshift_mod(y3, y3);
- multiprecision_mersenns_squa_mod(x3, t2, keyLength); // x3=t2^2
- multiprecision_lshift_mod(t1, t3, keyLength); // t1=2t3
- multiprecision_sub_mod(x3, x3, t1, keyLength); // x3=x3-t1
- multiprecision_sub_mod(t1, t3, x3, keyLength); // t1=t3-x3
- multiprecision_mersenns_mult_mod(t1, t1, t2, keyLength); // t1=t1*t2
- multiprecision_sub_mod(y3, t1, y3, keyLength); // y3=t1-y3
+ multiprecision_mersenns_squa_mod(x3, t2); // x3=t2^2
+ multiprecision_lshift_mod(t1, t3); // t1=2t3
+ multiprecision_sub_mod(x3, x3, t1); // x3=x3-t1
+ multiprecision_sub_mod(t1, t3, x3); // t1=t3-x3
+ multiprecision_mersenns_mult_mod(t1, t1, t2); // t1=t1*t2
+ multiprecision_sub_mod(y3, t1, y3); // y3=t1-y3
}
// q=q+p, zp must be 1
-static void ECC_Add(Point* r, Point* p, Point* q, uint32_t keyLength) {
+static void ECC_Add(Point* r, Point* p, Point* q) {
uint32_t t1[KEY_LENGTH_DWORDS_P256];
uint32_t t2[KEY_LENGTH_DWORDS_P256];
uint32_t* x1;
@@ -111,58 +111,57 @@
z3 = r->z;
// if Q=infinity, return p
- if (multiprecision_iszero(z2, keyLength)) {
+ if (multiprecision_iszero(z2)) {
p_256_copy_point(r, p);
return;
}
// if P=infinity, return q
- if (multiprecision_iszero(z1, keyLength)) {
+ if (multiprecision_iszero(z1)) {
p_256_copy_point(r, q);
return;
}
- multiprecision_mersenns_squa_mod(t1, z1, keyLength); // t1=z1^2
- multiprecision_mersenns_mult_mod(t2, z1, t1, keyLength); // t2=t1*z1
- multiprecision_mersenns_mult_mod(t1, x2, t1, keyLength); // t1=t1*x2
- multiprecision_mersenns_mult_mod(t2, y2, t2, keyLength); // t2=t2*y2
+ multiprecision_mersenns_squa_mod(t1, z1); // t1=z1^2
+ multiprecision_mersenns_mult_mod(t2, z1, t1); // t2=t1*z1
+ multiprecision_mersenns_mult_mod(t1, x2, t1); // t1=t1*x2
+ multiprecision_mersenns_mult_mod(t2, y2, t2); // t2=t2*y2
- multiprecision_sub_mod(t1, t1, x1, keyLength); // t1=t1-x1
- multiprecision_sub_mod(t2, t2, y1, keyLength); // t2=t2-y1
+ multiprecision_sub_mod(t1, t1, x1); // t1=t1-x1
+ multiprecision_sub_mod(t2, t2, y1); // t2=t2-y1
- if (multiprecision_iszero(t1, keyLength)) {
- if (multiprecision_iszero(t2, keyLength)) {
- ECC_Double(r, q, keyLength);
+ if (multiprecision_iszero(t1)) {
+ if (multiprecision_iszero(t2)) {
+ ECC_Double(r, q);
return;
} else {
- multiprecision_init(z3, keyLength);
+ multiprecision_init(z3);
return; // return infinity
}
}
- multiprecision_mersenns_mult_mod(z3, z1, t1, keyLength); // z3=z1*t1
- multiprecision_mersenns_squa_mod(y3, t1, keyLength); // t3=t1^2
- multiprecision_mersenns_mult_mod(z1, y3, t1, keyLength); // t4=t3*t1
- multiprecision_mersenns_mult_mod(y3, y3, x1, keyLength); // t3=t3*x1
- multiprecision_lshift_mod(t1, y3, keyLength); // t1=2*t3
- multiprecision_mersenns_squa_mod(x3, t2, keyLength); // x3=t2^2
- multiprecision_sub_mod(x3, x3, t1, keyLength); // x3=x3-t1
- multiprecision_sub_mod(x3, x3, z1, keyLength); // x3=x3-t4
- multiprecision_sub_mod(y3, y3, x3, keyLength); // t3=t3-x3
- multiprecision_mersenns_mult_mod(y3, y3, t2, keyLength); // t3=t3*t2
- multiprecision_mersenns_mult_mod(z1, z1, y1, keyLength); // t4=t4*t1
- multiprecision_sub_mod(y3, y3, z1, keyLength);
+ multiprecision_mersenns_mult_mod(z3, z1, t1); // z3=z1*t1
+ multiprecision_mersenns_squa_mod(y3, t1); // t3=t1^2
+ multiprecision_mersenns_mult_mod(z1, y3, t1); // t4=t3*t1
+ multiprecision_mersenns_mult_mod(y3, y3, x1); // t3=t3*x1
+ multiprecision_lshift_mod(t1, y3); // t1=2*t3
+ multiprecision_mersenns_squa_mod(x3, t2); // x3=t2^2
+ multiprecision_sub_mod(x3, x3, t1); // x3=x3-t1
+ multiprecision_sub_mod(x3, x3, z1); // x3=x3-t4
+ multiprecision_sub_mod(y3, y3, x3); // t3=t3-x3
+ multiprecision_mersenns_mult_mod(y3, y3, t2); // t3=t3*t2
+ multiprecision_mersenns_mult_mod(z1, z1, y1); // t4=t4*t1
+ multiprecision_sub_mod(y3, y3, z1);
}
// Computing the Non-Adjacent Form of a positive integer
-static void ECC_NAF(uint8_t* naf, uint32_t* NumNAF, uint32_t* k,
- uint32_t keyLength) {
+static void ECC_NAF(uint8_t* naf, uint32_t* NumNAF, uint32_t* k) {
uint32_t sign;
int i = 0;
int j;
uint32_t var;
- while ((var = multiprecision_most_signbits(k, keyLength)) >= 1) {
+ while ((var = multiprecision_most_signbits(k)) >= 1) {
if (k[0] & 0x01) // k is odd
{
sign = (k[0] & 0x03); // 1 or 3
@@ -183,7 +182,7 @@
} else
sign = 0;
- multiprecision_rshift(k, k, keyLength);
+ multiprecision_rshift(k, k);
naf[i / 4] |= (sign) << ((i % 4) * 2);
i++;
}
@@ -192,8 +191,7 @@
}
// Binary Non-Adjacent Form for point multiplication
-void ECC_PointMult_Bin_NAF(Point* q, Point* p, uint32_t* n,
- uint32_t keyLength) {
+void ECC_PointMult_Bin_NAF(Point* q, Point* p, uint32_t* n) {
uint32_t sign;
uint8_t naf[256 / 4 + 1];
uint32_t NumNaf;
@@ -201,69 +199,64 @@
Point r;
uint32_t* modp;
- if (keyLength == KEY_LENGTH_DWORDS_P256) {
- modp = curve_p256.p;
- } else {
- modp = curve.p;
- }
+ modp = curve_p256.p;
p_256_init_point(&r);
- multiprecision_init(p->z, keyLength);
+ multiprecision_init(p->z);
p->z[0] = 1;
// initialization
p_256_init_point(q);
// -p
- multiprecision_copy(minus_p.x, p->x, keyLength);
- multiprecision_sub(minus_p.y, modp, p->y, keyLength);
+ multiprecision_copy(minus_p.x, p->x);
+ multiprecision_sub(minus_p.y, modp, p->y);
- multiprecision_init(minus_p.z, keyLength);
+ multiprecision_init(minus_p.z);
minus_p.z[0] = 1;
// NAF
memset(naf, 0, sizeof(naf));
- ECC_NAF(naf, &NumNaf, n, keyLength);
+ ECC_NAF(naf, &NumNaf, n);
for (int i = NumNaf - 1; i >= 0; i--) {
p_256_copy_point(&r, q);
- ECC_Double(q, &r, keyLength);
+ ECC_Double(q, &r);
sign = (naf[i / 4] >> ((i % 4) * 2)) & 0x03;
if (sign == 1) {
p_256_copy_point(&r, q);
- ECC_Add(q, &r, p, keyLength);
+ ECC_Add(q, &r, p);
} else if (sign == 3) {
p_256_copy_point(&r, q);
- ECC_Add(q, &r, &minus_p, keyLength);
+ ECC_Add(q, &r, &minus_p);
}
}
- multiprecision_inv_mod(minus_p.x, q->z, keyLength);
- multiprecision_mersenns_squa_mod(q->z, minus_p.x, keyLength);
- multiprecision_mersenns_mult_mod(q->x, q->x, q->z, keyLength);
- multiprecision_mersenns_mult_mod(q->z, q->z, minus_p.x, keyLength);
- multiprecision_mersenns_mult_mod(q->y, q->y, q->z, keyLength);
+ multiprecision_inv_mod(minus_p.x, q->z);
+ multiprecision_mersenns_squa_mod(q->z, minus_p.x);
+ multiprecision_mersenns_mult_mod(q->x, q->x, q->z);
+ multiprecision_mersenns_mult_mod(q->z, q->z, minus_p.x);
+ multiprecision_mersenns_mult_mod(q->y, q->y, q->z);
}
bool ECC_ValidatePoint(const Point& pt) {
- const size_t kl = KEY_LENGTH_DWORDS_P256;
- p_256_init_curve(kl);
+ p_256_init_curve();
// Ensure y^2 = x^3 + a*x + b (mod p); a = -3
// y^2 mod p
- uint32_t y2_mod[kl] = {0};
- multiprecision_mersenns_squa_mod(y2_mod, (uint32_t*)pt.y, kl);
+ uint32_t y2_mod[KEY_LENGTH_DWORDS_P256] = {0};
+ multiprecision_mersenns_squa_mod(y2_mod, (uint32_t*)pt.y);
// Right hand side calculation
- uint32_t rhs[kl] = {0};
- multiprecision_mersenns_squa_mod(rhs, (uint32_t*)pt.x, kl);
- uint32_t three[kl] = {0};
+ uint32_t rhs[KEY_LENGTH_DWORDS_P256] = {0};
+ multiprecision_mersenns_squa_mod(rhs, (uint32_t*)pt.x);
+ uint32_t three[KEY_LENGTH_DWORDS_P256] = {0};
three[0] = 3;
- multiprecision_sub_mod(rhs, rhs, three, kl);
- multiprecision_mersenns_mult_mod(rhs, rhs, (uint32_t*)pt.x, kl);
- multiprecision_add_mod(rhs, rhs, curve_p256.b, kl);
+ multiprecision_sub_mod(rhs, rhs, three);
+ multiprecision_mersenns_mult_mod(rhs, rhs, (uint32_t*)pt.x);
+ multiprecision_add_mod(rhs, rhs, curve_p256.b);
- return multiprecision_compare(rhs, y2_mod, kl) == 0;
+ return multiprecision_compare(rhs, y2_mod) == 0;
}
diff --git a/stack/smp/p_256_ecc_pp.h b/stack/smp/p_256_ecc_pp.h
index b49b72a..4dff0a8 100644
--- a/stack/smp/p_256_ecc_pp.h
+++ b/stack/smp/p_256_ecc_pp.h
@@ -58,9 +58,8 @@
bool ECC_ValidatePoint(const Point& p);
-void ECC_PointMult_Bin_NAF(Point* q, Point* p, uint32_t* n, uint32_t keyLength);
+void ECC_PointMult_Bin_NAF(Point* q, Point* p, uint32_t* n);
-#define ECC_PointMult(q, p, n, keyLength) \
- ECC_PointMult_Bin_NAF(q, p, n, keyLength)
+#define ECC_PointMult(q, p, n) ECC_PointMult_Bin_NAF(q, p, n)
-void p_256_init_curve(uint32_t keyLength);
+void p_256_init_curve();
diff --git a/stack/smp/p_256_multprecision.cc b/stack/smp/p_256_multprecision.cc
index 286aca1..0310829 100644
--- a/stack/smp/p_256_multprecision.cc
+++ b/stack/smp/p_256_multprecision.cc
@@ -27,24 +27,24 @@
#include "bt_target.h"
#include "p_256_ecc_pp.h"
-void multiprecision_init(uint32_t* c, uint32_t keyLength) {
- for (uint32_t i = 0; i < keyLength; i++) c[i] = 0;
+void multiprecision_init(uint32_t* c) {
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) c[i] = 0;
}
-void multiprecision_copy(uint32_t* c, uint32_t* a, uint32_t keyLength) {
- for (uint32_t i = 0; i < keyLength; i++) c[i] = a[i];
+void multiprecision_copy(uint32_t* c, uint32_t* a) {
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) c[i] = a[i];
}
-int multiprecision_compare(uint32_t* a, uint32_t* b, uint32_t keyLength) {
- for (int i = keyLength - 1; i >= 0; i--) {
+int multiprecision_compare(uint32_t* a, uint32_t* b) {
+ for (int i = KEY_LENGTH_DWORDS_P256 - 1; i >= 0; i--) {
if (a[i] > b[i]) return 1;
if (a[i] < b[i]) return -1;
}
return 0;
}
-int multiprecision_iszero(uint32_t* a, uint32_t keyLength) {
- for (uint32_t i = 0; i < keyLength; i++)
+int multiprecision_iszero(uint32_t* a) {
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++)
if (a[i]) return 0;
return 1;
@@ -58,30 +58,29 @@
return i;
}
-uint32_t multiprecision_most_signdwords(uint32_t* a, uint32_t keyLength) {
+uint32_t multiprecision_most_signdwords(uint32_t* a) {
int i;
- for (i = keyLength - 1; i >= 0; i--)
+ for (i = KEY_LENGTH_DWORDS_P256 - 1; i >= 0; i--)
if (a[i]) break;
return (i + 1);
}
-uint32_t multiprecision_most_signbits(uint32_t* a, uint32_t keyLength) {
+uint32_t multiprecision_most_signbits(uint32_t* a) {
int aMostSignDWORDs;
- aMostSignDWORDs = multiprecision_most_signdwords(a, keyLength);
+ aMostSignDWORDs = multiprecision_most_signdwords(a);
if (aMostSignDWORDs == 0) return 0;
return (((aMostSignDWORDs - 1) << DWORD_BITS_SHIFT) +
multiprecision_dword_bits(a[aMostSignDWORDs - 1]));
}
-uint32_t multiprecision_add(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength) {
+uint32_t multiprecision_add(uint32_t* c, uint32_t* a, uint32_t* b) {
uint32_t carrier;
uint32_t temp;
carrier = 0;
- for (uint32_t i = 0; i < keyLength; i++) {
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) {
temp = a[i] + carrier;
carrier = (temp < carrier);
temp += b[i];
@@ -93,13 +92,12 @@
}
// c=a-b
-uint32_t multiprecision_sub(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength) {
+uint32_t multiprecision_sub(uint32_t* c, uint32_t* a, uint32_t* b) {
uint32_t borrow;
uint32_t temp;
borrow = 0;
- for (uint32_t i = 0; i < keyLength; i++) {
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) {
temp = a[i] - borrow;
borrow = (temp > a[i]);
c[i] = temp - b[i];
@@ -110,27 +108,20 @@
}
// c = a << 1
-void multiprecision_lshift_mod(uint32_t* c, uint32_t* a, uint32_t keyLength) {
+void multiprecision_lshift_mod(uint32_t* c, uint32_t* a) {
uint32_t carrier;
- uint32_t* modp;
+ uint32_t* modp = curve_p256.p;
- if (keyLength == KEY_LENGTH_DWORDS_P192) {
- modp = curve.p;
- } else if (keyLength == KEY_LENGTH_DWORDS_P256) {
- modp = curve_p256.p;
- } else
- return;
-
- carrier = multiprecision_lshift(c, a, keyLength);
+ carrier = multiprecision_lshift(c, a);
if (carrier) {
- multiprecision_sub(c, c, modp, keyLength);
- } else if (multiprecision_compare(c, modp, keyLength) >= 0) {
- multiprecision_sub(c, c, modp, keyLength);
+ multiprecision_sub(c, c, modp);
+ } else if (multiprecision_compare(c, modp) >= 0) {
+ multiprecision_sub(c, c, modp);
}
}
// c=a>>1
-void multiprecision_rshift(uint32_t* c, uint32_t* a, uint32_t keyLength) {
+void multiprecision_rshift(uint32_t* c, uint32_t* a) {
int j;
uint32_t b = 1;
@@ -138,7 +129,7 @@
uint32_t carrier = 0;
uint32_t temp;
- for (int i = keyLength - 1; i >= 0; i--) {
+ for (int i = KEY_LENGTH_DWORDS_P256 - 1; i >= 0; i--) {
temp = a[i]; // in case of c==a
c[i] = (temp >> b) | carrier;
carrier = temp << j;
@@ -147,64 +138,42 @@
// Curve specific optimization when p is a pseudo-Mersenns prime,
// p=2^(KEY_LENGTH_BITS)-omega
-void multiprecision_mersenns_mult_mod(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength) {
+void multiprecision_mersenns_mult_mod(uint32_t* c, uint32_t* a, uint32_t* b) {
uint32_t cc[2 * KEY_LENGTH_DWORDS_P256];
- multiprecision_mult(cc, a, b, keyLength);
- if (keyLength == 6) {
- multiprecision_fast_mod(c, cc);
- } else if (keyLength == 8) {
- multiprecision_fast_mod_P256(c, cc);
- }
+ multiprecision_mult(cc, a, b);
+ multiprecision_fast_mod_P256(c, cc);
}
// Curve specific optimization when p is a pseudo-Mersenns prime
-void multiprecision_mersenns_squa_mod(uint32_t* c, uint32_t* a,
- uint32_t keyLength) {
- multiprecision_mersenns_mult_mod(c, a, a, keyLength);
+void multiprecision_mersenns_squa_mod(uint32_t* c, uint32_t* a) {
+ multiprecision_mersenns_mult_mod(c, a, a);
}
// c=(a+b) mod p, b<p, a<p
-void multiprecision_add_mod(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength) {
+void multiprecision_add_mod(uint32_t* c, uint32_t* a, uint32_t* b) {
uint32_t carrier;
- uint32_t* modp;
+ uint32_t* modp = curve_p256.p;
- if (keyLength == KEY_LENGTH_DWORDS_P192) {
- modp = curve.p;
- } else if (keyLength == KEY_LENGTH_DWORDS_P256) {
- modp = curve_p256.p;
- } else
- return;
-
- carrier = multiprecision_add(c, a, b, keyLength);
+ carrier = multiprecision_add(c, a, b);
if (carrier) {
- multiprecision_sub(c, c, modp, keyLength);
- } else if (multiprecision_compare(c, modp, keyLength) >= 0) {
- multiprecision_sub(c, c, modp, keyLength);
+ multiprecision_sub(c, c, modp);
+ } else if (multiprecision_compare(c, modp) >= 0) {
+ multiprecision_sub(c, c, modp);
}
}
// c=(a-b) mod p, a<p, b<p
-void multiprecision_sub_mod(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength) {
+void multiprecision_sub_mod(uint32_t* c, uint32_t* a, uint32_t* b) {
uint32_t borrow;
- uint32_t* modp;
+ uint32_t* modp = curve_p256.p;
- if (keyLength == KEY_LENGTH_DWORDS_P192) {
- modp = curve.p;
- } else if (keyLength == KEY_LENGTH_DWORDS_P256) {
- modp = curve_p256.p;
- } else
- return;
-
- borrow = multiprecision_sub(c, a, b, keyLength);
- if (borrow) multiprecision_add(c, c, modp, keyLength);
+ borrow = multiprecision_sub(c, a, b);
+ if (borrow) multiprecision_add(c, c, modp);
}
// c=a<<b, b<DWORD_BITS, c has a buffer size of Numuint32_ts+1
-uint32_t multiprecision_lshift(uint32_t* c, uint32_t* a, uint32_t keyLength) {
+uint32_t multiprecision_lshift(uint32_t* c, uint32_t* a) {
int j;
uint32_t b = 1;
j = DWORD_BITS - b;
@@ -212,7 +181,7 @@
uint32_t carrier = 0;
uint32_t temp;
- for (uint32_t i = 0; i < keyLength; i++) {
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) {
temp = a[i]; // in case c==a
c[i] = (temp << b) | carrier;
carrier = temp >> j;
@@ -222,19 +191,18 @@
}
// c=a*b; c must have a buffer of 2*Key_LENGTH_uint32_tS, c != a != b
-void multiprecision_mult(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength) {
+void multiprecision_mult(uint32_t* c, uint32_t* a, uint32_t* b) {
uint32_t W;
uint32_t U;
uint32_t V;
U = V = W = 0;
- multiprecision_init(c, keyLength);
+ multiprecision_init(c);
// assume little endian right now
- for (uint32_t i = 0; i < keyLength; i++) {
+ for (uint32_t i = 0; i < KEY_LENGTH_DWORDS_P256; i++) {
U = 0;
- for (uint32_t j = 0; j < keyLength; j++) {
+ for (uint32_t j = 0; j < KEY_LENGTH_DWORDS_P256; j++) {
uint64_t result;
result = ((uint64_t)a[i]) * ((uint64_t)b[j]);
W = result >> 32;
@@ -246,78 +214,7 @@
U += (V < c[i + j]);
c[i + j] = V;
}
- c[i + keyLength] = U;
- }
-}
-
-void multiprecision_fast_mod(uint32_t* c, uint32_t* a) {
- uint32_t U;
- uint32_t V;
- uint32_t* modp = curve.p;
-
- c[0] = a[0] + a[6];
- U = c[0] < a[0];
- c[0] += a[10];
- U += c[0] < a[10];
-
- c[1] = a[1] + U;
- U = c[1] < a[1];
- c[1] += a[7];
- U += c[1] < a[7];
- c[1] += a[11];
- U += c[1] < a[11];
-
- c[2] = a[2] + U;
- U = c[2] < a[2];
- c[2] += a[6];
- U += c[2] < a[6];
- c[2] += a[8];
- U += c[2] < a[8];
- c[2] += a[10];
- U += c[2] < a[10];
-
- c[3] = a[3] + U;
- U = c[3] < a[3];
- c[3] += a[7];
- U += c[3] < a[7];
- c[3] += a[9];
- U += c[3] < a[9];
- c[3] += a[11];
- U += c[3] < a[11];
-
- c[4] = a[4] + U;
- U = c[4] < a[4];
- c[4] += a[8];
- U += c[4] < a[8];
- c[4] += a[10];
- U += c[4] < a[10];
-
- c[5] = a[5] + U;
- U = c[5] < a[5];
- c[5] += a[9];
- U += c[5] < a[9];
- c[5] += a[11];
- U += c[5] < a[11];
-
- c[0] += U;
- V = c[0] < U;
- c[1] += V;
- V = c[1] < V;
- c[2] += V;
- V = c[2] < V;
- c[2] += U;
- V = c[2] < U;
- c[3] += V;
- V = c[3] < V;
- c[4] += V;
- V = c[4] < V;
- c[5] += V;
- V = c[5] < V;
-
- if (V) {
- multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P192);
- } else if (multiprecision_compare(c, modp, KEY_LENGTH_DWORDS_P192) >= 0) {
- multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P192);
+ c[i + KEY_LENGTH_DWORDS_P256] = U;
}
}
@@ -541,74 +438,67 @@
if (U & 0x80000000) {
while (U) {
- multiprecision_add(c, c, modp, KEY_LENGTH_DWORDS_P256);
+ multiprecision_add(c, c, modp);
U++;
}
} else if (U) {
while (U) {
- multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P256);
+ multiprecision_sub(c, c, modp);
U--;
}
}
- if (multiprecision_compare(c, modp, KEY_LENGTH_DWORDS_P256) >= 0)
- multiprecision_sub(c, c, modp, KEY_LENGTH_DWORDS_P256);
+ if (multiprecision_compare(c, modp) >= 0) multiprecision_sub(c, c, modp);
}
-void multiprecision_inv_mod(uint32_t* aminus, uint32_t* u, uint32_t keyLength) {
+void multiprecision_inv_mod(uint32_t* aminus, uint32_t* u) {
uint32_t v[KEY_LENGTH_DWORDS_P256];
uint32_t A[KEY_LENGTH_DWORDS_P256 + 1];
uint32_t C[KEY_LENGTH_DWORDS_P256 + 1];
- uint32_t* modp;
+ uint32_t* modp = curve_p256.p;
- if (keyLength == KEY_LENGTH_DWORDS_P256) {
- modp = curve_p256.p;
- } else {
- modp = curve.p;
- }
-
- multiprecision_copy(v, modp, keyLength);
- multiprecision_init(A, keyLength);
- multiprecision_init(C, keyLength);
+ multiprecision_copy(v, modp);
+ multiprecision_init(A);
+ multiprecision_init(C);
A[0] = 1;
- while (!multiprecision_iszero(u, keyLength)) {
+ while (!multiprecision_iszero(u)) {
while (!(u[0] & 0x01)) // u is even
{
- multiprecision_rshift(u, u, keyLength);
+ multiprecision_rshift(u, u);
if (!(A[0] & 0x01)) // A is even
- multiprecision_rshift(A, A, keyLength);
+ multiprecision_rshift(A, A);
else {
- A[keyLength] = multiprecision_add(A, A, modp, keyLength); // A =A+p
- multiprecision_rshift(A, A, keyLength);
- A[keyLength - 1] |= (A[keyLength] << 31);
+ A[KEY_LENGTH_DWORDS_P256] = multiprecision_add(A, A, modp); // A =A+p
+ multiprecision_rshift(A, A);
+ A[KEY_LENGTH_DWORDS_P256 - 1] |= (A[KEY_LENGTH_DWORDS_P256] << 31);
}
}
while (!(v[0] & 0x01)) // v is even
{
- multiprecision_rshift(v, v, keyLength);
+ multiprecision_rshift(v, v);
if (!(C[0] & 0x01)) // C is even
{
- multiprecision_rshift(C, C, keyLength);
+ multiprecision_rshift(C, C);
} else {
- C[keyLength] = multiprecision_add(C, C, modp, keyLength); // C =C+p
- multiprecision_rshift(C, C, keyLength);
- C[keyLength - 1] |= (C[keyLength] << 31);
+ C[KEY_LENGTH_DWORDS_P256] = multiprecision_add(C, C, modp); // C =C+p
+ multiprecision_rshift(C, C);
+ C[KEY_LENGTH_DWORDS_P256 - 1] |= (C[KEY_LENGTH_DWORDS_P256] << 31);
}
}
- if (multiprecision_compare(u, v, keyLength) >= 0) {
- multiprecision_sub(u, u, v, keyLength);
- multiprecision_sub_mod(A, A, C, keyLength);
+ if (multiprecision_compare(u, v) >= 0) {
+ multiprecision_sub(u, u, v);
+ multiprecision_sub_mod(A, A, C);
} else {
- multiprecision_sub(v, v, u, keyLength);
- multiprecision_sub_mod(C, C, A, keyLength);
+ multiprecision_sub(v, v, u);
+ multiprecision_sub_mod(C, C, A);
}
}
- if (multiprecision_compare(C, modp, keyLength) >= 0)
- multiprecision_sub(aminus, C, modp, keyLength);
+ if (multiprecision_compare(C, modp) >= 0)
+ multiprecision_sub(aminus, C, modp);
else
- multiprecision_copy(aminus, C, keyLength);
+ multiprecision_copy(aminus, C);
}
diff --git a/stack/smp/p_256_multprecision.h b/stack/smp/p_256_multprecision.h
index fbbd88d..a98fe4d 100644
--- a/stack/smp/p_256_multprecision.h
+++ b/stack/smp/p_256_multprecision.h
@@ -12,8 +12,7 @@
* 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.
- *
+ * limitations under the License. *
******************************************************************************/
/*******************************************************************************
@@ -29,40 +28,30 @@
#define DWORD_BYTES 4
#define DWORD_BITS_SHIFT 5
-#define KEY_LENGTH_DWORDS_P192 6
#define KEY_LENGTH_DWORDS_P256 8
/* Arithmetic Operations */
-int multiprecision_compare(uint32_t* a, uint32_t* b, uint32_t keyLength);
-int multiprecision_iszero(uint32_t* a, uint32_t keyLength);
-void multiprecision_init(uint32_t* c, uint32_t keyLength);
-void multiprecision_copy(uint32_t* c, uint32_t* a, uint32_t keyLength);
+int multiprecision_compare(uint32_t* a, uint32_t* b);
+int multiprecision_iszero(uint32_t* a);
+void multiprecision_init(uint32_t* c);
+void multiprecision_copy(uint32_t* c, uint32_t* a);
uint32_t multiprecision_dword_bits(uint32_t a);
-uint32_t multiprecision_most_signdwords(uint32_t* a, uint32_t keyLength);
-uint32_t multiprecision_most_signbits(uint32_t* a, uint32_t keyLength);
-void multiprecision_inv_mod(uint32_t* aminus, uint32_t* a, uint32_t keyLength);
-uint32_t multiprecision_add(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength); // c=a+b
-void multiprecision_add_mod(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength);
-uint32_t multiprecision_sub(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength); // c=a-b
-void multiprecision_sub_mod(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength);
-void multiprecision_rshift(uint32_t* c, uint32_t* a,
- uint32_t keyLength); // c=a>>1, return carrier
-void multiprecision_lshift_mod(uint32_t* c, uint32_t* a,
- uint32_t keyLength); // c=a<<b, return carrier
-uint32_t multiprecision_lshift(uint32_t* c, uint32_t* a,
- uint32_t keyLength); // c=a<<b, return carrier
-void multiprecision_mult(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength); // c=a*b
-void multiprecision_mersenns_mult_mod(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength);
-void multiprecision_mersenns_squa_mod(uint32_t* c, uint32_t* a,
- uint32_t keyLength);
-uint32_t multiprecision_lshift(uint32_t* c, uint32_t* a, uint32_t keyLength);
-void multiprecision_mult(uint32_t* c, uint32_t* a, uint32_t* b,
- uint32_t keyLength);
+uint32_t multiprecision_most_signdwords(uint32_t* a);
+uint32_t multiprecision_most_signbits(uint32_t* a);
+void multiprecision_inv_mod(uint32_t* aminus, uint32_t* a);
+uint32_t multiprecision_add(uint32_t* c, uint32_t* a, uint32_t* b); // c=a+b
+void multiprecision_add_mod(uint32_t* c, uint32_t* a, uint32_t* b);
+uint32_t multiprecision_sub(uint32_t* c, uint32_t* a, uint32_t* b); // c=a-b
+void multiprecision_sub_mod(uint32_t* c, uint32_t* a, uint32_t* b);
+void multiprecision_rshift(uint32_t* c, uint32_t* a); // c=a>>1, return carrier
+void multiprecision_lshift_mod(uint32_t* c,
+ uint32_t* a); // c=a<<b, return carrier
+uint32_t multiprecision_lshift(uint32_t* c,
+ uint32_t* a); // c=a<<b, return carrier
+void multiprecision_mult(uint32_t* c, uint32_t* a, uint32_t* b); // c=a*b
+void multiprecision_mersenns_mult_mod(uint32_t* c, uint32_t* a, uint32_t* b);
+void multiprecision_mersenns_squa_mod(uint32_t* c, uint32_t* a);
+uint32_t multiprecision_lshift(uint32_t* c, uint32_t* a);
+void multiprecision_mult(uint32_t* c, uint32_t* a, uint32_t* b);
void multiprecision_fast_mod(uint32_t* c, uint32_t* a);
void multiprecision_fast_mod_P256(uint32_t* c, uint32_t* a);
diff --git a/stack/smp/smp_api.cc b/stack/smp/smp_api.cc
index baa41cf..e082356 100644
--- a/stack/smp/smp_api.cc
+++ b/stack/smp/smp_api.cc
@@ -62,7 +62,7 @@
smp_l2cap_if_init();
/* initialization of P-256 parameters */
- p_256_init_curve(KEY_LENGTH_DWORDS_P256);
+ p_256_init_curve();
/* Initialize failure case for certification */
smp_cb.cert_failure =
diff --git a/stack/smp/smp_keys.cc b/stack/smp/smp_keys.cc
index da8d0f4..64c969d 100644
--- a/stack/smp/smp_keys.cc
+++ b/stack/smp/smp_keys.cc
@@ -691,8 +691,7 @@
SMP_TRACE_DEBUG("%s", __func__);
memcpy(private_key, p_cb->private_key, BT_OCTET32_LEN);
- ECC_PointMult(&public_key, &(curve_p256.G), (uint32_t*)private_key,
- KEY_LENGTH_DWORDS_P256);
+ ECC_PointMult(&public_key, &(curve_p256.G), (uint32_t*)private_key);
memcpy(p_cb->loc_publ_key.x, public_key.x, BT_OCTET32_LEN);
memcpy(p_cb->loc_publ_key.y, public_key.y, BT_OCTET32_LEN);
@@ -728,8 +727,7 @@
memcpy(peer_publ_key.x, p_cb->peer_publ_key.x, BT_OCTET32_LEN);
memcpy(peer_publ_key.y, p_cb->peer_publ_key.y, BT_OCTET32_LEN);
- ECC_PointMult(&new_publ_key, &peer_publ_key, (uint32_t*)private_key,
- KEY_LENGTH_DWORDS_P256);
+ ECC_PointMult(&new_publ_key, &peer_publ_key, (uint32_t*)private_key);
memcpy(p_cb->dhkey, new_publ_key.x, BT_OCTET32_LEN);
diff --git a/stack/test/ble_advertiser_test.cc b/stack/test/ble_advertiser_test.cc
index 9c7d5a5..952aa41 100644
--- a/stack/test/ble_advertiser_test.cc
+++ b/stack/test/ble_advertiser_test.cc
@@ -131,7 +131,7 @@
cmd_complete);
};
- bool QuirkAdvertiserZeroHandle() { return false; }
+ bool QuirkAdvertiserZeroHandle() override { return false; }
private:
DISALLOW_COPY_AND_ASSIGN(AdvertiserHciMock);
@@ -153,7 +153,7 @@
std::unique_ptr<AdvertiserHciMock> hci_mock;
- virtual void SetUp() {
+ void SetUp() override {
hci_mock.reset(new AdvertiserHciMock());
base::Callback<void(uint8_t)> inst_cnt_Cb;
@@ -168,7 +168,7 @@
inst_cnt_Cb.Run(num_adv_instances);
}
- virtual void TearDown() {
+ void TearDown() override {
BleAdvertisingManager::CleanUp();
hci_mock.reset();
}
diff --git a/stack/test/gatt_connection_manager_test.cc b/stack/test/gatt_connection_manager_test.cc
index eed3776..0997aa8 100644
--- a/stack/test/gatt_connection_manager_test.cc
+++ b/stack/test/gatt_connection_manager_test.cc
@@ -61,11 +61,11 @@
namespace connection_manager {
class BleConnectionManager : public testing::Test {
- virtual void SetUp() {
+ void SetUp() override {
localWhiteListMock = std::make_unique<WhiteListMock>();
}
- virtual void TearDown() {
+ void TearDown() override {
connection_manager::reset(true);
AlarmMock::Reset();
localWhiteListMock.reset();
diff --git a/stack/test/stack_btu_test.cc b/stack/test/stack_btu_test.cc
index 5976bb2..2502646 100644
--- a/stack/test/stack_btu_test.cc
+++ b/stack/test/stack_btu_test.cc
@@ -89,7 +89,7 @@
MOCK_METHOD0(TestCallback, void(void));
base::MessageLoop* message_loop;
- virtual void SetUp() {
+ void SetUp() override {
// Initialize alarms to prevent btu_task_shut_down from crashing
alarm_new("test alarm");
bt_startup_thread.StartUp();
@@ -100,7 +100,7 @@
"BTU startup timed out"));
}
- virtual void TearDown() {
+ void TearDown() override {
btu_task_shut_down(nullptr);
alarm_cleanup();
bt_startup_thread.ShutDown();
diff --git a/stack/test/stack_smp_test.cc b/stack/test/stack_smp_test.cc
index 0b1f0a9..d83430c 100644
--- a/stack/test/stack_smp_test.cc
+++ b/stack/test/stack_smp_test.cc
@@ -131,7 +131,7 @@
Octet16 rand_{0x57, 0x83, 0xD5, 0x21, 0x56, 0xAD, 0x6F, 0x0E,
0x63, 0x88, 0x27, 0x4E, 0xC6, 0x70, 0x2E, 0xE0};
- void SetUp() {
+ void SetUp() override {
p_cb_.tk = {0};
// Set pairing request packet to 0x070710000001(01)
p_cb_.local_io_capability = 0x01;
@@ -151,7 +151,7 @@
p_cb_.role = HCI_ROLE_MASTER;
std::reverse(rand_.begin(), rand_.end());
}
- void TearDown() {}
+ void TearDown() override {}
public:
};
@@ -261,8 +261,8 @@
TEST(SmpEccValidationTest, test_invalid_points) {
Point p;
- multiprecision_init(p.x, 8);
- multiprecision_init(p.y, 8);
+ multiprecision_init(p.x);
+ multiprecision_init(p.y);
EXPECT_FALSE(ECC_ValidatePoint(p));
diff --git a/test/gen_coverage.py b/test/gen_coverage.py
index 3697c37..c699d3b 100755
--- a/test/gen_coverage.py
+++ b/test/gen_coverage.py
@@ -89,7 +89,7 @@
WORKING_DIR = '/tmp/coverage'
SOONG_UI_BASH = 'build/soong/soong_ui.bash'
-LLVM_DIR = 'prebuilts/clang/host/linux-x86/clang-r328903/bin'
+LLVM_DIR = 'prebuilts/clang/host/linux-x86/clang-r353983b/bin'
LLVM_MERGE = LLVM_DIR + '/llvm-profdata'
LLVM_COV = LLVM_DIR + '/llvm-cov'
diff --git a/test/rootcanal/Android.bp b/test/rootcanal/Android.bp
index e312c0e..bd62e50 100644
--- a/test/rootcanal/Android.bp
+++ b/test/rootcanal/Android.bp
@@ -14,7 +14,7 @@
// limitations under the License.
cc_binary {
- name: "android.hardware.bluetooth@1.0-service.sim",
+ name: "android.hardware.bluetooth@1.1-service.sim",
proprietary: true,
relative_install_path: "hw",
srcs: [
@@ -25,12 +25,11 @@
header_libs: ["libbluetooth_headers"],
shared_libs: [
"android.hardware.bluetooth@1.0",
+ "android.hardware.bluetooth@1.1",
"libbase",
"libchrome",
"libcutils",
- "libhwbinder",
"libhidlbase",
- "libhidltransport",
"liblog",
"libutils",
],
@@ -41,6 +40,10 @@
"-Werror",
"-DHAS_NO_BDROID_BUILDCFG",
],
+ generated_headers: [
+ "RootCanalGeneratedPackets_h",
+ "BluetoothGeneratedPackets_h",
+ ],
static_libs: [
"android.hardware.bluetooth-async",
"android.hardware.bluetooth-hci",
@@ -49,15 +52,16 @@
],
include_dirs: [
"system/bt",
+ "system/bt/gd",
"system/bt/hci/include",
"system/bt/internal_include",
"system/bt/stack/include",
],
- init_rc: ["android.hardware.bluetooth@1.0-service.sim.rc"],
+ init_rc: ["android.hardware.bluetooth@1.1-service.sim.rc"],
}
cc_library_shared {
- name: "android.hardware.bluetooth@1.0-impl-sim",
+ name: "android.hardware.bluetooth@1.1-impl-sim",
proprietary: true,
relative_install_path: "hw",
srcs: [
@@ -67,11 +71,11 @@
header_libs: ["libbluetooth_headers"],
shared_libs: [
"android.hardware.bluetooth@1.0",
+ "android.hardware.bluetooth@1.1",
"libbase",
"libchrome",
"libcutils",
"libhidlbase",
- "libhidltransport",
"liblog",
"libutils",
],
@@ -81,6 +85,10 @@
"-Werror",
"-DHAS_NO_BDROID_BUILDCFG",
],
+ generated_headers: [
+ "RootCanalGeneratedPackets_h",
+ "BluetoothGeneratedPackets_h",
+ ],
static_libs: [
"android.hardware.bluetooth-async",
"android.hardware.bluetooth-hci",
@@ -89,6 +97,7 @@
],
include_dirs: [
"system/bt",
+ "system/bt/gd",
"system/bt/hci/include",
"system/bt/internal_include",
"system/bt/stack/include",
diff --git a/test/rootcanal/android.hardware.bluetooth@1.0-service.sim.rc b/test/rootcanal/android.hardware.bluetooth@1.0-service.sim.rc
deleted file mode 100644
index 9d99c8a..0000000
--- a/test/rootcanal/android.hardware.bluetooth@1.0-service.sim.rc
+++ /dev/null
@@ -1,4 +0,0 @@
-service vendor.bluetooth-1-0 /vendor/bin/hw/android.hardware.bluetooth@1.0-service.sim
- class hal
- user bluetooth
- group bluetooth
diff --git a/test/rootcanal/android.hardware.bluetooth@1.1-service.sim.rc b/test/rootcanal/android.hardware.bluetooth@1.1-service.sim.rc
new file mode 100644
index 0000000..2626841
--- /dev/null
+++ b/test/rootcanal/android.hardware.bluetooth@1.1-service.sim.rc
@@ -0,0 +1,4 @@
+service vendor.bluetooth-1-1 /vendor/bin/hw/android.hardware.bluetooth@1.1-service.sim
+ class hal
+ user bluetooth
+ group bluetooth
diff --git a/test/rootcanal/bluetooth_hci.cc b/test/rootcanal/bluetooth_hci.cc
index e40a0c1..2bebd9a 100644
--- a/test/rootcanal/bluetooth_hci.cc
+++ b/test/rootcanal/bluetooth_hci.cc
@@ -14,23 +14,22 @@
// limitations under the License.
//
-#define LOG_TAG "android.hardware.bluetooth@1.0.sim"
+#define LOG_TAG "android.hardware.bluetooth@1.1.sim"
#include "bluetooth_hci.h"
-#include <base/logging.h>
#include <cutils/properties.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
-#include <utils/Log.h>
#include "hci_internals.h"
+#include "os/log.h"
namespace android {
namespace hardware {
namespace bluetooth {
-namespace V1_0 {
+namespace V1_1 {
namespace sim {
using android::hardware::hidl_vec;
@@ -51,8 +50,10 @@
public:
BluetoothDeathRecipient(const sp<IBluetoothHci> hci) : mHci(hci) {}
- virtual void serviceDied(uint64_t /* cookie */, const wp<::android::hidl::base::V1_0::IBase>& /* who */) {
- ALOGE("BluetoothDeathRecipient::serviceDied - Bluetooth service died");
+ void serviceDied(
+ uint64_t /* cookie */,
+ const wp<::android::hidl::base::V1_0::IBase>& /* who */) override {
+ LOG_ERROR("BluetoothDeathRecipient::serviceDied - Bluetooth service died");
has_died_ = true;
mHci->close();
}
@@ -70,51 +71,98 @@
BluetoothHci::BluetoothHci() : death_recipient_(new BluetoothDeathRecipient(this)) {}
-Return<void> BluetoothHci::initialize(const sp<IBluetoothHciCallbacks>& cb) {
- ALOGI("%s", __func__);
+Return<void> BluetoothHci::initialize(
+ const sp<V1_0::IBluetoothHciCallbacks>& cb) {
+ return initialize_impl(cb, nullptr);
+}
+
+Return<void> BluetoothHci::initialize_1_1(
+ const sp<V1_1::IBluetoothHciCallbacks>& cb) {
+ return initialize_impl(cb, cb);
+}
+
+Return<void> BluetoothHci::initialize_impl(
+ const sp<V1_0::IBluetoothHciCallbacks>& cb,
+ const sp<V1_1::IBluetoothHciCallbacks>& cb_1_1) {
+ LOG_INFO("%s", __func__);
if (cb == nullptr) {
- ALOGE("cb == nullptr! -> Unable to call initializationComplete(ERR)");
+ LOG_ERROR("cb == nullptr! -> Unable to call initializationComplete(ERR)");
return Void();
}
death_recipient_->setHasDied(false);
- cb->linkToDeath(death_recipient_, 0);
+ auto link_ret = cb->linkToDeath(death_recipient_, 0);
+ CHECK(link_ret.isOk()) << "Error calling linkToDeath.";
- test_channel_transport_.RegisterCommandHandler([this](const std::string& name, const std::vector<std::string>& args) {
- async_manager_.ExecAsync(std::chrono::milliseconds(0),
- [this, name, args]() { test_channel_.HandleCommand(name, args); });
- });
+ test_channel_transport_.RegisterCommandHandler(
+ [this](const std::string& name, const std::vector<std::string>& args) {
+ async_manager_.ExecAsync(
+ std::chrono::milliseconds(0),
+ [this, name, args]() { test_channel_.HandleCommand(name, args); });
+ });
controller_ = std::make_shared<DualModeController>();
- controller_->Initialize({"dmc", "3C:5A:B4:01:02:03"});
+ char mac_property[PROPERTY_VALUE_MAX] = "";
+ property_get("bt.rootcanal_mac_address", mac_property, "3C:5A:B4:01:02:03");
+ controller_->Initialize({"dmc", std::string(mac_property)});
- controller_->RegisterEventChannel([cb](std::shared_ptr<std::vector<uint8_t>> packet) {
- hidl_vec<uint8_t> hci_event(packet->begin(), packet->end());
- cb->hciEventReceived(hci_event);
- });
+ controller_->RegisterEventChannel(
+ [this, cb](std::shared_ptr<std::vector<uint8_t>> packet) {
+ hidl_vec<uint8_t> hci_event(packet->begin(), packet->end());
+ auto ret = cb->hciEventReceived(hci_event);
+ if (!ret.isOk()) {
+ CHECK(death_recipient_->getHasDied())
+ << "Error sending event callback, but no death notification.";
+ }
+ });
- controller_->RegisterAclChannel([cb](std::shared_ptr<std::vector<uint8_t>> packet) {
- hidl_vec<uint8_t> acl_packet(packet->begin(), packet->end());
- cb->aclDataReceived(acl_packet);
- });
+ controller_->RegisterAclChannel(
+ [this, cb](std::shared_ptr<std::vector<uint8_t>> packet) {
+ hidl_vec<uint8_t> acl_packet(packet->begin(), packet->end());
+ auto ret = cb->aclDataReceived(acl_packet);
+ if (!ret.isOk()) {
+ CHECK(death_recipient_->getHasDied())
+ << "Error sending acl callback, but no death notification.";
+ }
+ });
- controller_->RegisterScoChannel([cb](std::shared_ptr<std::vector<uint8_t>> packet) {
- hidl_vec<uint8_t> sco_packet(packet->begin(), packet->end());
- cb->aclDataReceived(sco_packet);
- });
+ controller_->RegisterScoChannel(
+ [this, cb](std::shared_ptr<std::vector<uint8_t>> packet) {
+ hidl_vec<uint8_t> sco_packet(packet->begin(), packet->end());
+ auto ret = cb->aclDataReceived(sco_packet);
+ if (!ret.isOk()) {
+ CHECK(death_recipient_->getHasDied())
+ << "Error sending sco callback, but no death notification.";
+ }
+ });
- controller_->RegisterTaskScheduler([this](std::chrono::milliseconds delay, const TaskCallback& task) {
- return async_manager_.ExecAsync(delay, task);
- });
+ if (cb_1_1 != nullptr) {
+ controller_->RegisterIsoChannel(
+ [this, cb_1_1](std::shared_ptr<std::vector<uint8_t>> packet) {
+ hidl_vec<uint8_t> iso_packet(packet->begin(), packet->end());
+ auto ret = cb_1_1->isoDataReceived(iso_packet);
+ if (!ret.isOk()) {
+ CHECK(death_recipient_->getHasDied())
+ << "Error sending iso callback, but no death notification.";
+ }
+ });
+ }
+
+ controller_->RegisterTaskScheduler(
+ [this](std::chrono::milliseconds delay, const TaskCallback& task) {
+ return async_manager_.ExecAsync(delay, task);
+ });
controller_->RegisterPeriodicTaskScheduler(
- [this](std::chrono::milliseconds delay, std::chrono::milliseconds period, const TaskCallback& task) {
+ [this](std::chrono::milliseconds delay, std::chrono::milliseconds period,
+ const TaskCallback& task) {
return async_manager_.ExecAsyncPeriodically(delay, period, task);
});
- controller_->RegisterTaskCancel([this](AsyncTaskId task) { async_manager_.CancelAsyncTask(task); });
+ controller_->RegisterTaskCancel(
+ [this](AsyncTaskId task) { async_manager_.CancelAsyncTask(task); });
test_model_.Reset();
// Add the controller as a device in the model.
@@ -122,7 +170,7 @@
// Send responses to logcat if the test channel is not configured.
test_channel_.RegisterSendResponse([](const std::string& response) {
- ALOGI("No test channel yet: %s", response.c_str());
+ LOG_INFO("No test channel yet: %s", response.c_str());
});
if (BtTestConsoleEnabled()) {
@@ -137,26 +185,34 @@
test_channel_.AddDefaults();
// This should be configurable in the future.
- ALOGI("Adding Beacons so the scan list is not empty.");
+ LOG_INFO("Adding Beacons so the scan list is not empty.");
test_channel_.Add({"beacon", "be:ac:10:00:00:01", "1000"});
- test_channel_.AddDeviceToPhy({"1", "0"});
+ test_channel_.AddDeviceToPhy({"2", "1"});
test_channel_.Add({"beacon", "be:ac:10:00:00:02", "1000"});
- test_channel_.AddDeviceToPhy({"2", "0"});
- test_channel_.SetTimerPeriod({"1000"});
+ test_channel_.AddDeviceToPhy({"3", "1"});
- unlink_cb_ = [cb](sp<BluetoothDeathRecipient>& death_recipient) {
+ unlink_cb_ = [this, cb](sp<BluetoothDeathRecipient>& death_recipient) {
if (death_recipient->getHasDied())
- ALOGI("Skipping unlink call, service died.");
- else
- cb->unlinkToDeath(death_recipient);
+ LOG_INFO("Skipping unlink call, service died.");
+ else {
+ auto ret = cb->unlinkToDeath(death_recipient);
+ if (!ret.isOk()) {
+ CHECK(death_recipient_->getHasDied())
+ << "Error calling unlink, but no death notification.";
+ }
+ }
};
- cb->initializationComplete(Status::SUCCESS);
+ auto init_ret = cb->initializationComplete(V1_0::Status::SUCCESS);
+ if (!init_ret.isOk()) {
+ CHECK(death_recipient_->getHasDied())
+ << "Error sending init callback, but no death notification.";
+ }
return Void();
}
Return<void> BluetoothHci::close() {
- ALOGI("%s", __func__);
+ LOG_INFO("%s", __func__);
return Void();
}
@@ -187,21 +243,31 @@
return Void();
}
+Return<void> BluetoothHci::sendIsoData(const hidl_vec<uint8_t>& packet) {
+ async_manager_.ExecAsync(std::chrono::milliseconds(0), [this, packet]() {
+ std::shared_ptr<std::vector<uint8_t>> packet_copy =
+ std::shared_ptr<std::vector<uint8_t>>(new std::vector<uint8_t>(packet));
+ controller_->HandleIso(packet_copy);
+ });
+ return Void();
+}
+
void BluetoothHci::SetUpHciServer(int port, const std::function<void(int)>& connection_callback) {
int socket_fd = remote_hci_transport_.SetUp(port);
- test_channel_.RegisterSendResponse(
- [](const std::string& response) { ALOGI("No HCI Response channel: %s", response.c_str()); });
+ test_channel_.RegisterSendResponse([](const std::string& response) {
+ LOG_INFO("No HCI Response channel: %s", response.c_str());
+ });
if (socket_fd == -1) {
- ALOGE("Remote HCI channel SetUp(%d) failed.", port);
+ LOG_ERROR("Remote HCI channel SetUp(%d) failed.", port);
return;
}
async_manager_.WatchFdForNonBlockingReads(socket_fd, [this, connection_callback](int socket_fd) {
int conn_fd = remote_hci_transport_.Accept(socket_fd);
if (conn_fd < 0) {
- ALOGE("Error watching remote HCI channel fd.");
+ LOG_ERROR("Error watching remote HCI channel fd.");
return;
}
int flags = fcntl(conn_fd, F_GETFL, NULL);
@@ -216,18 +282,19 @@
void BluetoothHci::SetUpLinkLayerServer(int port, const std::function<void(int)>& connection_callback) {
int socket_fd = remote_link_layer_transport_.SetUp(port);
- test_channel_.RegisterSendResponse(
- [](const std::string& response) { ALOGI("No LinkLayer Response channel: %s", response.c_str()); });
+ test_channel_.RegisterSendResponse([](const std::string& response) {
+ LOG_INFO("No LinkLayer Response channel: %s", response.c_str());
+ });
if (socket_fd == -1) {
- ALOGE("Remote LinkLayer channel SetUp(%d) failed.", port);
+ LOG_ERROR("Remote LinkLayer channel SetUp(%d) failed.", port);
return;
}
async_manager_.WatchFdForNonBlockingReads(socket_fd, [this, connection_callback](int socket_fd) {
int conn_fd = remote_link_layer_transport_.Accept(socket_fd);
if (conn_fd < 0) {
- ALOGE("Error watching remote LinkLayer channel fd.");
+ LOG_ERROR("Error watching remote LinkLayer channel fd.");
return;
}
int flags = fcntl(conn_fd, F_GETFL, NULL);
@@ -241,14 +308,15 @@
int BluetoothHci::ConnectToRemoteServer(const std::string& server, int port) {
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd < 1) {
- ALOGI("socket() call failed: %s", strerror(errno));
+ LOG_INFO("socket() call failed: %s", strerror(errno));
return -1;
}
struct hostent* host;
host = gethostbyname(server.c_str());
if (host == NULL) {
- ALOGI("gethostbyname() failed for %s: %s", server.c_str(), strerror(errno));
+ LOG_INFO("gethostbyname() failed for %s: %s", server.c_str(),
+ strerror(errno));
return -1;
}
@@ -260,7 +328,8 @@
int result = connect(socket_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
if (result < 0) {
- ALOGI("connect() failed for %s@%d: %s", server.c_str(), port, strerror(errno));
+ LOG_INFO("connect() failed for %s@%d: %s", server.c_str(), port,
+ strerror(errno));
return -1;
}
@@ -274,22 +343,23 @@
void BluetoothHci::SetUpTestChannel(int port) {
int socket_fd = test_channel_transport_.SetUp(port);
- test_channel_.RegisterSendResponse(
- [](const std::string& response) { ALOGI("No test channel: %s", response.c_str()); });
+ test_channel_.RegisterSendResponse([](const std::string& response) {
+ LOG_INFO("No test channel: %s", response.c_str());
+ });
if (socket_fd == -1) {
- ALOGE("Test channel SetUp(%d) failed.", port);
+ LOG_ERROR("Test channel SetUp(%d) failed.", port);
return;
}
- ALOGI("Test channel SetUp() successful");
+ LOG_INFO("Test channel SetUp() successful");
async_manager_.WatchFdForNonBlockingReads(socket_fd, [this](int socket_fd) {
int conn_fd = test_channel_transport_.Accept(socket_fd);
if (conn_fd < 0) {
- ALOGE("Error watching test channel fd.");
+ LOG_ERROR("Error watching test channel fd.");
return;
}
- ALOGI("Test channel connection accepted.");
+ LOG_INFO("Test channel connection accepted.");
test_channel_.RegisterSendResponse(
[this, conn_fd](const std::string& response) { test_channel_transport_.SendResponse(conn_fd, response); });
@@ -306,7 +376,7 @@
}
} // namespace sim
-} // namespace V1_0
+} // namespace V1_1
} // namespace bluetooth
} // namespace hardware
} // namespace android
diff --git a/test/rootcanal/bluetooth_hci.h b/test/rootcanal/bluetooth_hci.h
index 96d0ed8..99eda9f 100644
--- a/test/rootcanal/bluetooth_hci.h
+++ b/test/rootcanal/bluetooth_hci.h
@@ -16,7 +16,9 @@
#pragma once
-#include <android/hardware/bluetooth/1.0/IBluetoothHci.h>
+#include "os/log.h"
+
+#include <android/hardware/bluetooth/1.1/IBluetoothHci.h>
#include <hidl/MQDescriptor.h>
@@ -31,7 +33,7 @@
namespace android {
namespace hardware {
namespace bluetooth {
-namespace V1_0 {
+namespace V1_1 {
namespace sim {
class BluetoothDeathRecipient;
@@ -40,7 +42,10 @@
public:
BluetoothHci();
- ::android::hardware::Return<void> initialize(const sp<IBluetoothHciCallbacks>& cb) override;
+ ::android::hardware::Return<void> initialize(
+ const sp<V1_0::IBluetoothHciCallbacks>& cb) override;
+ ::android::hardware::Return<void> initialize_1_1(
+ const sp<V1_1::IBluetoothHciCallbacks>& cb) override;
::android::hardware::Return<void> sendHciCommand(const ::android::hardware::hidl_vec<uint8_t>& packet) override;
@@ -48,6 +53,9 @@
::android::hardware::Return<void> sendScoData(const ::android::hardware::hidl_vec<uint8_t>& packet) override;
+ ::android::hardware::Return<void> sendIsoData(
+ const ::android::hardware::hidl_vec<uint8_t>& packet) override;
+
::android::hardware::Return<void> close() override;
static void OnPacketReady();
@@ -55,6 +63,10 @@
static BluetoothHci* get();
private:
+ ::android::hardware::Return<void> initialize_impl(
+ const sp<V1_0::IBluetoothHciCallbacks>& cb,
+ const sp<V1_1::IBluetoothHciCallbacks>& cb_1_1);
+
sp<BluetoothDeathRecipient> death_recipient_;
std::function<void(sp<BluetoothDeathRecipient>&)> unlink_cb_;
@@ -94,7 +106,7 @@
extern "C" IBluetoothHci* HIDL_FETCH_IBluetoothHci(const char* name);
} // namespace sim
-} // namespace V1_0
+} // namespace V1_1
} // namespace bluetooth
} // namespace hardware
} // namespace android
diff --git a/test/rootcanal/service.cc b/test/rootcanal/service.cc
index 64fa9c7..7856dcf 100644
--- a/test/rootcanal/service.cc
+++ b/test/rootcanal/service.cc
@@ -14,20 +14,21 @@
// limitations under the License.
//
-#define LOG_TAG "android.hardware.bluetooth@1.0-service.sim"
+#define LOG_TAG "android.hardware.bluetooth@1.1-service.sim"
-#include <android/hardware/bluetooth/1.0/IBluetoothHci.h>
+#include "os/log.h"
+
+#include <android/hardware/bluetooth/1.1/IBluetoothHci.h>
#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportSupport.h>
-#include <utils/Log.h>
#include "bluetooth_hci.h"
using ::android::sp;
using ::android::hardware::configureRpcThreadpool;
using ::android::hardware::joinRpcThreadpool;
-using ::android::hardware::bluetooth::V1_0::IBluetoothHci;
-using ::android::hardware::bluetooth::V1_0::sim::BluetoothHci;
+using ::android::hardware::bluetooth::V1_1::IBluetoothHci;
+using ::android::hardware::bluetooth::V1_1::sim::BluetoothHci;
int main(int /* argc */, char** /* argv */) {
sp<IBluetoothHci> bluetooth = new BluetoothHci;
@@ -36,5 +37,5 @@
if (status == android::OK)
joinRpcThreadpool();
else
- ALOGE("Could not register as a service!");
+ LOG_ERROR("Could not register as a service!");
}
diff --git a/test/suite/Android.bp b/test/suite/Android.bp
index 3967ecc..1d919ed 100644
--- a/test/suite/Android.bp
+++ b/test/suite/Android.bp
@@ -38,7 +38,7 @@
"rfcomm/rfcomm_test.cc",
"rfcomm/rfcomm_unittest.cc",
],
- header_libs: [ "libhardware_headers" ],
+ header_libs: ["libhardware_headers"],
shared_libs: [
"liblog",
"libcutils",
diff --git a/test/suite/gatt/gatt_unittest.cc b/test/suite/gatt/gatt_unittest.cc
index 26fd850..b02c96a 100644
--- a/test/suite/gatt/gatt_unittest.cc
+++ b/test/suite/gatt/gatt_unittest.cc
@@ -69,12 +69,21 @@
int server_if = server_interface_id();
std::vector<btgatt_db_element_t> service = {
- {.type = BTGATT_DB_PRIMARY_SERVICE, .uuid = srvc_uuid},
- {.type = BTGATT_DB_CHARACTERISTIC,
- .uuid = char_uuid,
- .properties = 0x10 /* notification */,
- .permissions = 0x01 /* read only */},
- {.type = BTGATT_DB_DESCRIPTOR, .uuid = desc_uuid, .permissions = 0x01}};
+ {
+ .uuid = srvc_uuid,
+ .type = BTGATT_DB_PRIMARY_SERVICE,
+ },
+ {
+ .uuid = char_uuid,
+ .type = BTGATT_DB_CHARACTERISTIC,
+ .properties = 0x10, /* notification */
+ .permissions = 0x01, /* read only */
+ },
+ {
+ .uuid = desc_uuid,
+ .type = BTGATT_DB_DESCRIPTOR,
+ .permissions = 0x01,
+ }};
gatt_server_interface()->add_service(server_if, service);
semaphore_wait(service_added_callback_sem_);
diff --git a/tools/hci/main.c b/tools/hci/main.c
index c167886..093af6b 100644
--- a/tools/hci/main.c
+++ b/tools/hci/main.c
@@ -15,6 +15,7 @@
HCI_PACKET_ACL_DATA = 2,
HCI_PACKET_SCO_DATA = 3,
HCI_PACKET_EVENT = 4,
+ HCI_PACKET_ISO = 5,
} hci_packet_t;
typedef struct {
diff --git a/tools/scripts/btsnoop_live.py b/tools/scripts/btsnoop_live.py
new file mode 100644
index 0000000..4e145ff
--- /dev/null
+++ b/tools/scripts/btsnoop_live.py
@@ -0,0 +1,297 @@
+#!/usr/bin/env python3
+###############################################################################################################
+#
+# Copyright (C) 2019 Motorola Mobility LLC
+#
+# Redistribution and use in source and binary forms, with or without modification, are permitted provided that
+# the following conditions are met:
+#
+# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the
+# following disclaimer.
+#
+# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
+# the following disclaimer in the documentation and/or other materials provided with the distribution.
+#
+# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or
+# promote products derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+# WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
+# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+###############################################################################################################
+###############################################################################################################
+#
+# Bluetooth Virtual Sniffing for Android
+#
+# This script supports Bluetooth Virtual Sniffing via Live Import Feature of Frontline Bluetooth Sniffer(FTS)
+#
+# It extracts the HCI packets from Snoop logs and redirect it to FTS for live HCI sniffing.
+#
+# It uses liveimport.ini and LiveImportAPI.dll from FTS path to communicate with FTS sniffer software.
+#
+# It works on both Windows and Ubuntu. For Ubuntu, both FTS and Python should be installed on Wine.
+#
+# FTS_INI_PATH & FTS_DLL_PATH should be set to absolute path of liveimport.ini and LiveImportAPI.dll of FTS
+#
+# Example below - This may change per machine per FTS version in Windows vs Ubuntu (Wine), set accordingly.
+# For Windows
+# FTS_INI_PATH = 'C:\\Program Files (x86)\\Frontline Test System II\\Frontline 13.2\\'
+# FTS_DLL_PATH = 'C:\\Program Files (x86)\\Frontline Test System II\\Frontline 13.2\\Executables\\Core\\'
+#
+# For Ubuntu - FTS path recognized by Wine (not Ubuntu path)
+# FTS_INI_PATH = 'C:\\Program Files\\Frontline Test System II\\Frontline 13.2\\'
+# FTS_DLL_PATH = 'C:\\Program Files\\Frontline Test System II\\Frontline 13.2\\Executables\\Core\\'
+#
+###############################################################################################################
+
+import os
+import platform
+import socket
+import struct
+import subprocess
+import sys
+import time
+if sys.version_info[0] >= 3:
+ import configparser
+else:
+ import ConfigParser as configparser
+
+from calendar import timegm
+from ctypes import byref, c_bool, c_longlong, CDLL
+from _ctypes import FreeLibrary
+from datetime import datetime
+
+
+# Update below to right path corresponding to your machine, FTS version and OS used.
+FTS_INI_PATH = 'C:\\Program Files (x86)\\Frontline Test System II\\Frontline 15.12\\'
+FTS_DLL_PATH = 'C:\\Program Files (x86)\\Frontline Test System II\\Frontline 15.12\\Executables\\Core\\'
+
+
+iniName = 'liveimport.ini'
+if (platform.architecture()[0] == '32bit'):
+ dllName = 'LiveImportAPI.dll'
+else:
+ dllName = 'LiveImportAPI_x64.dll'
+
+launchFtsCmd = '\"'+FTS_DLL_PATH + 'fts.exe\"' + ' \"/ComProbe Protocol Analysis System=Generic\"' + ' \"/oemkey=Virtual\"'
+
+# Unix Epoch delta since 01/01/1970
+FILETIME_EPOCH_DELTA = 116444736000000000
+HUNDREDS_OF_NANOSECONDS = 10000000
+
+HOST = 'localhost'
+PORT = 8872
+SNOOP_ID = 16
+SNOOP_HDR = 24
+
+
+def get_file_time():
+ """
+ Obtain current time in file time format for display
+ """
+ date_time = datetime.now()
+ file_time = FILETIME_EPOCH_DELTA + (timegm(date_time.timetuple()) * HUNDREDS_OF_NANOSECONDS)
+ file_time = file_time + (date_time.microsecond * 10)
+ return file_time
+
+
+def get_connection_string():
+ """
+ Read ConnectionString from liveimport.ini
+ """
+ config = configparser.ConfigParser()
+ config.read(FTS_INI_PATH + iniName)
+ try:
+ conn_str = config.get('General', 'ConnectionString')
+ except (configparser.NoSectionError, configparser.NoOptionError):
+ return None
+
+ return conn_str
+
+
+def get_configuration_string():
+ """
+ Read Configuration string from liveimport.ini
+ """
+ config_str = ''
+ config = configparser.ConfigParser()
+ config.read(FTS_INI_PATH + iniName)
+ try:
+ config_items = config.items('Configuration')
+ except (configparser.NoSectionError, configparser.NoOptionError):
+ return None
+
+ if config_items is not None:
+ for item in config_items:
+ key, value = item
+ config_str += ("%s=%s\n" % (key, value))
+ return config_str
+ else:
+ return None
+
+def check_live_import_connection(live_import):
+ """
+ Launch FTS app in Virtual Sniffing Mode
+ Check if FTS App is ready to start receiving the data.
+ If not, wait until 1 min and exit if FTS didn't start.
+ """
+ is_connection_running = c_bool()
+ count = 0
+
+ status = live_import.IsAppReady(byref(is_connection_running))
+ if (is_connection_running.value == True):
+ print ("FTS is already launched, Start capture if not already started")
+ return True
+
+ print("Launching FTS Virtual Sniffing")
+ try:
+ ftsProcess = subprocess.Popen((launchFtsCmd), stdout=subprocess.PIPE)
+ except:
+ print("Error in Launching FTS.. exiting")
+ return False
+
+ while (is_connection_running.value == False and count < 12):
+ status = live_import.IsAppReady(byref(is_connection_running))
+ if (status < 0):
+ print("Live Import Internal Error %d" %(status))
+ return False
+ if (is_connection_running.value == False):
+ print("Waiting for 5 sec.. Open FTS Virtual Sniffing")
+ time.sleep(5)
+ count += 1
+ if (is_connection_running.value == True):
+ print ("FTS is ready to receive the data, Start capture now")
+ return True
+ else:
+ print("FTS Virtual Sniffing didn't start until 1 min.. exiting")
+ return False
+
+
+def init_live_import(conn_str, config_str):
+ """
+ Load DLL and Initialize the LiveImport module for FTS.
+ """
+ success = c_bool()
+ try:
+ live_import = CDLL(FTS_DLL_PATH + dllName)
+ except:
+ return None
+
+ if live_import is None:
+ print("Error: Path to LiveImportAPI.dll is incorrect.. exiting");
+ return None
+
+ print(dllName + " loaded successfully")
+ result = live_import.InitializeLiveImport(conn_str.encode('ascii', 'ignore'),
+ config_str.encode('ascii', 'ignore'),
+ byref(success))
+ if (result < 0):
+ print("Live Import Init failed")
+ return None
+ else:
+ print("Live Import Init success")
+ return live_import
+
+
+def release_live_import(live_import):
+ """
+ Cleanup and exit live import module.
+ """
+ if live_import is not None:
+ live_import.ReleaseLiveImport()
+ FreeLibrary(live_import._handle)
+
+
+def main():
+
+ print("Bluetooth Virtual Sniffing for Fluoride")
+ connection_str = get_connection_string()
+ if connection_str is None:
+ print("Error: path to liveimport.ini is incorrect.. exiting")
+ exit(0)
+
+ configuration_str = get_configuration_string()
+ if configuration_str is None:
+ print("Error: path to liveimport.ini is incorrect.. exiting")
+ exit(0)
+
+ live_import = init_live_import(connection_str, configuration_str)
+ if live_import is None:
+ print("Error: Path to LiveImportAPI.dll is incorrect.. exiting")
+ exit(0)
+
+ if (check_live_import_connection(live_import) == False):
+ release_live_import(live_import)
+ exit(0)
+
+ # Wait until the forward socket is ready
+ print("Waiting until adb is ready")
+ os.system('adb wait-for-device forward tcp:8872 tcp:8872')
+
+ btsnoop_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+ btsnoop_sock.connect((HOST, PORT))
+ snoop_id = btsnoop_sock.recv(SNOOP_ID)
+ if not snoop_id.startswith(b"btsnoop"):
+ print("Error: Snoop ID wasn't received.. exiting")
+ release_live_import(live_import)
+ exit(0)
+
+ while True:
+ try:
+ snoop_hdr = btsnoop_sock.recv(SNOOP_HDR)
+ if snoop_hdr is not None:
+ try:
+ olen, ilen, flags = struct.unpack(">LLL", snoop_hdr[0:12])
+ except struct.error:
+ print("Error: Invalid data", repr(snoop_hdr))
+ continue
+
+ file_time = get_file_time()
+ timestamp = c_longlong(file_time)
+
+ snoop_data = b''
+ while (len(snoop_data) < olen):
+ data_frag = btsnoop_sock.recv(olen - len(snoop_data))
+ if data_frag is not None:
+ snoop_data += data_frag
+
+ print ("Bytes received %d Olen %d ilen %d flags %d" % (len(snoop_data), olen, ilen, flags))
+ packet_type = struct.unpack(">B", snoop_data[0:1])[0]
+ if packet_type == 1:
+ drf = 1
+ isend = 0
+ elif packet_type == 2:
+ drf = 2
+ if (flags & 0x01):
+ isend = 1
+ else:
+ isend = 0
+ elif packet_type == 3:
+ drf = 4
+ if (flags & 0x01):
+ isend = 1
+ else:
+ isend = 0
+ elif packet_type == 4:
+ drf = 8
+ isend = 1
+
+ result = live_import.SendFrame(olen-1, olen-1, snoop_data[1:olen], drf, isend, timestamp)
+ if (result < 0):
+ print("Send frame failed")
+ except KeyboardInterrupt:
+ print("Cleanup and exit")
+ release_live_import(live_import)
+ btsnoop_sock.close()
+ exit(0)
+
+
+if __name__ == '__main__':
+ main()
+
diff --git a/tools/scripts/dump_hearingaid_audio.py b/tools/scripts/dump_hearingaid_audio.py
index 32d9a13..ca2eed2 100755
--- a/tools/scripts/dump_hearingaid_audio.py
+++ b/tools/scripts/dump_hearingaid_audio.py
@@ -20,7 +20,10 @@
# Generates a valid audio file which can be played using player like smplayer.
#
# Audio File Name Format:
-# [PEER_ADDRESS]-[START TIMESTAMP]-[AUDIO_TYPE]-[SAMPLE_RATE].[CODEC]
+# [PEER_ADDRESS]-[START_TIMESTAMP]-[AUDIO_TYPE]-[SAMPLE_RATE].[CODEC]
+#
+# Debug Infomation File Name Format:
+# debug_ver_[DEBUG_VERSION]-[PEER_ADDRESS]-[START_TIMESTAMP]-[AUDIO_TYPE]-[SAMPLE_RATE].txt
#
# Player:
# smplayer
@@ -41,15 +44,34 @@
CONNECTION_HANDLE = "CONNECTION_HANDLE"
AUDIO_CONTROL_ATTR_HANDLE = "AUDIO_CONTROL_ATTR_HANDLE"
START = "START"
-TIMESTAMP = "TIMESTAMP"
+TIMESTAMP_STR_FORMAT = "TIMESTAMP_STR_FORMAT"
+TIMESTAMP_TIME_FORMAT = "TIMESTAMP_TIME_FORMAT"
CODEC = "CODEC"
SAMPLE_RATE = "SAMPLE_RATE"
AUDIO_TYPE = "AUDIO_TYPE"
+DEBUG_VERSION = "DEBUG_VERSION"
+DEBUG_DATA = "DEBUG_DATA"
AUDIO_DATA_B = "AUDIO_DATA_B"
+# Debug packet header struct
+header_list_str = ["Event Processed",
+ "Number Packet Nacked By Slave",
+ "Number Packet Nacked By Master"]
+# Debug frame information structs
+data_list_str = ["Event Number",
+ "Overrun",
+ "Underrun",
+ "Skips",
+ "Rendered Audio Frame",
+ "First PDU Option",
+ "Second PDU Option",
+ "Third PDU Option"]
+
AUDIO_CONTROL_POINT_UUID = "f0d4de7e4a88476c9d9f1937b0996cc0"
SEC_CONVERT = 1000000
folder = None
+full_debug = False
+simple_debug = False
force_audio_control_attr_handle = None
default_audio_control_attr_handle = 0x0079
@@ -64,6 +86,39 @@
# Parse Hearing Aid Packet
#-----------------------------------------------------------------------
+def parse_acl_ha_debug_buffer(data, result):
+ """This function extracts HA debug buffer"""
+ if len(data) < 5:
+ return
+
+ version, data = unpack_data(data, 1)
+ update_audio_data(CONNECTION_HANDLE, result[CONNECTION_HANDLE], DEBUG_VERSION, str(version))
+
+ debug_str = result[TIMESTAMP_TIME_FORMAT];
+ for p in range(3):
+ byte_data, data = unpack_data(data, 1)
+ debug_str = debug_str + ", " + header_list_str[p] + "=" + str(byte_data).rjust(3)
+
+ if full_debug:
+ debug_str = debug_str + "\n" + "|".join(data_list_str) + "\n"
+ while True:
+ if len(data) < 7:
+ break
+ base = 0
+ data_list_content = []
+ for counter in range(6):
+ p = base + counter
+ byte_data, data = unpack_data(data, 1)
+ if p == 1:
+ data_list_content.append(str(byte_data & 0x03).rjust(len(data_list_str[p])))
+ data_list_content.append(str((byte_data >> 2) & 0x03).rjust(len(data_list_str[p + 1])))
+ data_list_content.append(str((byte_data >> 4) & 0x0f).rjust(len(data_list_str[p + 2])))
+ base = 2
+ else:
+ data_list_content.append(str(byte_data).rjust(len(data_list_str[p])))
+ debug_str = debug_str + "|".join(data_list_content) + "\n"
+
+ update_audio_data(CONNECTION_HANDLE, result[CONNECTION_HANDLE], DEBUG_DATA, debug_str)
def parse_acl_ha_audio_data(data, result):
"""This function extracts HA audio data."""
@@ -118,7 +173,7 @@
update_audio_data(CONNECTION_HANDLE, result[CONNECTION_HANDLE],
START, True)
update_audio_data(CONNECTION_HANDLE, result[CONNECTION_HANDLE],
- TIMESTAMP, result[TIMESTAMP])
+ TIMESTAMP_STR_FORMAT, result[TIMESTAMP_STR_FORMAT])
parse_acl_ha_codec(data, result)
elif control_cmd == 0x02:
update_audio_data(CONNECTION_HANDLE, result[CONNECTION_HANDLE],
@@ -188,11 +243,15 @@
if channel_id <= 0x003F:
result[CONNECTION_HANDLE] = connection_handle
parse_acl_opcode(data, result)
- elif result[IS_SENT] and channel_id >= 0x0040 and channel_id <= 0x007F:
+ elif channel_id >= 0x0040 and channel_id <= 0x007F:
result[CONNECTION_HANDLE] = connection_handle
sdu, data = unpack_data(data, 2)
if pdu - 2 == sdu:
- parse_acl_ha_audio_data(data, result)
+ if result[IS_SENT]:
+ parse_acl_ha_audio_data(data, result)
+ else:
+ if simple_debug:
+ parse_acl_ha_debug_buffer(data, result)
#=======================================================================
@@ -282,7 +341,7 @@
return False
if packet_flag != 2 and drop == 0:
packet_result[IS_SENT] = (packet_flag == 0)
- packet_result[TIMESTAMP] = convert_time_str(timestamp)
+ packet_result[TIMESTAMP_STR_FORMAT], packet_result[TIMESTAMP_TIME_FORMAT] = convert_time_str(timestamp)
parse_packet_data(packet_data, packet_result)
else:
return False
@@ -300,24 +359,42 @@
file_type = "." + data[CODEC]
file_name_list = []
file_name_list.append(data[PEER_ADDRESS])
- file_name_list.append(data[TIMESTAMP])
+ file_name_list.append(data[TIMESTAMP_STR_FORMAT])
file_name_list.append(data[AUDIO_TYPE])
file_name_list.append(data[SAMPLE_RATE])
if folder is not None:
if not os.path.exists(folder):
os.makedirs(folder)
- file_name = os.path.join(folder, "-".join(file_name_list) + file_type)
+ audio_file_name = os.path.join(folder, "-".join(file_name_list) + file_type)
+ if data.has_key(DEBUG_VERSION):
+ file_prefix = "debug_ver_" + data[DEBUG_VERSION] + "-"
+ debug_file_name = os.path.join(folder, file_prefix + "-".join(file_name_list) + ".txt")
else:
- file_name = "-".join(file_name_list) + file_type
- sys.stdout.write("Start to dump audio file : " + file_name + "\n")
+ audio_file_name = "-".join(file_name_list) + file_type
+ if data.has_key(DEBUG_VERSION):
+ file_prefix = "debug_ver_" + data[DEBUG_VERSION] + "-"
+ debug_file_name = file_prefix + "-".join(file_name_list) + ".txt"
+
+ sys.stdout.write("Start to dump Audio File : %s\n" % audio_file_name)
if data.has_key(AUDIO_DATA_B):
- with open(file_name, "wb+") as g722_file:
- g722_file.write(data[AUDIO_DATA_B])
- sys.stdout.write("Finished to dump Audio File: %s\n\n" % file_name)
+ with open(audio_file_name, "wb+") as audio_file:
+ audio_file.write(data[AUDIO_DATA_B])
+ sys.stdout.write("Finished to dump Audio File: %s\n\n" % audio_file_name)
else:
- sys.stdout.write("Fail to dump Audio File: %s\n" % file_name)
+ sys.stdout.write("Fail to dump Audio File: %s\n" % audio_file_name)
sys.stdout.write("There isn't any Hearing Aid audio data.\n\n")
+ if simple_debug:
+ sys.stdout.write("Start to dump audio %s Debug File\n" % audio_file_name)
+ if data.has_key(DEBUG_DATA):
+ with open(debug_file_name, "wb+") as debug_file:
+ debug_file.write(data[DEBUG_DATA])
+ sys.stdout.write("Finished to dump Debug File: %s\n\n" % debug_file_name)
+ else:
+ sys.stdout.write("Fail to dump audio %s Debug File\n" % audio_file_name)
+ sys.stdout.write("There isn't any Hearing Aid debug data.\n\n")
+
+
def update_audio_data(relate_key, relate_value, key, value):
"""
@@ -328,10 +405,12 @@
CONNECTION_HANDLE: CONNECTION_HANDLE,
AUDIO_CONTROL_ATTR_HANDLE: AUDIO_CONTROL_ATTR_HANDLE,
START: True or False,
- TIMESTAMP: START_TIMESTAMP,
+ TIMESTAMP_STR_FORMAT: START_TIMESTAMP_STR_FORMAT,
CODEC: CODEC,
SAMPLE_RATE: SAMPLE_RATE,
AUDIO_TYPE: AUDIO_TYPE,
+ DEBUG_VERSION: DEBUG_VERSION,
+ DEBUG_DATA: DEBUG_DATA,
AUDIO_DATA_B: AUDIO_DATA_B
},
PEER_ADDRESS_2:{
@@ -339,10 +418,12 @@
CONNECTION_HANDLE: CONNECTION_HANDLE,
AUDIO_CONTROL_ATTR_HANDLE: AUDIO_CONTROL_ATTR_HANDLE,
START: True or False,
- TIMESTAMP: START_TIMESTAMP,
+ TIMESTAMP_STR_FORMAT: START_TIMESTAMP_STR_FORMAT,
CODEC: CODEC,
SAMPLE_RATE: SAMPLE_RATE,
AUDIO_TYPE: AUDIO_TYPE,
+ DEBUG_VERSION: DEBUG_VERSION,
+ DEBUG_DATA: DEBUG_DATA,
AUDIO_DATA_B: AUDIO_DATA_B
}
}
@@ -368,16 +449,18 @@
# Clear data except PEER_ADDRESS, CONNECTION_HANDLE and
# AUDIO_CONTROL_ATTR_HANDLE.
audio_data[i].pop(key, "")
- audio_data[i].pop(TIMESTAMP, "")
+ audio_data[i].pop(TIMESTAMP_STR_FORMAT, "")
audio_data[i].pop(CODEC, "")
audio_data[i].pop(SAMPLE_RATE, "")
audio_data[i].pop(AUDIO_TYPE, "")
+ audio_data[i].pop(DEBUG_VERSION, "")
+ audio_data[i].pop(DEBUG_DATA, "")
audio_data[i].pop(AUDIO_DATA_B, "")
- elif key == AUDIO_DATA_B:
+ elif key == AUDIO_DATA_B or key == DEBUG_DATA:
if audio_data[i].has_key(START) and audio_data[i][START]:
- if audio_data[i].has_key(AUDIO_DATA_B):
- ori_audio_data = audio_data[i].pop(AUDIO_DATA_B, "")
- value = ori_audio_data + value
+ if audio_data[i].has_key(key):
+ ori_data = audio_data[i].pop(key, "")
+ value = ori_data + value
else:
# Audio doesn't start, don't record.
return
@@ -423,11 +506,15 @@
"""This function converts time to string format."""
really_timestamp = float(timestamp) / SEC_CONVERT
local_timestamp = time.localtime(really_timestamp)
- time_str = time.strftime("%m_%d__%H_%M_%S", local_timestamp)
dt = really_timestamp - long(really_timestamp)
ms_str = "{0:06}".format(int(round(dt * 1000000)))
- full_time_str = time_str + "_" + ms_str
- return full_time_str
+
+ str_format = time.strftime("%m_%d__%H_%M_%S", local_timestamp)
+ full_str_format = str_format + "_" + ms_str
+
+ time_format = time.strftime("%m-%d %H:%M:%S", local_timestamp)
+ full_time_format = time_format + "." + ms_str
+ return full_str_format, full_time_format
def set_config():
@@ -451,6 +538,12 @@
argv_parser.add_argument("-a", "--attr-handle",
help="force to select audio control attr handle.",
dest="audio_control_attr_handle", type=int)
+ argv_parser.add_argument("-d", "--debug",
+ help="dump full debug buffer content.",
+ dest="full_debug", default="False")
+ argv_parser.add_argument("-sd", "--simple-debug",
+ help="dump debug buffer header content.",
+ dest="simple_debug", default="False")
arg = argv_parser.parse_args()
if arg.folder is not None:
@@ -474,7 +567,7 @@
arg.connection_handle1)
if arg.no_start.lower() == "true":
update_audio_data(PEER_ADDRESS, fake_name, START, True)
- update_audio_data(PEER_ADDRESS, fake_name, TIMESTAMP, "Unknown")
+ update_audio_data(PEER_ADDRESS, fake_name, TIMESTAMP_STR_FORMAT, "Unknown")
update_audio_data(PEER_ADDRESS, fake_name, CODEC, arg.codec)
update_audio_data(PEER_ADDRESS, fake_name, SAMPLE_RATE, "Unknown")
update_audio_data(PEER_ADDRESS, fake_name, AUDIO_TYPE, "Unknown")
@@ -486,7 +579,7 @@
arg.connection_handle2)
if arg.no_start.lower() == "true":
update_audio_data(PEER_ADDRESS, fake_name, START, True)
- update_audio_data(PEER_ADDRESS, fake_name, TIMESTAMP, "Unknown")
+ update_audio_data(PEER_ADDRESS, fake_name, TIMESTAMP_STR_FORMAT, "Unknown")
update_audio_data(PEER_ADDRESS, fake_name, CODEC, arg.codec)
update_audio_data(PEER_ADDRESS, fake_name, SAMPLE_RATE, "Unknown")
update_audio_data(PEER_ADDRESS, fake_name, AUDIO_TYPE, "Unknown")
@@ -495,6 +588,14 @@
global force_audio_control_attr_handle
force_audio_control_attr_handle = arg.audio_control_attr_handle
+ global full_debug
+ global simple_debug
+ if arg.full_debug.lower() == "true":
+ full_debug = True
+ simple_debug = True
+ elif arg.simple_debug.lower() == "true":
+ simple_debug = True
+
if os.path.isfile(arg.BTSNOOP):
return arg.BTSNOOP
else:
diff --git a/types/class_of_device.h b/types/class_of_device.h
index 8c2ab37..4c37ebf 100644
--- a/types/class_of_device.h
+++ b/types/class_of_device.h
@@ -20,6 +20,9 @@
#include <string>
+namespace bluetooth {
+namespace types {
+
/** Bluetooth Class of Device */
class ClassOfDevice final {
public:
@@ -52,3 +55,8 @@
os << c.ToString();
return os;
}
+
+} // namespace types
+} // namespace bluetooth
+
+using ::bluetooth::types::ClassOfDevice; // TODO, remove
\ No newline at end of file
diff --git a/udrv/Android.bp b/udrv/Android.bp
index 9bf1d83..4605c53 100644
--- a/udrv/Android.bp
+++ b/udrv/Android.bp
@@ -5,15 +5,15 @@
"ulinux/uipc.cc",
],
include_dirs: [
- "system/bt",
- "system/bt/internal_include",
- "system/bt/utils/include",
- "system/bt/stack/include",
+ "system/bt",
+ "system/bt/internal_include",
+ "system/bt/utils/include",
+ "system/bt/stack/include",
],
local_include_dirs: [
- "include",
+ "include",
],
shared_libs: [
- "liblog",
+ "liblog",
],
}
diff --git a/vendor_libs/linux/interface/Android.bp b/vendor_libs/linux/interface/Android.bp
index 8d6caa4..e7d161e 100644
--- a/vendor_libs/linux/interface/Android.bp
+++ b/vendor_libs/linux/interface/Android.bp
@@ -14,7 +14,7 @@
// limitations under the License.
cc_binary {
- name: "android.hardware.bluetooth@1.0-service.btlinux",
+ name: "android.hardware.bluetooth@1.1-service.btlinux",
proprietary: true,
relative_install_path: "hw",
srcs: [
@@ -22,22 +22,23 @@
"h4_protocol.cc",
"bluetooth_hci.cc",
"async_fd_watcher.cc",
- "service.cc"
+ "service.cc",
],
- cflags: ["-Wall", "-Werror"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
header_libs: ["libbluetooth_headers"],
shared_libs: [
- "android.hardware.bluetooth@1.0",
+ "android.hardware.bluetooth@1.1",
"libbase",
"libcutils",
"libhidlbase",
- "libhidltransport",
"liblog",
"libutils",
],
conlyflags: [
"-std=c99",
],
- init_rc: ["android.hardware.bluetooth@1.0-service.btlinux.rc"],
+ init_rc: ["android.hardware.bluetooth@1.1-service.btlinux.rc"],
}
-
diff --git a/vendor_libs/linux/interface/android.hardware.bluetooth@1.0-service.btlinux.rc b/vendor_libs/linux/interface/android.hardware.bluetooth@1.0-service.btlinux.rc
deleted file mode 100644
index 36fbc2c..0000000
--- a/vendor_libs/linux/interface/android.hardware.bluetooth@1.0-service.btlinux.rc
+++ /dev/null
@@ -1,5 +0,0 @@
-service btlinux-1.0 /vendor/bin/hw/android.hardware.bluetooth@1.0-service.btlinux
- class hal
- user bluetooth
- group bluetooth net_admin net_bt_admin
- capabilities NET_ADMIN
diff --git a/vendor_libs/linux/interface/android.hardware.bluetooth@1.1-service.btlinux.rc b/vendor_libs/linux/interface/android.hardware.bluetooth@1.1-service.btlinux.rc
new file mode 100644
index 0000000..cb03de2
--- /dev/null
+++ b/vendor_libs/linux/interface/android.hardware.bluetooth@1.1-service.btlinux.rc
@@ -0,0 +1,5 @@
+service btlinux-1.1 /vendor/bin/hw/android.hardware.bluetooth@1.1-service.btlinux
+ class hal
+ user bluetooth
+ group bluetooth net_admin net_bt_admin
+ capabilities NET_ADMIN
diff --git a/vendor_libs/linux/interface/bluetooth_hci.cc b/vendor_libs/linux/interface/bluetooth_hci.cc
index 8d7e3f7..bd987d8 100644
--- a/vendor_libs/linux/interface/bluetooth_hci.cc
+++ b/vendor_libs/linux/interface/bluetooth_hci.cc
@@ -14,7 +14,7 @@
// limitations under the License.
//
-#define LOG_TAG "android.hardware.bluetooth@1.0-btlinux"
+#define LOG_TAG "android.hardware.bluetooth@1.1-btlinux"
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
@@ -66,7 +66,7 @@
namespace android {
namespace hardware {
namespace bluetooth {
-namespace V1_0 {
+namespace V1_1 {
namespace btlinux {
int BluetoothHci::openBtHci() {
@@ -245,9 +245,9 @@
public:
BluetoothDeathRecipient(const sp<IBluetoothHci> hci) : mHci(hci) {}
- virtual void serviceDied(
+ void serviceDied(
uint64_t /*cookie*/,
- const wp<::android::hidl::base::V1_0::IBase>& /*who*/) {
+ const wp<::android::hidl::base::V1_0::IBase>& /*who*/) override {
ALOGE("BluetoothDeathRecipient::serviceDied - Bluetooth service died");
has_died_ = true;
mHci->close();
@@ -264,7 +264,18 @@
: death_recipient_(new BluetoothDeathRecipient(this)) {}
Return<void> BluetoothHci::initialize(
- const ::android::sp<IBluetoothHciCallbacks>& cb) {
+ const ::android::sp<V1_0::IBluetoothHciCallbacks>& cb) {
+ return initialize_impl(cb, nullptr);
+}
+
+Return<void> BluetoothHci::initialize_1_1(
+ const ::android::sp<V1_1::IBluetoothHciCallbacks>& cb) {
+ return initialize_impl(cb, cb);
+}
+
+Return<void> BluetoothHci::initialize_impl(
+ const ::android::sp<V1_0::IBluetoothHciCallbacks>& cb,
+ const ::android::sp<V1_1::IBluetoothHciCallbacks>& cb_1_1) {
ALOGI("BluetoothHci::initialize()");
if (cb == nullptr) {
ALOGE("cb == nullptr! -> Unable to call initializationComplete(ERR)");
@@ -275,7 +286,7 @@
cb->linkToDeath(death_recipient_, 0);
int hci_fd = openBtHci();
auto hidl_status = cb->initializationComplete(
- hci_fd > 0 ? Status::SUCCESS : Status::INITIALIZATION_ERROR);
+ hci_fd > 0 ? V1_0::Status::SUCCESS : V1_0::Status::INITIALIZATION_ERROR);
if (!hidl_status.isOk()) {
ALOGE("VendorInterface -> Unable to call initializationComplete(ERR)");
}
@@ -283,7 +294,10 @@
hci_fd,
[cb](const hidl_vec<uint8_t>& packet) { cb->hciEventReceived(packet); },
[cb](const hidl_vec<uint8_t>& packet) { cb->aclDataReceived(packet); },
- [cb](const hidl_vec<uint8_t>& packet) { cb->scoDataReceived(packet); });
+ [cb](const hidl_vec<uint8_t>& packet) { cb->scoDataReceived(packet); },
+ [cb_1_1](const hidl_vec<uint8_t>& packet) {
+ cb_1_1->isoDataReceived(packet);
+ });
fd_watcher_.WatchFdForNonBlockingReads(
hci_fd, [h4_hci](int fd) { h4_hci->OnDataReady(fd); });
@@ -327,6 +341,11 @@
return Void();
}
+Return<void> BluetoothHci::sendIsoData(const hidl_vec<uint8_t>& data) {
+ sendDataToController(HCI_DATA_TYPE_ISO, data);
+ return Void();
+}
+
void BluetoothHci::sendDataToController(const uint8_t type,
const hidl_vec<uint8_t>& data) {
hci_handle_->Send(type, data.data(), data.size());
@@ -337,7 +356,7 @@
}
} // namespace btlinux
-} // namespace V1_0
+} // namespace V1_1
} // namespace bluetooth
} // namespace hardware
} // namespace android
diff --git a/vendor_libs/linux/interface/bluetooth_hci.h b/vendor_libs/linux/interface/bluetooth_hci.h
index 5dc1c0a..095c10c 100644
--- a/vendor_libs/linux/interface/bluetooth_hci.h
+++ b/vendor_libs/linux/interface/bluetooth_hci.h
@@ -14,10 +14,11 @@
// limitations under the License.
//
-#ifndef HIDL_GENERATED_android_hardware_bluetooth_V1_0_BluetoothHci_H_
-#define HIDL_GENERATED_android_hardware_bluetooth_V1_0_BluetoothHci_H_
+#ifndef HIDL_GENERATED_android_hardware_bluetooth_V1_1_BluetoothHci_H_
+#define HIDL_GENERATED_android_hardware_bluetooth_V1_1_BluetoothHci_H_
#include <android/hardware/bluetooth/1.0/IBluetoothHci.h>
+#include <android/hardware/bluetooth/1.1/IBluetoothHci.h>
#include <hidl/MQDescriptor.h>
@@ -28,7 +29,7 @@
namespace android {
namespace hardware {
namespace bluetooth {
-namespace V1_0 {
+namespace V1_1 {
namespace btlinux {
using ::android::hardware::Return;
@@ -40,13 +41,20 @@
public:
BluetoothHci();
Return<void> initialize(
- const ::android::sp<IBluetoothHciCallbacks>& cb) override;
+ const ::android::sp<V1_0::IBluetoothHciCallbacks>& cb) override;
+ Return<void> initialize_1_1(
+ const ::android::sp<V1_1::IBluetoothHciCallbacks>& cb) override;
Return<void> sendHciCommand(const hidl_vec<uint8_t>& packet) override;
Return<void> sendAclData(const hidl_vec<uint8_t>& data) override;
Return<void> sendScoData(const hidl_vec<uint8_t>& data) override;
+ Return<void> sendIsoData(const hidl_vec<uint8_t>& data) override;
Return<void> close() override;
private:
+ Return<void> initialize_impl(
+ const ::android::sp<V1_0::IBluetoothHciCallbacks>& cb,
+ const ::android::sp<V1_1::IBluetoothHciCallbacks>& cb_1_1);
+
async::AsyncFdWatcher fd_watcher_;
hci::H4Protocol* hci_handle_;
int bt_soc_fd_;
@@ -55,6 +63,7 @@
const uint8_t HCI_DATA_TYPE_COMMAND = 1;
const uint8_t HCI_DATA_TYPE_ACL = 2;
const uint8_t HCI_DATA_TYPE_SCO = 3;
+ const uint8_t HCI_DATA_TYPE_ISO = 5;
int waitHciDev(int hci_interface);
int findRfKill(void);
@@ -70,9 +79,9 @@
extern "C" IBluetoothHci* HIDL_FETCH_IBluetoothHci(const char* name);
} // namespace btlinux
-} // namespace V1_0
+} // namespace V1_1
} // namespace bluetooth
} // namespace hardware
} // namespace android
-#endif // HIDL_GENERATED_android_hardware_bluetooth_V1_0_BluetoothHci_H_
+#endif // HIDL_GENERATED_android_hardware_bluetooth_V1_1_BluetoothHci_H_
diff --git a/vendor_libs/linux/interface/h4_protocol.cc b/vendor_libs/linux/interface/h4_protocol.cc
index e7acff4..e7c0f62 100644
--- a/vendor_libs/linux/interface/h4_protocol.cc
+++ b/vendor_libs/linux/interface/h4_protocol.cc
@@ -67,6 +67,9 @@
case HCI_PACKET_TYPE_SCO_DATA:
sco_cb_(hci_packetizer_.GetPacket());
break;
+ case HCI_PACKET_TYPE_ISO_DATA:
+ iso_cb_(hci_packetizer_.GetPacket());
+ break;
default: {
bool bad_packet_type = true;
CHECK(!bad_packet_type);
diff --git a/vendor_libs/linux/interface/h4_protocol.h b/vendor_libs/linux/interface/h4_protocol.h
index 612b0db..92d6698 100644
--- a/vendor_libs/linux/interface/h4_protocol.h
+++ b/vendor_libs/linux/interface/h4_protocol.h
@@ -33,11 +33,12 @@
class H4Protocol {
public:
H4Protocol(int fd, PacketReadCallback event_cb, PacketReadCallback acl_cb,
- PacketReadCallback sco_cb)
+ PacketReadCallback sco_cb, PacketReadCallback iso_cb)
: uart_fd_(fd),
event_cb_(event_cb),
acl_cb_(acl_cb),
sco_cb_(sco_cb),
+ iso_cb_(iso_cb),
hci_packetizer_([this]() { OnPacketReady(); }) {}
size_t Send(uint8_t type, const uint8_t* data, size_t length);
@@ -52,6 +53,7 @@
PacketReadCallback event_cb_;
PacketReadCallback acl_cb_;
PacketReadCallback sco_cb_;
+ PacketReadCallback iso_cb_;
HciPacketType hci_packet_type_{HCI_PACKET_TYPE_UNKNOWN};
HciPacketizer hci_packetizer_;
diff --git a/vendor_libs/linux/interface/hci_internals.h b/vendor_libs/linux/interface/hci_internals.h
index 1e1f300..24e944f 100644
--- a/vendor_libs/linux/interface/hci_internals.h
+++ b/vendor_libs/linux/interface/hci_internals.h
@@ -24,7 +24,8 @@
HCI_PACKET_TYPE_COMMAND = 1,
HCI_PACKET_TYPE_ACL_DATA = 2,
HCI_PACKET_TYPE_SCO_DATA = 3,
- HCI_PACKET_TYPE_EVENT = 4
+ HCI_PACKET_TYPE_EVENT = 4,
+ HCI_PACKET_TYPE_ISO_DATA = 5,
};
// 2 bytes for opcode, 1 byte for parameter length (Volume 2, Part E, 5.4.1)
diff --git a/vendor_libs/linux/interface/service.cc b/vendor_libs/linux/interface/service.cc
index fac9ce0..4efd5e7 100644
--- a/vendor_libs/linux/interface/service.cc
+++ b/vendor_libs/linux/interface/service.cc
@@ -14,20 +14,20 @@
// limitations under the License.
//
-#define LOG_TAG "android.hardware.bluetooth@1.0-service.btlinux"
+#define LOG_TAG "android.hardware.bluetooth@1.1-service.btlinux"
-#include <android/hardware/bluetooth/1.0/IBluetoothHci.h>
+#include <android/hardware/bluetooth/1.1/IBluetoothHci.h>
#include <hidl/HidlSupport.h>
#include <hidl/HidlTransportSupport.h>
#include <utils/Log.h>
#include "bluetooth_hci.h"
-using ::android::hardware::configureRpcThreadpool;
-using ::android::hardware::bluetooth::V1_0::IBluetoothHci;
-using ::android::hardware::bluetooth::V1_0::btlinux::BluetoothHci;
-using ::android::hardware::joinRpcThreadpool;
using ::android::sp;
+using ::android::hardware::configureRpcThreadpool;
+using ::android::hardware::joinRpcThreadpool;
+using ::android::hardware::bluetooth::V1_1::IBluetoothHci;
+using ::android::hardware::bluetooth::V1_1::btlinux::BluetoothHci;
int main(int /* argc */, char** /* argv */) {
sp<IBluetoothHci> bluetooth = new BluetoothHci;
diff --git a/vendor_libs/test_vendor_lib/Android.bp b/vendor_libs/test_vendor_lib/Android.bp
index aded1c3..16662c2 100644
--- a/vendor_libs/test_vendor_lib/Android.bp
+++ b/vendor_libs/test_vendor_lib/Android.bp
@@ -35,6 +35,8 @@
"model/setup/test_channel_transport.cc",
"model/setup/test_command_handler.cc",
"model/setup/test_model.cc",
+ ":BluetoothPacketSources",
+ ":BluetoothHciClassSources",
],
cflags: [
"-fvisibility=hidden",
@@ -47,23 +49,18 @@
"include",
".",
],
- header_libs: [
- "libbluetooth_headers",
+ generated_headers: [
+ "RootCanalGeneratedPackets_h",
+ "BluetoothGeneratedPackets_h",
],
include_dirs: [
"system/bt",
- "system/bt/utils/include",
- "system/bt/hci/include",
- "system/bt/internal_include",
- "system/bt/stack/include",
+ "system/bt/gd",
],
shared_libs: [
"libbase",
"liblog",
],
- whole_static_libs: [
- "libbt-rootcanal-packets",
- ],
static_libs: [
"libbt-rootcanal-types",
],
@@ -90,9 +87,7 @@
],
include_dirs: [
"system/bt",
- "system/bt/utils/include",
- "system/bt/hci/include",
- "system/bt/stack/include",
+ "system/bt/gd",
],
shared_libs: [
"liblog",
@@ -126,9 +121,11 @@
],
include_dirs: [
"system/bt",
- "system/bt/utils/include",
- "system/bt/hci/include",
- "system/bt/stack/include",
+ "system/bt/gd",
+ ],
+ generated_headers: [
+ "RootCanalGeneratedPackets_h",
+ "BluetoothGeneratedPackets_h",
],
shared_libs: [
"liblog",
@@ -138,3 +135,17 @@
"libbt-rootcanal",
],
}
+
+genrule {
+ name: "RootCanalGeneratedPackets_h",
+ tools: [
+ "bluetooth_packetgen",
+ ],
+ cmd: "$(location bluetooth_packetgen) --root_namespace=model --include=system/bt/vendor_libs/test_vendor_lib --out=$(genDir) $(in)",
+ srcs: [
+ "packets/link_layer_packets.pdl",
+ ],
+ out: [
+ "packets/link_layer_packets.h",
+ ],
+}
diff --git a/vendor_libs/test_vendor_lib/data/controller_properties.json b/vendor_libs/test_vendor_lib/data/controller_properties.json
index 32adc52..814efd3 100644
--- a/vendor_libs/test_vendor_lib/data/controller_properties.json
+++ b/vendor_libs/test_vendor_lib/data/controller_properties.json
@@ -1,5 +1,6 @@
{
"AclDataPacketSize": "1024",
+ "EncryptionKeySize": "10",
"ScoDataPacketSize": "255",
"NumAclDataPackets": "10",
"NumScoDataPackets": "10",
diff --git a/vendor_libs/test_vendor_lib/desktop/root_canal_main.cc b/vendor_libs/test_vendor_lib/desktop/root_canal_main.cc
index 5432292..95bbfd3 100644
--- a/vendor_libs/test_vendor_lib/desktop/root_canal_main.cc
+++ b/vendor_libs/test_vendor_lib/desktop/root_canal_main.cc
@@ -14,15 +14,11 @@
// limitations under the License.
//
-#define LOG_TAG "root_canal"
-
#include "test_environment.h"
-#include <base/logging.h>
-#include <utils/Log.h>
#include <future>
-#include "hci_internals.h"
+#include "os/log.h"
using ::android::bluetooth::root_canal::TestEnvironment;
@@ -31,16 +27,16 @@
constexpr uint16_t kLinkServerPort = 6403;
int main(int argc, char** argv) {
- ALOGI("main");
+ LOG_INFO("main");
uint16_t test_port = kTestPort;
uint16_t hci_server_port = kHciServerPort;
uint16_t link_server_port = kLinkServerPort;
for (int arg = 0; arg < argc; arg++) {
int port = atoi(argv[arg]);
- ALOGI("%d: %s (%d)", arg, argv[arg], port);
+ LOG_INFO("%d: %s (%d)", arg, argv[arg], port);
if (port < 0 || port > 0xffff) {
- ALOGW("%s out of range", argv[arg]);
+ LOG_WARN("%s out of range", argv[arg]);
} else {
switch (arg) {
case 0: // executable name
@@ -55,7 +51,7 @@
link_server_port = port;
break;
default:
- ALOGW("Ignored option %s", argv[arg]);
+ LOG_WARN("Ignored option %s", argv[arg]);
}
}
}
diff --git a/vendor_libs/test_vendor_lib/desktop/test_environment.cc b/vendor_libs/test_vendor_lib/desktop/test_environment.cc
index 542738d..f787c51 100644
--- a/vendor_libs/test_vendor_lib/desktop/test_environment.cc
+++ b/vendor_libs/test_vendor_lib/desktop/test_environment.cc
@@ -14,17 +14,15 @@
// limitations under the License.
//
-#define LOG_TAG "root_canal"
-
#include "test_environment.h"
-#include <base/logging.h>
+#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
-#include <utils/Log.h>
+#include <unistd.h>
-#include "hci_internals.h"
+#include "os/log.h"
namespace android {
namespace bluetooth {
@@ -35,7 +33,7 @@
using test_vendor_lib::TaskCallback;
void TestEnvironment::initialize(std::promise<void> barrier) {
- ALOGI("%s", __func__);
+ LOG_INFO("%s", __func__);
barrier_ = std::move(barrier);
@@ -50,34 +48,34 @@
SetUpHciServer([this](int fd) { test_model_.IncomingHciConnection(fd); });
SetUpLinkLayerServer([this](int fd) { test_model_.IncomingLinkLayerConnection(fd); });
- ALOGI("%s: Finished", __func__);
+ LOG_INFO("%s: Finished", __func__);
}
void TestEnvironment::close() {
- ALOGI("%s", __func__);
+ LOG_INFO("%s", __func__);
}
void TestEnvironment::SetUpHciServer(const std::function<void(int)>& connection_callback) {
int socket_fd = remote_hci_transport_.SetUp(hci_server_port_);
test_channel_.RegisterSendResponse(
- [](const std::string& response) { ALOGI("No HCI Response channel: %s", response.c_str()); });
+ [](const std::string& response) { LOG_INFO("No HCI Response channel: %s", response.c_str()); });
if (socket_fd == -1) {
- ALOGE("Remote HCI channel SetUp(%d) failed.", hci_server_port_);
+ LOG_ERROR("Remote HCI channel SetUp(%d) failed.", hci_server_port_);
return;
}
async_manager_.WatchFdForNonBlockingReads(socket_fd, [this, connection_callback](int socket_fd) {
int conn_fd = remote_hci_transport_.Accept(socket_fd);
if (conn_fd < 0) {
- ALOGE("Error watching remote HCI channel fd.");
+ LOG_ERROR("Error watching remote HCI channel fd.");
return;
}
int flags = fcntl(conn_fd, F_GETFL, NULL);
int ret;
ret = fcntl(conn_fd, F_SETFL, flags | O_NONBLOCK);
- CHECK(ret != -1) << "Error setting O_NONBLOCK " << strerror(errno);
+ ASSERT_LOG(ret != -1, "Error setting O_NONBLOCK %s", strerror(errno));
connection_callback(conn_fd);
});
@@ -87,22 +85,22 @@
int socket_fd = remote_link_layer_transport_.SetUp(link_server_port_);
test_channel_.RegisterSendResponse(
- [](const std::string& response) { ALOGI("No LinkLayer Response channel: %s", response.c_str()); });
+ [](const std::string& response) { LOG_INFO("No LinkLayer Response channel: %s", response.c_str()); });
if (socket_fd == -1) {
- ALOGE("Remote LinkLayer channel SetUp(%d) failed.", link_server_port_);
+ LOG_ERROR("Remote LinkLayer channel SetUp(%d) failed.", link_server_port_);
return;
}
async_manager_.WatchFdForNonBlockingReads(socket_fd, [this, connection_callback](int socket_fd) {
int conn_fd = remote_link_layer_transport_.Accept(socket_fd);
if (conn_fd < 0) {
- ALOGE("Error watching remote LinkLayer channel fd.");
+ LOG_ERROR("Error watching remote LinkLayer channel fd.");
return;
}
int flags = fcntl(conn_fd, F_GETFL, NULL);
int ret = fcntl(conn_fd, F_SETFL, flags | O_NONBLOCK);
- CHECK(ret != -1) << "Error setting O_NONBLOCK " << strerror(errno);
+ ASSERT_LOG(ret != -1, "Error setting O_NONBLOCK %s", strerror(errno));
connection_callback(conn_fd);
});
@@ -111,14 +109,14 @@
int TestEnvironment::ConnectToRemoteServer(const std::string& server, int port) {
int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd < 1) {
- ALOGI("socket() call failed: %s", strerror(errno));
+ LOG_INFO("socket() call failed: %s", strerror(errno));
return -1;
}
struct hostent* host;
host = gethostbyname(server.c_str());
if (host == NULL) {
- ALOGI("gethostbyname() failed for %s: %s", server.c_str(), strerror(errno));
+ LOG_INFO("gethostbyname() failed for %s: %s", server.c_str(), strerror(errno));
return -1;
}
@@ -130,37 +128,41 @@
int result = connect(socket_fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
if (result < 0) {
- ALOGI("connect() failed for %s@%d: %s", server.c_str(), port, strerror(errno));
+ LOG_INFO("connect() failed for %s@%d: %s", server.c_str(), port, strerror(errno));
return -1;
}
int flags = fcntl(socket_fd, F_GETFL, NULL);
int ret = fcntl(socket_fd, F_SETFL, flags | O_NONBLOCK);
- CHECK(ret != -1) << "Error setting O_NONBLOCK " << strerror(errno);
+ ASSERT_LOG(ret != -1, "Error setting O_NONBLOCK %s", strerror(errno));
return socket_fd;
}
void TestEnvironment::SetUpTestChannel() {
int socket_fd = test_channel_transport_.SetUp(test_port_);
+ test_channel_.AddPhy({"BR_EDR"});
+ test_channel_.AddPhy({"LOW_ENERGY"});
+ test_channel_.SetTimerPeriod({"10"});
+ test_channel_.StartTimer({});
test_channel_.RegisterSendResponse(
- [](const std::string& response) { ALOGI("No test channel: %s", response.c_str()); });
+ [](const std::string& response) { LOG_INFO("No test channel: %s", response.c_str()); });
if (socket_fd == -1) {
- ALOGE("Test channel SetUp(%d) failed.", test_port_);
+ LOG_ERROR("Test channel SetUp(%d) failed.", test_port_);
return;
}
- ALOGI("Test channel SetUp() successful");
+ LOG_INFO("Test channel SetUp() successful");
async_manager_.WatchFdForNonBlockingReads(socket_fd, [this](int socket_fd) {
int conn_fd = test_channel_transport_.Accept(socket_fd);
if (conn_fd < 0) {
- ALOGE("Error watching test channel fd.");
+ LOG_ERROR("Error watching test channel fd.");
barrier_.set_value();
return;
}
- ALOGI("Test channel connection accepted.");
+ LOG_INFO("Test channel connection accepted.");
test_channel_.RegisterSendResponse(
[this, conn_fd](const std::string& response) { test_channel_transport_.SendResponse(conn_fd, response); });
diff --git a/vendor_libs/test_vendor_lib/include/hci.h b/vendor_libs/test_vendor_lib/include/hci.h
index 11eb029..eaa74c0 100644
--- a/vendor_libs/test_vendor_lib/include/hci.h
+++ b/vendor_libs/test_vendor_lib/include/hci.h
@@ -17,11 +17,6 @@
#pragma once
#include <cstdint>
-#include "include/hci/event_code.h"
-#include "include/hci/le_sub_event_code.h"
-#include "include/hci/op_code.h"
-#include "include/hci/status.h"
-
namespace test_vendor_lib {
namespace hci {
@@ -33,31 +28,5 @@
EVENT = 4,
};
-enum class LinkType : uint8_t {
- SCO = 0x00,
- ACL = 0x01,
- ESCO = 0x02,
-};
-
-enum class LoopbackMode : uint8_t {
- NO = 0x00,
- LOCAL = 0x01,
- REMOTE = 0x02,
-};
-
-/* HCI, PAL, and LMP Version numbers are the same */
-enum class Version : uint8_t {
- V1_0 = 0,
- V1_1 = 1,
- V1_2 = 2,
- V2_0 = 3,
- V2_1 = 4,
- V3_0 = 5,
- V4_0 = 6,
- V4_1 = 7,
- V4_2 = 8,
- V5_0 = 9,
-};
-
} // namespace hci
} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/hci/event_code.h b/vendor_libs/test_vendor_lib/include/hci/event_code.h
deleted file mode 100644
index c0bdcbc..0000000
--- a/vendor_libs/test_vendor_lib/include/hci/event_code.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-#include <cstdint>
-
-namespace test_vendor_lib {
-namespace hci {
-
-enum class EventCode : uint8_t {
- INQUIRY_COMPLETE = 0x01,
- INQUIRY_RESULT = 0x02,
- CONNECTION_COMPLETE = 0x03,
- CONNECTION_REQUEST = 0x04,
- DISCONNECTION_COMPLETE = 0x05,
- AUTHENTICATION_COMPLETE = 0x06,
- REMOTE_NAME_REQUEST_COMPLETE = 0x07,
- ENCRYPTION_CHANGE = 0x08,
- CHANGE_CONNECTION_LINK_KEY_COMPLETE = 0x09,
- MASTER_LINK_KEY_COMPLETE = 0x0A,
- READ_REMOTE_SUPPORTED_FEATURES_COMPLETE = 0x0B,
- READ_REMOTE_VERSION_INFORMATION_COMPLETE = 0x0C,
- QOS_SETUP_COMPLETE = 0x0D,
- COMMAND_COMPLETE = 0x0E,
- COMMAND_STATUS = 0x0F,
- HARDWARE_ERROR = 0x10,
- FLUSH_OCCURED = 0x11,
- ROLE_CHANGE = 0x12,
- NUMBER_OF_COMPLETED_PACKETS = 0x13,
- MODE_CHANGE = 0x14,
- RETURN_LINK_KEYS = 0x15,
- PIN_CODE_REQUEST = 0x16,
- LINK_KEY_REQUEST = 0x17,
- LINK_KEY_NOTIFICATION = 0x18,
- LOOPBACK_COMMAND = 0x19,
- DATA_BUFFER_OVERFLOW = 0x1A,
- MAX_SLOTS_CHANGE = 0x1B,
- READ_CLOCK_OFFSET_COMPLETE = 0x1C,
- CONNECTION_PACKET_TYPE_CHANGE = 0x1D,
- QOS_VIOLATION = 0x1E,
- PAGE_SCAN_REPETITION_MODE_CHANGE = 0x20,
- FLOW_SPECIFICATION_COMPLETE = 0x21,
- INQUIRY_RESULT_WITH_RSSI = 0x22,
- READ_REMOTE_EXTENDED_FEATURES_COMPLETE = 0x23,
- SYNCHRONOUS_CONNECTION_COMPLETE = 0x2C,
- SYNCHRONOUS_CONNECTION_CHANGED = 0x2D,
- SNIFF_SUBRATING = 0x2E,
- EXTENDED_INQUIRY_RESULT = 0x2F,
- ENCRYPTION_KEY_REFRESH_COMPLETE = 0x30,
- IO_CAPABILITY_REQUEST = 0x31,
- IO_CAPABILITY_RESPONSE = 0x32,
- USER_CONFIRMATION_REQUEST = 0x33,
- USER_PASSKEY_REQUEST = 0x34,
- REMOTE_OOB_DATA_REQUEST = 0x35,
- SIMPLE_PAIRING_COMPLETE = 0x36,
- LINK_SUPERVISION_TIMEOUT_CHANGED = 0x38,
- ENHANCED_FLUSH_COMPLETE = 0x39,
- USER_PASSKEY_NOTIFICATION = 0x3B,
- KEYPRESS_NOTIFICATION = 0x3C,
- REMOTE_HOST_SUPPORTED_FEATURES_NOTIFICATION = 0x3D,
- LE_META_EVENT = 0x3e,
- PHYSICAL_LINK_COMPLETE = 0x40,
- CHANNEL_SELECTED = 0x41,
- DISCONNECTION_PHYSICAL_LINK_COMPLETE = 0x42,
- PHYSICAL_LINK_LOSS_EARLY_WARNING = 0x43,
- PHYSICAL_LINK_RECOVERY = 0x44,
- LOGICAL_LINK_COMPLETE = 0x45,
- DISCONNECTION_LOGICAL_LINK_COMPLETE = 0x46,
- FLOW_SPEC_MODIFY_COMPLETE = 0x47,
- NUMBER_OF_COMPLETED_DATA_BLOCKS = 0x48,
- SHORT_RANGE_MODE_CHANGE_COMPLETE = 0x4C,
-};
-}
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/hci/le_sub_event_code.h b/vendor_libs/test_vendor_lib/include/hci/le_sub_event_code.h
deleted file mode 100644
index 42edecd..0000000
--- a/vendor_libs/test_vendor_lib/include/hci/le_sub_event_code.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-#include <cstdint>
-
-namespace test_vendor_lib {
-namespace hci {
-
-enum class LeSubEventCode : uint8_t {
- CONNECTION_COMPLETE = 0x01,
- ADVERTISING_REPORT = 0x02,
- CONNECTION_UPDATE_COMPLETE = 0x03,
- READ_REMOTE_FEATURES_COMPLETE = 0x04,
- LONG_TERM_KEY_REQUEST = 0x05,
- REMOTE_CONNECTION_PARAMETER_REQUEST = 0x06,
- DATA_LENGTH_CHANGE = 0x07,
- ENHANCED_CONNECTION_COMPLETE = 0x0a,
- DIRECTED_ADVERTISING_REPORT = 0x0b,
- PHY_UPDATE_COMPLETE = 0x0c,
- EXTENDED_ADVERTISING_REPORT = 0x0D,
- PERIODIC_ADVERTISING_SYNC_ESTABLISHED = 0x0E,
- PERIODIC_ADVERTISING_REPORT = 0x0F,
- PERIODIC_ADVERTISING_SYNC_LOST = 0x10,
- SCAN_TIMEOUT = 0x11,
- ADVERTISING_SET_TERMINATED = 0x12,
- SCAN_REQUEST_RECEIVED = 0x13,
-};
-}
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/hci/op_code.h b/vendor_libs/test_vendor_lib/include/hci/op_code.h
deleted file mode 100644
index 931145d..0000000
--- a/vendor_libs/test_vendor_lib/include/hci/op_code.h
+++ /dev/null
@@ -1,281 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-#include <cstdint>
-
-namespace test_vendor_lib {
-namespace hci {
-
-using CommandGroups = enum {
- LINK_CONTROL = 0x01 << 10, /* 0x0400 */
- LINK_POLICY = 0x02 << 10, /* 0x0800 */
- CONTROLLER_AND_BASEBAND = 0x03 << 10, /* 0x0C00 */
- INFORMATIONAL_PARAMETERS = 0x04 << 10, /* 0x1000 */
- STATUS_PARAMETERS = 0x05 << 10, /* 0x1400 */
- TESTING = 0x06 << 10, /* 0x1800 */
- LE_CONTROLLER = 0x08 << 10, /* 0x2000 */
- VENDOR_SPECIFIC = 0x3F << 10, /* 0xFC00 */
-};
-
-enum class OpCode : uint16_t {
- NONE = 0x0000,
-
- /* LINK_CONTROL */
- INQUIRY = LINK_CONTROL | 0x0001,
- INQUIRY_CANCEL = LINK_CONTROL | 0x0002,
- PERIODIC_INQUIRY_MODE = LINK_CONTROL | 0x0003,
- EXIT_PERIODIC_INQUIRY_MODE = LINK_CONTROL | 0x0004,
- CREATE_CONNECTION = LINK_CONTROL | 0x0005,
- DISCONNECT = LINK_CONTROL | 0x0006,
- CREATE_CONNECTION_CANCEL = LINK_CONTROL | 0x0008,
- ACCEPT_CONNECTION_REQUEST = LINK_CONTROL | 0x0009,
- REJECT_CONNECTION_REQUEST = LINK_CONTROL | 0x000A,
- LINK_KEY_REQUEST_REPLY = LINK_CONTROL | 0x000B,
- LINK_KEY_REQUEST_NEGATIVE_REPLY = LINK_CONTROL | 0x000C,
- PIN_CODE_REQUEST_REPLY = LINK_CONTROL | 0x000D,
- PIN_CODE_REQUEST_NEGATIVE_REPLY = LINK_CONTROL | 0x000E,
- CHANGE_CONNECTION_PACKET_TYPE = LINK_CONTROL | 0x000F,
- AUTHENTICATION_REQUESTED = LINK_CONTROL | 0x0011,
- SET_CONNECTION_ENCRYPTION = LINK_CONTROL | 0x0013,
- CHANGE_CONNECTION_LINK_KEY = LINK_CONTROL | 0x0015,
- MASTER_LINK_KEY = LINK_CONTROL | 0x0017,
- REMOTE_NAME_REQUEST = LINK_CONTROL | 0x0019,
- REMOTE_NAME_REQUEST_CANCEL = LINK_CONTROL | 0x001A,
- READ_REMOTE_SUPPORTED_FEATURES = LINK_CONTROL | 0x001B,
- READ_REMOTE_EXTENDED_FEATURES = LINK_CONTROL | 0x001C,
- READ_REMOTE_VERSION_INFORMATION = LINK_CONTROL | 0x001D,
- READ_CLOCK_OFFSET = LINK_CONTROL | 0x001F,
- READ_LMP_HANDLE = LINK_CONTROL | 0x0020,
- SETUP_SYNCHRONOUS_CONNECTION = LINK_CONTROL | 0x0028,
- ACCEPT_SYNCHRONOUS_CONNECTION = LINK_CONTROL | 0x0029,
- REJECT_SYNCHRONOUS_CONNECTION = LINK_CONTROL | 0x002A,
- IO_CAPABILITY_REQUEST_REPLY = LINK_CONTROL | 0x002B,
- USER_CONFIRMATION_REQUEST_REPLY = LINK_CONTROL | 0x002C,
- USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY = LINK_CONTROL | 0x002D,
- USER_PASSKEY_REQUEST_REPLY = LINK_CONTROL | 0x002E,
- USER_PASSKEY_REQUEST_NEGATIVE_REPLY = LINK_CONTROL | 0x002F,
- REMOTE_OOB_DATA_REQUEST_REPLY = LINK_CONTROL | 0x0030,
- REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY = LINK_CONTROL | 0x0033,
- IO_CAPABILITY_REQUEST_NEGATIVE_REPLY = LINK_CONTROL | 0x0034,
- ENHANCED_SETUP_SYNCHRONOUS_CONNECTION = LINK_CONTROL | 0x003D,
- ENHANCED_ACCEPT_SYNCHRONOUS_CONNECTION = LINK_CONTROL | 0x003E,
-
- /* LINK_POLICY */
- HOLD_MODE = LINK_POLICY | 0x0001,
- SNIFF_MODE = LINK_POLICY | 0x0003,
- EXIT_SNIFF_MODE = LINK_POLICY | 0x0004,
- QOS_SETUP = LINK_POLICY | 0x0007,
- ROLE_DISCOVERY = LINK_POLICY | 0x0009,
- SWITCH_ROLE = LINK_POLICY | 0x000B,
- READ_LINK_POLICY_SETTINGS = LINK_POLICY | 0x000C,
- WRITE_LINK_POLICY_SETTINGS = LINK_POLICY | 0x000D,
- READ_DEFAULT_LINK_POLICY_SETTINGS = LINK_POLICY | 0x000E,
- WRITE_DEFAULT_LINK_POLICY_SETTINGS = LINK_POLICY | 0x000F,
- FLOW_SPECIFICATION = LINK_POLICY | 0x0010,
- SNIFF_SUBRATING = LINK_POLICY | 0x0011,
-
- /* CONTROLLER_AND_BASEBAND */
- SET_EVENT_MASK = CONTROLLER_AND_BASEBAND | 0x0001,
- RESET = CONTROLLER_AND_BASEBAND | 0x0003,
- SET_EVENT_FILTER = CONTROLLER_AND_BASEBAND | 0x0005,
- FLUSH = CONTROLLER_AND_BASEBAND | 0x0008,
- READ_PIN_TYPE = CONTROLLER_AND_BASEBAND | 0x0009,
- WRITE_PIN_TYPE = CONTROLLER_AND_BASEBAND | 0x000A,
- CREATE_NEW_UNIT_KEY = CONTROLLER_AND_BASEBAND | 0x000B,
- READ_STORED_LINK_KEY = CONTROLLER_AND_BASEBAND | 0x000D,
- WRITE_STORED_LINK_KEY = CONTROLLER_AND_BASEBAND | 0x0011,
- DELETE_STORED_LINK_KEY = CONTROLLER_AND_BASEBAND | 0x0012,
- WRITE_LOCAL_NAME = CONTROLLER_AND_BASEBAND | 0x0013,
- READ_LOCAL_NAME = CONTROLLER_AND_BASEBAND | 0x0014,
- READ_CONNECTION_ACCEPT_TIMEOUT = CONTROLLER_AND_BASEBAND | 0x0015,
- WRITE_CONNECTION_ACCEPT_TIMEOUT = CONTROLLER_AND_BASEBAND | 0x0016,
- READ_PAGE_TIMEOUT = CONTROLLER_AND_BASEBAND | 0x0017,
- WRITE_PAGE_TIMEOUT = CONTROLLER_AND_BASEBAND | 0x0018,
- READ_SCAN_ENABLE = CONTROLLER_AND_BASEBAND | 0x0019,
- WRITE_SCAN_ENABLE = CONTROLLER_AND_BASEBAND | 0x001A,
- READ_PAGE_SCAN_ACTIVITY = CONTROLLER_AND_BASEBAND | 0x001B,
- WRITE_PAGE_SCAN_ACTIVITY = CONTROLLER_AND_BASEBAND | 0x001C,
- READ_INQUIRY_SCAN_ACTIVITY = CONTROLLER_AND_BASEBAND | 0x001D,
- WRITE_INQUIRY_SCAN_ACTIVITY = CONTROLLER_AND_BASEBAND | 0x001E,
- READ_AUTHENTICATION_ENABLE = CONTROLLER_AND_BASEBAND | 0x001F,
- WRITE_AUTHENTICATION_ENABLE = CONTROLLER_AND_BASEBAND | 0x0020,
- READ_CLASS_OF_DEVICE = CONTROLLER_AND_BASEBAND | 0x0023,
- WRITE_CLASS_OF_DEVICE = CONTROLLER_AND_BASEBAND | 0x0024,
- READ_VOICE_SETTING = CONTROLLER_AND_BASEBAND | 0x0025,
- WRITE_VOICE_SETTING = CONTROLLER_AND_BASEBAND | 0x0026,
- READ_AUTOMATIC_FLUSH_TIMEOUT = CONTROLLER_AND_BASEBAND | 0x0027,
- WRITE_AUTOMATIC_FLUSH_TIMEOUT = CONTROLLER_AND_BASEBAND | 0x0028,
- READ_NUM_BROADCAST_RETRANSMITS = CONTROLLER_AND_BASEBAND | 0x0029,
- WRITE_NUM_BROADCAST_RETRANSMITS = CONTROLLER_AND_BASEBAND | 0x002A,
- READ_HOLD_MODE_ACTIVITY = CONTROLLER_AND_BASEBAND | 0x002B,
- WRITE_HOLD_MODE_ACTIVITY = CONTROLLER_AND_BASEBAND | 0x002C,
- READ_TRANSMIT_POWER_LEVEL = CONTROLLER_AND_BASEBAND | 0x002D,
- READ_SYNCHRONOUS_FLOW_CONTROL_ENABLE = CONTROLLER_AND_BASEBAND | 0x002E,
- WRITE_SYNCHRONOUS_FLOW_CONTROL_ENABLE = CONTROLLER_AND_BASEBAND | 0x002F,
- SET_CONTROLLER_TO_HOST_FLOW_CONTROL = CONTROLLER_AND_BASEBAND | 0x0031,
- HOST_BUFFER_SIZE = CONTROLLER_AND_BASEBAND | 0x0033,
- HOST_NUM_COMPLETED_PACKETS = CONTROLLER_AND_BASEBAND | 0x0035,
- READ_LINK_SUPERVISION_TIMEOUT = CONTROLLER_AND_BASEBAND | 0x0036,
- WRITE_LINK_SUPERVISION_TIMEOUT = CONTROLLER_AND_BASEBAND | 0x0037,
- READ_NUMBER_OF_SUPPORTED_IAC = CONTROLLER_AND_BASEBAND | 0x0038,
- READ_CURRENT_IAC_LAP = CONTROLLER_AND_BASEBAND | 0x0039,
- WRITE_CURRENT_IAC_LAP = CONTROLLER_AND_BASEBAND | 0x003A,
- SET_AFH_HOST_CHANNEL_CLASSIFICATION = CONTROLLER_AND_BASEBAND | 0x003F,
- READ_LE_HOST_SUPPORT = CONTROLLER_AND_BASEBAND | 0x6C,
- WRITE_LE_HOST_SUPPORT = CONTROLLER_AND_BASEBAND | 0x6D,
- READ_INQUIRY_SCAN_TYPE = CONTROLLER_AND_BASEBAND | 0x0042,
- WRITE_INQUIRY_SCAN_TYPE = CONTROLLER_AND_BASEBAND | 0x0043,
- READ_INQUIRY_MODE = CONTROLLER_AND_BASEBAND | 0x0044,
- WRITE_INQUIRY_MODE = CONTROLLER_AND_BASEBAND | 0x0045,
- READ_PAGE_SCAN_TYPE = CONTROLLER_AND_BASEBAND | 0x0046,
- WRITE_PAGE_SCAN_TYPE = CONTROLLER_AND_BASEBAND | 0x0047,
- READ_AFH_CHANNEL_ASSESSMENT_MODE = CONTROLLER_AND_BASEBAND | 0x0048,
- WRITE_AFH_CHANNEL_ASSESSMENT_MODE = CONTROLLER_AND_BASEBAND | 0x0049,
- READ_EXTENDED_INQUIRY_RESPONSE = CONTROLLER_AND_BASEBAND | 0x0051,
- WRITE_EXTENDED_INQUIRY_RESPONSE = CONTROLLER_AND_BASEBAND | 0x0052,
- REFRESH_ENCRYPTION_KEY = CONTROLLER_AND_BASEBAND | 0x0053,
- READ_SIMPLE_PAIRING_MODE = CONTROLLER_AND_BASEBAND | 0x0055,
- WRITE_SIMPLE_PAIRING_MODE = CONTROLLER_AND_BASEBAND | 0x0056,
- READ_LOCAL_OOB_DATA = CONTROLLER_AND_BASEBAND | 0x0057,
- READ_INQUIRY_RESPONSE_TRANSMIT_POWER_LEVEL = CONTROLLER_AND_BASEBAND | 0x0058,
- WRITE_INQUIRY_TRANSMIT_POWER_LEVEL = CONTROLLER_AND_BASEBAND | 0x0059,
- SEND_KEYPRESS_NOTIFICATION = CONTROLLER_AND_BASEBAND | 0x0060,
-
- READ_SECURE_CONNECTIONS_HOST_SUPPORT = CONTROLLER_AND_BASEBAND | 0x0079,
- WRITE_SECURE_CONNECTIONS_HOST_SUPPORT = CONTROLLER_AND_BASEBAND | 0x007A,
-
- /* INFORMATIONAL_PARAMETERS */
- READ_LOCAL_VERSION_INFORMATION = INFORMATIONAL_PARAMETERS | 0x0001,
- READ_LOCAL_SUPPORTED_COMMANDS = INFORMATIONAL_PARAMETERS | 0x0002,
- READ_LOCAL_SUPPORTED_FEATURES = INFORMATIONAL_PARAMETERS | 0x0003,
- READ_LOCAL_EXTENDED_FEATURES = INFORMATIONAL_PARAMETERS | 0x0004,
- READ_BUFFER_SIZE = INFORMATIONAL_PARAMETERS | 0x0005,
- READ_BD_ADDR = INFORMATIONAL_PARAMETERS | 0x0009,
- READ_DATA_BLOCK_SIZE = INFORMATIONAL_PARAMETERS | 0x000A,
- READ_LOCAL_SUPPORTED_CODECS = INFORMATIONAL_PARAMETERS | 0x000B,
-
- /* STATUS_PARAMETERS */
- READ_FAILED_CONTACT_COUNTER = STATUS_PARAMETERS | 0x0001,
- RESET_FAILED_CONTACT_COUNTER = STATUS_PARAMETERS | 0x0002,
- READ_LINK_QUALITY = STATUS_PARAMETERS | 0x0003,
- READ_RSSI = STATUS_PARAMETERS | 0x0005,
- READ_AFH_CHANNEL_MAP = STATUS_PARAMETERS | 0x0006,
- READ_CLOCK = STATUS_PARAMETERS | 0x0007,
- READ_ENCRYPTION_KEY_SIZE = STATUS_PARAMETERS | 0x0008,
-
- /* TESTING */
- READ_LOOPBACK_MODE = TESTING | 0x0001,
- WRITE_LOOPBACK_MODE = TESTING | 0x0002,
- ENABLE_DEVICE_UNDER_TEST_MODE = TESTING | 0x0003,
- WRITE_SIMPLE_PAIRING_DEBUG_MODE = TESTING | 0x0004,
- WRITE_SECURE_CONNECTIONS_TEST_MODE = TESTING | 0x000A,
-
- /* LE_CONTROLLER */
- LE_SET_EVENT_MASK = LE_CONTROLLER | 0x0001,
- LE_READ_BUFFER_SIZE = LE_CONTROLLER | 0x0002,
- LE_READ_LOCAL_SUPPORTED_FEATURES = LE_CONTROLLER | 0x0003,
- LE_WRITE_LOCAL_SUPPORTED_FEATURES = LE_CONTROLLER | 0x0004,
- LE_SET_RANDOM_ADDRESS = LE_CONTROLLER | 0x0005,
- LE_SET_ADVERTISING_PARAMETERS = LE_CONTROLLER | 0x0006,
- LE_READ_ADVERTISING_CHANNEL_TX_POWER = LE_CONTROLLER | 0x0007,
- LE_SET_ADVERTISING_DATA = LE_CONTROLLER | 0x0008,
- LE_SET_SCAN_RSPONSE_DATA = LE_CONTROLLER | 0x0009,
- LE_SET_ADVERTISING_ENABLE = LE_CONTROLLER | 0x000A,
- LE_SET_SCAN_PARAMETERS = LE_CONTROLLER | 0x000B,
- LE_SET_SCAN_ENABLE = LE_CONTROLLER | 0x000C,
- LE_CREATE_CONNECTION = LE_CONTROLLER | 0x000D,
- LE_CREATE_CONNECTION_CANCEL = LE_CONTROLLER | 0x000E,
- LE_READ_WHITE_LIST_SIZE = LE_CONTROLLER | 0x000F,
- LE_CLEAR_WHITE_LIST = LE_CONTROLLER | 0x0010,
- LE_ADD_DEVICE_TO_WHITE_LIST = LE_CONTROLLER | 0x0011,
- LE_REMOVE_DEVICE_FROM_WHITE_LIST = LE_CONTROLLER | 0x0012,
- LE_CONNECTION_UPDATE = LE_CONTROLLER | 0x0013,
- LE_SET_HOST_CHANNEL_CLASSIFICATION = LE_CONTROLLER | 0x0014,
- LE_READ_CHANNEL_MAP = LE_CONTROLLER | 0x0015,
- LE_READ_REMOTE_FEATURES = LE_CONTROLLER | 0x0016,
- LE_ENCRYPT = LE_CONTROLLER | 0x0017,
- LE_RAND = LE_CONTROLLER | 0x0018,
- LE_START_ENCRYPTION = LE_CONTROLLER | 0x0019,
- LE_LONG_TERM_KEY_REQUEST_REPLY = LE_CONTROLLER | 0x001A,
- LE_LONG_TERM_KEY_REQUEST_NEGATIVE_REPLY = LE_CONTROLLER | 0x001B,
- LE_READ_SUPPORTED_STATES = LE_CONTROLLER | 0x001C,
- LE_RECEIVER_TEST = LE_CONTROLLER | 0x001D,
- LE_TRANSMITTER_TEST = LE_CONTROLLER | 0x001E,
- LE_TEST_END = LE_CONTROLLER | 0x001F,
- LE_REMOTE_CONNECTION_PARAMETER_REQUEST_REPLY = LE_CONTROLLER | 0x0020,
- LE_REMOTE_CONNECTION_PARAMETER_REQUEST_NEGATIVE_REPLY = LE_CONTROLLER | 0x0021,
-
- LE_SET_DATA_LENGTH = LE_CONTROLLER | 0x0022,
- LE_READ_SUGGESTED_DEFAULT_DATA_LENGTH = LE_CONTROLLER | 0x0023,
- LE_WRITE_SUGGESTED_DEFAULT_DATA_LENGTH = LE_CONTROLLER | 0x0024,
- LE_READ_LOCAL_P_256_PUBLIC_KEY_COMMAND = LE_CONTROLLER | 0x0025,
- LE_GENERATE_DHKEY_COMMAND = LE_CONTROLLER | 0x0026,
- LE_ADD_DEVICE_TO_RESOLVING_LIST = LE_CONTROLLER | 0x0027,
- LE_REMOVE_DEVICE_FROM_RESOLVING_LIST = LE_CONTROLLER | 0x0028,
- LE_CLEAR_RESOLVING_LIST = LE_CONTROLLER | 0x0029,
- LE_READ_RESOLVING_LIST_SIZE = LE_CONTROLLER | 0x002A,
- LE_READ_PEER_RESOLVABLE_ADDRESS = LE_CONTROLLER | 0x002B,
- LE_READ_LOCAL_RESOLVABLE_ADDRESS = LE_CONTROLLER | 0x002C,
- LE_SET_ADDRESS_RESOLUTION_ENABLE = LE_CONTROLLER | 0x002D,
- LE_SET_RESOLVABLE_PRIVATE_ADDRESS_TIMEOUT = LE_CONTROLLER | 0x002E,
- LE_READ_MAXIMUM_DATA_LENGTH = LE_CONTROLLER | 0x002F,
- LE_READ_PHY = LE_CONTROLLER | 0x0030,
- LE_SET_DEFAULT_PHY = LE_CONTROLLER | 0x0031,
- LE_SET_PHY = LE_CONTROLLER | 0x0032,
- LE_ENHANCED_RECEIVER_TEST = LE_CONTROLLER | 0x0033,
- LE_ENHANCED_TRANSMITTER_TEST = LE_CONTROLLER | 0x0034,
- LE_SET_EXTENDED_ADVERTISING_RANDOM_ADDRESS = LE_CONTROLLER | 0x35,
- LE_SET_EXTENDED_ADVERTISING_PARAMETERS = LE_CONTROLLER | 0x36,
- LE_SET_EXTENDED_ADVERTISING_DATA = LE_CONTROLLER | 0x37,
- LE_SET_EXTENDED_ADVERTISING_SCAN_RESPONSE = LE_CONTROLLER | 0x38,
- LE_SET_EXTENDED_ADVERTISING_ENABLE = LE_CONTROLLER | 0x39,
- LE_READ_MAXIMUM_ADVERTISING_DATA_LENGTH = LE_CONTROLLER | 0x003A,
- LE_READ_NUMBER_OF_SUPPORTED_ADVERTISING_SETS = LE_CONTROLLER | 0x003B,
- LE_REMOVE_ADVERTISING_SET = LE_CONTROLLER | 0x003C,
- LE_CLEAR_ADVERTISING_SETS = LE_CONTROLLER | 0x003D,
- LE_SET_PERIODIC_ADVERTISING_PARAM = LE_CONTROLLER | 0x003E,
- LE_SET_PERIODIC_ADVERTISING_DATA = LE_CONTROLLER | 0x003F,
- LE_SET_PERIODIC_ADVERTISING_ENABLE = LE_CONTROLLER | 0x0040,
- LE_SET_EXTENDED_SCAN_PARAMETERS = LE_CONTROLLER | 0x0041,
- LE_SET_EXTENDED_SCAN_ENABLE = LE_CONTROLLER | 0x0042,
- LE_EXTENDED_CREATE_CONNECTION = LE_CONTROLLER | 0x0043,
- LE_PERIODIC_ADVERTISING_CREATE_SYNC = LE_CONTROLLER | 0x0044,
- LE_PERIODIC_ADVERTISING_CREATE_SYNC_CANCEL = LE_CONTROLLER | 0x0045,
- LE_PERIODIC_ADVERTISING_TERMINATE_SYNC = LE_CONTROLLER | 0x0046,
- LE_ADD_DEVICE_TO_PERIODIC_ADVERTISING_LIST = LE_CONTROLLER | 0x0047,
- LE_REMOVE_DEVICE_FROM_PERIODIC_ADVERTISING_LIST = LE_CONTROLLER | 0x0048,
- LE_CLEAR_PERIODIC_ADVERTISING_LIST = LE_CONTROLLER | 0x0049,
- LE_READ_PERIODIC_ADVERTISING_LIST_SIZE = LE_CONTROLLER | 0x004A,
- LE_READ_TRANSMIT_POWER = LE_CONTROLLER | 0x004B,
- LE_READ_RF_PATH_COMPENSATION_POWER = LE_CONTROLLER | 0x004C,
- LE_WRITE_RF_PATH_COMPENSATION_POWER = LE_CONTROLLER | 0x004D,
- LE_SET_PRIVACY_MODE = LE_CONTROLLER | 0x004E,
-
- /* VENDOR_SPECIFIC */
- LE_GET_VENDOR_CAPABILITIES = VENDOR_SPECIFIC | 0x0153,
- LE_MULTI_ADVT = VENDOR_SPECIFIC | 0x0154,
- LE_BATCH_SCAN = VENDOR_SPECIFIC | 0x0156,
- LE_ADV_FILTER = VENDOR_SPECIFIC | 0x0157,
- LE_TRACK_ADV = VENDOR_SPECIFIC | 0x0158,
- LE_ENERGY_INFO = VENDOR_SPECIFIC | 0x0159,
- LE_EXTENDED_SCAN_PARAMS = VENDOR_SPECIFIC | 0x015A,
- CONTROLLER_DEBUG_INFO = VENDOR_SPECIFIC | 0x015B,
- CONTROLLER_A2DP_OPCODE = VENDOR_SPECIFIC | 0x015D,
-};
-
-} // namespace hci
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/hci/status.h b/vendor_libs/test_vendor_lib/include/hci/status.h
deleted file mode 100644
index 4452cfa..0000000
--- a/vendor_libs/test_vendor_lib/include/hci/status.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-#include <cstdint>
-
-namespace test_vendor_lib {
-namespace hci {
-
-enum class Status : uint8_t {
- SUCCESS = 0,
- UNKNOWN_COMMAND = 1,
- UNKNOWN_CONNECTION = 2,
- HARDWARE_FAILURE = 3,
- PAGE_TIMEOUT = 4,
- AUTHENTICATION_FAILURE = 5,
- PIN_OR_KEY_MISSING = 6,
- MEMORY_CAPACITY_EXCEEDED = 7,
- CONNECTION_TIMEOUT = 8,
- COMMAND_DISALLOWED = 0x0c,
- CONNECTION_REJECTED_LIMITED_RESOURCES = 0x0d,
- CONNECTION_REJECTED_SECURITY = 0x0e,
- CONNECTION_REJECTED_UNACCEPTABLE_BD_ADDR = 0x0f,
- INVALID_HCI_COMMAND_PARAMETERS = 0x12,
- REMOTE_USER_TERMINATED_CONNECTION = 0x13,
- CONNECTION_TERMINATED_BY_LOCAL_HOST = 0x16,
- UNSPECIFIED_ERROR = 0x1f,
- ENCRYPTION_MODE_NOT_ACCEPTABLE = 0x25,
- HOST_BUSY_PAIRING = 0x38,
- CONTROLLER_BUSY = 0x3a,
-};
-}
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/include/link.h b/vendor_libs/test_vendor_lib/include/link.h
deleted file mode 100644
index 1c60e3d..0000000
--- a/vendor_libs/test_vendor_lib/include/link.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-namespace test_vendor_lib {
-class Link {
- public:
- static constexpr size_t kSizeBytes = sizeof(uint32_t);
- static constexpr size_t kTypeBytes = sizeof(uint8_t);
-
- enum class PacketType : uint8_t {
- UNKNOWN,
- ACL,
- COMMAND,
- DISCONNECT,
- ENCRYPT_CONNECTION,
- ENCRYPT_CONNECTION_RESPONSE,
- EVENT,
- INQUIRY,
- INQUIRY_RESPONSE,
- IO_CAPABILITY_REQUEST,
- IO_CAPABILITY_RESPONSE,
- IO_CAPABILITY_NEGATIVE_RESPONSE,
- LE_ADVERTISEMENT,
- LE_SCAN,
- LE_SCAN_RESPONSE,
- PAGE,
- PAGE_RESPONSE,
- RESPONSE,
- SCO,
- };
-};
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/acl_connection.cc b/vendor_libs/test_vendor_lib/model/controller/acl_connection.cc
index 460f550..7e14db6 100644
--- a/vendor_libs/test_vendor_lib/model/controller/acl_connection.cc
+++ b/vendor_libs/test_vendor_lib/model/controller/acl_connection.cc
@@ -14,14 +14,8 @@
* limitations under the License.
*/
-#define LOG_TAG "acl_connection"
-
#include "acl_connection.h"
-#include "base/logging.h"
-
-#include "osi/include/log.h"
-
using std::shared_ptr;
namespace test_vendor_lib {} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/acl_connection.h b/vendor_libs/test_vendor_lib/model/controller/acl_connection.h
index 796d04e..cc33c13 100644
--- a/vendor_libs/test_vendor_lib/model/controller/acl_connection.h
+++ b/vendor_libs/test_vendor_lib/model/controller/acl_connection.h
@@ -18,24 +18,19 @@
#include <cstdint>
-#include "types/address.h"
+#include "hci/address.h"
namespace test_vendor_lib {
+using ::bluetooth::hci::Address;
+
// Model the connection of a device to the controller.
class AclConnection {
public:
- AclConnection(const Address& addr) : address_(addr), connected_(false), encrypted_(false) {}
+ AclConnection(Address addr) : address_(addr), address_type_(0), own_address_type_(0) {}
virtual ~AclConnection() = default;
- void SetConnected(bool connected) {
- connected_ = connected;
- };
- bool IsConnected() const {
- return connected_;
- };
-
void Encrypt() {
encrypted_ = true;
};
@@ -43,19 +38,33 @@
return encrypted_;
};
- const Address& GetAddress() const {
+ Address GetAddress() const {
return address_;
}
- void SetAddress(const Address& address) {
+ void SetAddress(Address address) {
address_ = address;
}
+ uint8_t GetAddressType() const {
+ return address_type_;
+ }
+ void SetAddressType(uint8_t address_type) {
+ address_type_ = address_type;
+ }
+ uint8_t GetOwnAddressType() const {
+ return own_address_type_;
+ }
+ void SetOwnAddressType(uint8_t address_type) {
+ own_address_type_ = address_type;
+ }
+
private:
Address address_;
+ uint8_t address_type_;
+ uint8_t own_address_type_;
// State variables
- bool connected_;
- bool encrypted_;
+ bool encrypted_{false};
};
} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.cc b/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.cc
index 2d5ff97..014015a 100644
--- a/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.cc
+++ b/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.cc
@@ -14,19 +14,18 @@
* limitations under the License.
*/
-#define LOG_TAG "acl_connection_handler"
-
#include "acl_connection_handler.h"
-#include "base/logging.h"
+#include "os/log.h"
-#include "osi/include/log.h"
-#include "types/address.h"
+#include "hci/address.h"
using std::shared_ptr;
namespace test_vendor_lib {
+using ::bluetooth::hci::Address;
+
bool AclConnectionHandler::HasHandle(uint16_t handle) const {
if (acl_connections_.count(handle) == 0) {
return false;
@@ -35,40 +34,89 @@
}
uint16_t AclConnectionHandler::GetUnusedHandle() {
- static uint16_t sNextHandle = acl::kReservedHandle - 2;
- while (acl_connections_.count(sNextHandle) == 1) {
- sNextHandle = (sNextHandle + 1) % acl::kReservedHandle;
+ while (acl_connections_.count(last_handle_) == 1) {
+ last_handle_ = (last_handle_ + 1) % acl::kReservedHandle;
}
- uint16_t unused_handle = sNextHandle;
- sNextHandle = (sNextHandle + 1) % acl::kReservedHandle;
+ uint16_t unused_handle = last_handle_;
+ last_handle_ = (last_handle_ + 1) % acl::kReservedHandle;
return unused_handle;
}
-bool AclConnectionHandler::CreatePendingConnection(const Address& addr) {
- if ((pending_connections_.size() + 1 > max_pending_connections_) || HasPendingConnection(addr)) {
+bool AclConnectionHandler::CreatePendingConnection(
+ Address addr, bool authenticate_on_connect) {
+ if (classic_connection_pending_) {
return false;
}
- pending_connections_.insert(addr);
+ classic_connection_pending_ = true;
+ pending_connection_address_ = addr;
+ authenticate_pending_classic_connection_ = authenticate_on_connect;
return true;
}
-bool AclConnectionHandler::HasPendingConnection(const Address& addr) {
- return pending_connections_.count(addr) == 1;
+bool AclConnectionHandler::HasPendingConnection(Address addr) const {
+ return classic_connection_pending_ && pending_connection_address_ == addr;
}
-bool AclConnectionHandler::CancelPendingConnection(const Address& addr) {
- if (!HasPendingConnection(addr)) {
+bool AclConnectionHandler::AuthenticatePendingConnection() const {
+ return authenticate_pending_classic_connection_;
+}
+
+bool AclConnectionHandler::CancelPendingConnection(Address addr) {
+ if (!classic_connection_pending_ || pending_connection_address_ != addr) {
return false;
}
- pending_connections_.erase(addr);
+ classic_connection_pending_ = false;
+ pending_connection_address_ = Address::kEmpty;
return true;
}
-uint16_t AclConnectionHandler::CreateConnection(const Address& addr) {
+bool AclConnectionHandler::CreatePendingLeConnection(Address addr, uint8_t address_type) {
+ if (IsDeviceConnected(addr, address_type)) {
+ LOG_INFO("%s: %s (type %hhx) is already connected", __func__, addr.ToString().c_str(), address_type);
+ return false;
+ }
+ if (le_connection_pending_) {
+ LOG_INFO("%s: connection already pending", __func__);
+ return false;
+ }
+ le_connection_pending_ = true;
+ pending_le_connection_address_ = addr;
+ pending_le_connection_address_type_ = address_type;
+ return true;
+}
+
+bool AclConnectionHandler::HasPendingLeConnection(Address addr,
+ uint8_t address_type) const {
+ return le_connection_pending_ && pending_le_connection_address_ == addr &&
+ pending_le_connection_address_type_ == address_type;
+}
+
+bool AclConnectionHandler::CancelPendingLeConnection(Address addr, uint8_t address_type) {
+ if (!le_connection_pending_ || pending_le_connection_address_ != addr ||
+ pending_le_connection_address_type_ != address_type) {
+ return false;
+ }
+ le_connection_pending_ = false;
+ pending_le_connection_address_ = Address::kEmpty;
+ pending_le_connection_address_type_ = 0xba;
+ return true;
+}
+
+uint16_t AclConnectionHandler::CreateConnection(Address addr) {
if (CancelPendingConnection(addr)) {
uint16_t handle = GetUnusedHandle();
acl_connections_.emplace(handle, addr);
- SetConnected(handle, true);
+ return handle;
+ }
+ return acl::kReservedHandle;
+}
+
+uint16_t AclConnectionHandler::CreateLeConnection(Address addr, uint8_t address_type, uint8_t own_address_type) {
+ if (CancelPendingLeConnection(addr, address_type)) {
+ uint16_t handle = GetUnusedHandle();
+ acl_connections_.emplace(handle, addr);
+ set_own_address_type(handle, own_address_type);
+ SetAddress(handle, addr, address_type);
return handle;
}
return acl::kReservedHandle;
@@ -78,7 +126,7 @@
return acl_connections_.erase(handle) > 0;
}
-uint16_t AclConnectionHandler::GetHandle(const Address& addr) const {
+uint16_t AclConnectionHandler::GetHandle(Address addr) const {
for (auto pair : acl_connections_) {
if (std::get<AclConnection>(pair).GetAddress() == addr) {
return std::get<0>(pair);
@@ -87,23 +135,41 @@
return acl::kReservedHandle;
}
-const Address& AclConnectionHandler::GetAddress(uint16_t handle) const {
- CHECK(HasHandle(handle)) << "Handle unknown " << handle;
+Address AclConnectionHandler::GetAddress(uint16_t handle) const {
+ ASSERT_LOG(HasHandle(handle), "Handle unknown %hd", handle);
return acl_connections_.at(handle).GetAddress();
}
-void AclConnectionHandler::SetConnected(uint16_t handle, bool connected) {
- if (!HasHandle(handle)) {
- return;
- }
- acl_connections_.at(handle).SetConnected(connected);
+uint8_t AclConnectionHandler::GetAddressType(uint16_t handle) const {
+ ASSERT_LOG(HasHandle(handle), "Handle unknown %hd", handle);
+ return acl_connections_.at(handle).GetAddressType();
+}
+
+void AclConnectionHandler::set_own_address_type(uint16_t handle, uint8_t address_type) {
+ ASSERT_LOG(HasHandle(handle), "Handle unknown %hd", handle);
+ acl_connections_.at(handle).SetOwnAddressType(address_type);
+}
+
+uint8_t AclConnectionHandler::GetOwnAddressType(uint16_t handle) const {
+ ASSERT_LOG(HasHandle(handle), "Handle unknown %hd", handle);
+ return acl_connections_.at(handle).GetOwnAddressType();
}
bool AclConnectionHandler::IsConnected(uint16_t handle) const {
if (!HasHandle(handle)) {
return false;
}
- return acl_connections_.at(handle).IsConnected();
+ return true;
+}
+
+bool AclConnectionHandler::IsDeviceConnected(Address addr, uint8_t address_type) const {
+ for (auto pair : acl_connections_) {
+ auto connection = std::get<AclConnection>(pair);
+ if (connection.GetAddress() == addr && connection.GetAddressType() == address_type) {
+ return true;
+ }
+ }
+ return false;
}
void AclConnectionHandler::Encrypt(uint16_t handle) {
@@ -120,11 +186,13 @@
return acl_connections_.at(handle).IsEncrypted();
}
-void AclConnectionHandler::SetAddress(uint16_t handle, const Address& address) {
+void AclConnectionHandler::SetAddress(uint16_t handle, Address address, uint8_t address_type) {
if (!HasHandle(handle)) {
return;
}
- acl_connections_.at(handle).SetAddress(address);
+ auto connection = acl_connections_.at(handle);
+ connection.SetAddress(address);
+ connection.SetAddressType(address_type);
}
} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.h b/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.h
index fda1d3d..c08f529 100644
--- a/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.h
+++ b/vendor_libs/test_vendor_lib/model/controller/acl_connection_handler.h
@@ -21,41 +21,60 @@
#include <unordered_map>
#include "acl_connection.h"
+#include "hci/address.h"
#include "include/acl.h"
-#include "types/address.h"
namespace test_vendor_lib {
+using ::bluetooth::hci::Address;
+
class AclConnectionHandler {
public:
- AclConnectionHandler(size_t max_pending_connections = 1) : max_pending_connections_(max_pending_connections) {}
+ AclConnectionHandler() = default;
virtual ~AclConnectionHandler() = default;
- bool CreatePendingConnection(const Address& addr);
- bool HasPendingConnection(const Address& addr);
- bool CancelPendingConnection(const Address& addr);
+ bool CreatePendingConnection(Address addr, bool authenticate_on_connect);
+ bool HasPendingConnection(Address addr) const;
+ bool CancelPendingConnection(Address addr);
+ bool AuthenticatePendingConnection() const;
- uint16_t CreateConnection(const Address& addr);
+ bool CreatePendingLeConnection(Address addr, uint8_t addr_type);
+ bool HasPendingLeConnection(Address addr, uint8_t addr_type) const;
+ bool CancelPendingLeConnection(Address addr, uint8_t addr_type);
+
+ uint16_t CreateConnection(Address addr);
+ uint16_t CreateLeConnection(Address addr, uint8_t address_type, uint8_t own_address_type);
bool Disconnect(uint16_t handle);
bool HasHandle(uint16_t handle) const;
- uint16_t GetHandle(const Address& addr) const;
- const Address& GetAddress(uint16_t handle) const;
+ uint16_t GetHandle(Address addr) const;
+ Address GetAddress(uint16_t handle) const;
+ uint8_t GetAddressType(uint16_t handle) const;
+ uint8_t GetOwnAddressType(uint16_t handle) const;
void SetConnected(uint16_t handle, bool connected);
bool IsConnected(uint16_t handle) const;
+ bool IsDeviceConnected(Address addr, uint8_t address_type = 0) const;
+
void Encrypt(uint16_t handle);
bool IsEncrypted(uint16_t handle) const;
- void SetAddress(uint16_t handle, const Address& address);
+ void SetAddress(uint16_t handle, Address address, uint8_t address_type = 0); // default to public
private:
std::unordered_map<uint16_t, AclConnection> acl_connections_;
- size_t max_pending_connections_;
- std::set<Address> pending_connections_;
+ bool classic_connection_pending_{false};
+ Address pending_connection_address_{Address::kEmpty};
+ bool authenticate_pending_classic_connection_{false};
+ bool le_connection_pending_{false};
+ Address pending_le_connection_address_{Address::kEmpty};
+ uint8_t pending_le_connection_address_type_{false};
+
uint16_t GetUnusedHandle();
+ uint16_t last_handle_{acl::kReservedHandle - 2};
+ void set_own_address_type(uint16_t handle, uint8_t own_address_type);
};
} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc
index 273dd09..bb3ba63 100644
--- a/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc
+++ b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.cc
@@ -14,33 +14,23 @@
* limitations under the License.
*/
-#define LOG_TAG "dual_mode_controller"
-
#include "dual_mode_controller.h"
#include <memory>
#include <base/files/file_util.h>
#include <base/json/json_reader.h>
-#include <base/logging.h>
#include <base/values.h>
-#include "osi/include/log.h"
-#include "osi/include/osi.h"
+#include "os/log.h"
+#include "packet/raw_builder.h"
-#include "hci.h"
-#include "packets/hci/acl_packet_view.h"
-#include "packets/hci/command_packet_view.h"
-#include "packets/hci/event_packet_builder.h"
-#include "packets/hci/sco_packet_view.h"
-
+using bluetooth::hci::OpCode;
using std::vector;
-using test_vendor_lib::hci::EventCode;
-using test_vendor_lib::hci::OpCode;
namespace {
-size_t LastNonZero(test_vendor_lib::packets::PacketView<true> view) {
+size_t LastNonZero(bluetooth::packet::PacketView<true> view) {
for (size_t i = view.size() - 1; i > 0; i--) {
if (view[i] != 0) {
return i;
@@ -54,20 +44,26 @@
namespace test_vendor_lib {
constexpr char DualModeController::kControllerPropertiesFile[];
constexpr uint16_t DualModeController::kSecurityManagerNumKeys;
+constexpr uint16_t kNumCommandPackets = 0x01;
// Device methods.
void DualModeController::Initialize(const std::vector<std::string>& args) {
if (args.size() < 2) return;
Address addr;
- if (Address::FromString(args[1], addr)) properties_.SetAddress(addr);
+ if (Address::FromString(args[1], addr)) {
+ properties_.SetAddress(addr);
+ } else {
+ LOG_ALWAYS_FATAL("Invalid address: %s", args[1].c_str());
+ }
};
std::string DualModeController::GetTypeString() const {
return "Simulated Bluetooth Controller";
}
-void DualModeController::IncomingPacket(packets::LinkLayerPacketView incoming) {
+void DualModeController::IncomingPacket(
+ model::packets::LinkLayerPacketView incoming) {
link_layer_controller_.IncomingPacket(incoming);
}
@@ -75,80 +71,49 @@
link_layer_controller_.TimerTick();
}
-void DualModeController::SendLinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> to_send,
- Phy::Type phy_type) {
- for (auto phy_pair : phy_layers_) {
- auto phy_list = std::get<1>(phy_pair);
- if (phy_type != std::get<0>(phy_pair)) {
- continue;
- }
- for (auto phy : phy_list) {
- phy->Send(to_send);
- }
- }
-}
-
-/*
-void DualModeController::AddConnectionAction(const TaskCallback& task,
- uint16_t handle) {
- for (size_t i = 0; i < connections_.size(); i++)
- if (connections_[i]->GetHandle() == handle)
-connections_[i]->AddAction(task);
-}
-*/
-
-void DualModeController::SendCommandCompleteSuccess(OpCode command_opcode) const {
- send_event_(packets::EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(command_opcode, hci::Status::SUCCESS)
- ->ToVector());
-}
-
void DualModeController::SendCommandCompleteUnknownOpCodeEvent(uint16_t command_opcode) const {
- send_event_(packets::EventPacketBuilder::CreateCommandCompleteUnknownOpCodeEvent(command_opcode)->ToVector());
-}
+ std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr =
+ std::make_unique<bluetooth::packet::RawBuilder>();
+ raw_builder_ptr->AddOctets1(kNumCommandPackets);
+ raw_builder_ptr->AddOctets2(command_opcode);
+ raw_builder_ptr->AddOctets1(
+ static_cast<uint8_t>(bluetooth::hci::ErrorCode::UNKNOWN_HCI_COMMAND));
-void DualModeController::SendCommandCompleteOnlyStatus(OpCode command_opcode, hci::Status status) const {
- send_event_(packets::EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(command_opcode, status)->ToVector());
-}
-
-void DualModeController::SendCommandCompleteStatusAndAddress(OpCode command_opcode, hci::Status status,
- const Address& address) const {
- send_event_(packets::EventPacketBuilder::CreateCommandCompleteStatusAndAddressEvent(command_opcode, status, address)
- ->ToVector());
-}
-
-void DualModeController::SendCommandStatus(hci::Status status, OpCode command_opcode) const {
- send_event_(packets::EventPacketBuilder::CreateCommandStatusEvent(status, command_opcode)->ToVector());
-}
-
-void DualModeController::SendCommandStatusSuccess(OpCode command_opcode) const {
- SendCommandStatus(hci::Status::SUCCESS, command_opcode);
+ auto packet = bluetooth::hci::EventPacketBuilder::Create(
+ bluetooth::hci::EventCode::COMMAND_COMPLETE, std::move(raw_builder_ptr));
+ send_event_(std::move(packet));
}
DualModeController::DualModeController(const std::string& properties_filename, uint16_t num_keys)
: Device(properties_filename), security_manager_(num_keys) {
- loopback_mode_ = hci::LoopbackMode::NO;
+ loopback_mode_ = bluetooth::hci::LoopbackMode::NO_LOOPBACK;
Address public_address;
- CHECK(Address::FromString("3C:5A:B4:04:05:06", public_address));
+ ASSERT(Address::FromString("3C:5A:B4:04:05:06", public_address));
properties_.SetAddress(public_address);
link_layer_controller_.RegisterRemoteChannel(
- [this](std::shared_ptr<packets::LinkLayerPacketBuilder> packet, Phy::Type phy_type) {
+ [this](std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet,
+ Phy::Type phy_type) {
DualModeController::SendLinkLayerPacket(packet, phy_type);
});
-#define SET_HANDLER(opcode, method) \
- active_hci_commands_[static_cast<uint16_t>(opcode)] = [this](packets::PacketView<true> param) { method(param); };
+#define SET_HANDLER(opcode, method) \
+ active_hci_commands_[static_cast<uint16_t>(opcode)] = \
+ [this](bluetooth::packet::PacketView<true> param) { method(param); };
SET_HANDLER(OpCode::RESET, HciReset);
SET_HANDLER(OpCode::READ_BUFFER_SIZE, HciReadBufferSize);
SET_HANDLER(OpCode::HOST_BUFFER_SIZE, HciHostBufferSize);
SET_HANDLER(OpCode::SNIFF_SUBRATING, HciSniffSubrating);
+ SET_HANDLER(OpCode::READ_ENCRYPTION_KEY_SIZE, HciReadEncryptionKeySize);
SET_HANDLER(OpCode::READ_LOCAL_VERSION_INFORMATION, HciReadLocalVersionInformation);
SET_HANDLER(OpCode::READ_BD_ADDR, HciReadBdAddr);
SET_HANDLER(OpCode::READ_LOCAL_SUPPORTED_COMMANDS, HciReadLocalSupportedCommands);
+ SET_HANDLER(OpCode::READ_LOCAL_SUPPORTED_FEATURES, HciReadLocalSupportedFeatures);
SET_HANDLER(OpCode::READ_LOCAL_SUPPORTED_CODECS, HciReadLocalSupportedCodecs);
SET_HANDLER(OpCode::READ_LOCAL_EXTENDED_FEATURES, HciReadLocalExtendedFeatures);
SET_HANDLER(OpCode::READ_REMOTE_EXTENDED_FEATURES, HciReadRemoteExtendedFeatures);
+ SET_HANDLER(OpCode::SWITCH_ROLE, HciSwitchRole);
SET_HANDLER(OpCode::READ_REMOTE_SUPPORTED_FEATURES, HciReadRemoteSupportedFeatures);
SET_HANDLER(OpCode::READ_CLOCK_OFFSET, HciReadClockOffset);
SET_HANDLER(OpCode::IO_CAPABILITY_REQUEST_REPLY, HciIoCapabilityRequestReply);
@@ -157,23 +122,33 @@
SET_HANDLER(OpCode::IO_CAPABILITY_REQUEST_NEGATIVE_REPLY, HciIoCapabilityRequestNegativeReply);
SET_HANDLER(OpCode::WRITE_SIMPLE_PAIRING_MODE, HciWriteSimplePairingMode);
SET_HANDLER(OpCode::WRITE_LE_HOST_SUPPORT, HciWriteLeHostSupport);
+ SET_HANDLER(OpCode::WRITE_SECURE_CONNECTIONS_HOST_SUPPORT,
+ HciWriteSecureConnectionsHostSupport);
SET_HANDLER(OpCode::SET_EVENT_MASK, HciSetEventMask);
SET_HANDLER(OpCode::WRITE_INQUIRY_MODE, HciWriteInquiryMode);
SET_HANDLER(OpCode::WRITE_PAGE_SCAN_TYPE, HciWritePageScanType);
SET_HANDLER(OpCode::WRITE_INQUIRY_SCAN_TYPE, HciWriteInquiryScanType);
SET_HANDLER(OpCode::AUTHENTICATION_REQUESTED, HciAuthenticationRequested);
SET_HANDLER(OpCode::SET_CONNECTION_ENCRYPTION, HciSetConnectionEncryption);
+ SET_HANDLER(OpCode::CHANGE_CONNECTION_LINK_KEY, HciChangeConnectionLinkKey);
+ SET_HANDLER(OpCode::MASTER_LINK_KEY, HciMasterLinkKey);
SET_HANDLER(OpCode::WRITE_AUTHENTICATION_ENABLE, HciWriteAuthenticationEnable);
SET_HANDLER(OpCode::READ_AUTHENTICATION_ENABLE, HciReadAuthenticationEnable);
SET_HANDLER(OpCode::WRITE_CLASS_OF_DEVICE, HciWriteClassOfDevice);
SET_HANDLER(OpCode::WRITE_PAGE_TIMEOUT, HciWritePageTimeout);
SET_HANDLER(OpCode::WRITE_LINK_SUPERVISION_TIMEOUT, HciWriteLinkSupervisionTimeout);
+ SET_HANDLER(OpCode::HOLD_MODE, HciHoldMode);
+ SET_HANDLER(OpCode::SNIFF_MODE, HciSniffMode);
+ SET_HANDLER(OpCode::EXIT_SNIFF_MODE, HciExitSniffMode);
+ SET_HANDLER(OpCode::QOS_SETUP, HciQosSetup);
SET_HANDLER(OpCode::WRITE_DEFAULT_LINK_POLICY_SETTINGS, HciWriteDefaultLinkPolicySettings);
+ SET_HANDLER(OpCode::FLOW_SPECIFICATION, HciFlowSpecification);
SET_HANDLER(OpCode::WRITE_LINK_POLICY_SETTINGS, HciWriteLinkPolicySettings);
SET_HANDLER(OpCode::CHANGE_CONNECTION_PACKET_TYPE, HciChangeConnectionPacketType);
SET_HANDLER(OpCode::WRITE_LOCAL_NAME, HciWriteLocalName);
SET_HANDLER(OpCode::READ_LOCAL_NAME, HciReadLocalName);
SET_HANDLER(OpCode::WRITE_EXTENDED_INQUIRY_RESPONSE, HciWriteExtendedInquiryResponse);
+ SET_HANDLER(OpCode::REFRESH_ENCRYPTION_KEY, HciRefreshEncryptionKey);
SET_HANDLER(OpCode::WRITE_VOICE_SETTING, HciWriteVoiceSetting);
SET_HANDLER(OpCode::WRITE_CURRENT_IAC_LAP, HciWriteCurrentIacLap);
SET_HANDLER(OpCode::WRITE_INQUIRY_SCAN_ACTIVITY, HciWriteInquiryScanActivity);
@@ -191,8 +166,10 @@
SET_HANDLER(OpCode::LE_READ_BUFFER_SIZE, HciLeReadBufferSize);
SET_HANDLER(OpCode::LE_READ_LOCAL_SUPPORTED_FEATURES, HciLeReadLocalSupportedFeatures);
SET_HANDLER(OpCode::LE_SET_RANDOM_ADDRESS, HciLeSetRandomAddress);
- SET_HANDLER(OpCode::LE_SET_ADVERTISING_DATA, HciLeSetAdvertisingData);
SET_HANDLER(OpCode::LE_SET_ADVERTISING_PARAMETERS, HciLeSetAdvertisingParameters);
+ SET_HANDLER(OpCode::LE_SET_ADVERTISING_DATA, HciLeSetAdvertisingData);
+ SET_HANDLER(OpCode::LE_SET_SCAN_RESPONSE_DATA, HciLeSetScanResponseData);
+ SET_HANDLER(OpCode::LE_SET_ADVERTISING_ENABLE, HciLeSetAdvertisingEnable);
SET_HANDLER(OpCode::LE_SET_SCAN_PARAMETERS, HciLeSetScanParameters);
SET_HANDLER(OpCode::LE_SET_SCAN_ENABLE, HciLeSetScanEnable);
SET_HANDLER(OpCode::LE_CREATE_CONNECTION, HciLeCreateConnection);
@@ -214,18 +191,27 @@
SET_HANDLER(OpCode::READ_REMOTE_VERSION_INFORMATION, HciReadRemoteVersionInformation);
SET_HANDLER(OpCode::LE_CONNECTION_UPDATE, HciLeConnectionUpdate);
SET_HANDLER(OpCode::LE_START_ENCRYPTION, HciLeStartEncryption);
+ SET_HANDLER(OpCode::LE_ADD_DEVICE_TO_RESOLVING_LIST,
+ HciLeAddDeviceToResolvingList);
+ SET_HANDLER(OpCode::LE_REMOVE_DEVICE_FROM_RESOLVING_LIST,
+ HciLeRemoveDeviceFromResolvingList);
+ SET_HANDLER(OpCode::LE_CLEAR_RESOLVING_LIST, HciLeClearResolvingList);
+ SET_HANDLER(OpCode::LE_SET_PRIVACY_MODE, HciLeSetPrivacyMode);
// Testing Commands
SET_HANDLER(OpCode::READ_LOOPBACK_MODE, HciReadLoopbackMode);
SET_HANDLER(OpCode::WRITE_LOOPBACK_MODE, HciWriteLoopbackMode);
#undef SET_HANDLER
}
-void DualModeController::HciSniffSubrating(packets::PacketView<true> args) {
- CHECK(args.size() == 8) << __func__ << " size=" << args.size();
+void DualModeController::HciSniffSubrating(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 8, "%s size=%zu", __func__, args.size());
uint16_t handle = args.begin().extract<uint16_t>();
- send_event_(packets::EventPacketBuilder::CreateSniffSubratingEvent(hci::Status::SUCCESS, handle)->ToVector());
+ auto packet = bluetooth::hci::SniffSubratingCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS, handle);
+ send_event_(std::move(packet));
}
void DualModeController::RegisterTaskScheduler(
@@ -244,11 +230,20 @@
}
void DualModeController::HandleAcl(std::shared_ptr<std::vector<uint8_t>> packet) {
- auto acl_packet = packets::AclPacketView::Create(packet);
- if (loopback_mode_ == hci::LoopbackMode::LOCAL) {
+ bluetooth::hci::PacketView<bluetooth::hci::kLittleEndian> raw_packet(packet);
+ auto acl_packet = bluetooth::hci::AclPacketView::Create(raw_packet);
+ ASSERT(acl_packet.IsValid());
+ if (loopback_mode_ == bluetooth::hci::LoopbackMode::ENABLE_LOCAL) {
uint16_t handle = acl_packet.GetHandle();
- send_acl_(packet);
- send_event_(packets::EventPacketBuilder::CreateNumberOfCompletedPacketsEvent(handle, 1)->ToVector());
+
+ std::vector<bluetooth::hci::CompletedPackets> completed_packets;
+ bluetooth::hci::CompletedPackets cp;
+ cp.connection_handle_ = handle;
+ cp.host_num_of_completed_packets_ = kNumCommandPackets;
+ completed_packets.push_back(cp);
+ auto packet = bluetooth::hci::NumberOfCompletedPacketsBuilder::Create(
+ completed_packets);
+ send_event_(std::move(packet));
return;
}
@@ -256,44 +251,83 @@
}
void DualModeController::HandleSco(std::shared_ptr<std::vector<uint8_t>> packet) {
- auto sco_packet = packets::ScoPacketView::Create(packet);
- if (loopback_mode_ == hci::LoopbackMode::LOCAL) {
+ bluetooth::hci::PacketView<bluetooth::hci::kLittleEndian> raw_packet(packet);
+ auto sco_packet = bluetooth::hci::ScoPacketView::Create(raw_packet);
+ if (loopback_mode_ == bluetooth::hci::LoopbackMode::ENABLE_LOCAL) {
uint16_t handle = sco_packet.GetHandle();
send_sco_(packet);
- send_event_(packets::EventPacketBuilder::CreateNumberOfCompletedPacketsEvent(handle, 1)->ToVector());
+ std::vector<bluetooth::hci::CompletedPackets> completed_packets;
+ bluetooth::hci::CompletedPackets cp;
+ cp.connection_handle_ = handle;
+ cp.host_num_of_completed_packets_ = kNumCommandPackets;
+ completed_packets.push_back(cp);
+ auto packet = bluetooth::hci::NumberOfCompletedPacketsBuilder::Create(
+ completed_packets);
+ send_event_(std::move(packet));
return;
}
}
-void DualModeController::HandleCommand(std::shared_ptr<std::vector<uint8_t>> packet) {
- auto command_packet = packets::CommandPacketView::Create(packet);
- uint16_t opcode = command_packet.GetOpcode();
- hci::OpCode op = static_cast<hci::OpCode>(opcode);
+void DualModeController::HandleIso(
+ std::shared_ptr<std::vector<uint8_t>> /* packet */) {
+ // TODO: implement handling similar to HandleSco
+}
- if (loopback_mode_ == hci::LoopbackMode::LOCAL &&
+void DualModeController::HandleCommand(std::shared_ptr<std::vector<uint8_t>> packet) {
+ bluetooth::hci::PacketView<bluetooth::hci::kLittleEndian> raw_packet(packet);
+ auto command_packet = bluetooth::hci::CommandPacketView::Create(raw_packet);
+ ASSERT(command_packet.IsValid());
+ auto op = command_packet.GetOpCode();
+ uint16_t opcode = static_cast<uint16_t>(op);
+
+ if (loopback_mode_ == bluetooth::hci::LoopbackMode::ENABLE_LOCAL &&
// Loopback exceptions.
- op != OpCode::RESET && op != OpCode::SET_CONTROLLER_TO_HOST_FLOW_CONTROL && op != OpCode::HOST_BUFFER_SIZE &&
- op != OpCode::HOST_NUM_COMPLETED_PACKETS && op != OpCode::READ_BUFFER_SIZE && op != OpCode::READ_LOOPBACK_MODE &&
- op != OpCode::WRITE_LOOPBACK_MODE) {
- send_event_(packets::EventPacketBuilder::CreateLoopbackCommandEvent(op, command_packet.GetPayload())->ToVector());
+ op != bluetooth::hci::OpCode::RESET &&
+ op != bluetooth::hci::OpCode::SET_CONTROLLER_TO_HOST_FLOW_CONTROL &&
+ op != bluetooth::hci::OpCode::HOST_BUFFER_SIZE &&
+ op != bluetooth::hci::OpCode::HOST_NUM_COMPLETED_PACKETS &&
+ op != bluetooth::hci::OpCode::READ_BUFFER_SIZE &&
+ op != bluetooth::hci::OpCode::READ_LOOPBACK_MODE &&
+ op != bluetooth::hci::OpCode::WRITE_LOOPBACK_MODE) {
+ std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr =
+ std::make_unique<bluetooth::packet::RawBuilder>();
+ raw_builder_ptr->AddOctets(*packet);
+ auto packet = bluetooth::hci::LoopbackCommandBuilder::Create(
+ std::move(raw_builder_ptr));
+ send_event_(std::move(packet));
} else if (active_hci_commands_.count(opcode) > 0) {
active_hci_commands_[opcode](command_packet.GetPayload());
} else {
SendCommandCompleteUnknownOpCodeEvent(opcode);
- LOG_INFO(LOG_TAG, "Command opcode: 0x%04X, OGF: 0x%04X, OCF: 0x%04X", opcode, opcode & 0xFC00, opcode & 0x03FF);
+ LOG_INFO("Unknown command, opcode: 0x%04X, OGF: 0x%04X, OCF: 0x%04X",
+ opcode, (opcode & 0xFC00) >> 10, opcode & 0x03FF);
}
}
void DualModeController::RegisterEventChannel(
const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& callback) {
- link_layer_controller_.RegisterEventChannel(callback);
- send_event_ = callback;
+ send_event_ =
+ [callback](std::shared_ptr<bluetooth::hci::EventPacketBuilder> event) {
+ auto bytes = std::make_shared<std::vector<uint8_t>>();
+ bluetooth::packet::BitInserter bit_inserter(*bytes);
+ bytes->reserve(event->size());
+ event->Serialize(bit_inserter);
+ callback(std::move(bytes));
+ };
+ link_layer_controller_.RegisterEventChannel(send_event_);
}
void DualModeController::RegisterAclChannel(
const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& callback) {
- link_layer_controller_.RegisterAclChannel(callback);
- send_acl_ = callback;
+ send_acl_ =
+ [callback](std::shared_ptr<bluetooth::hci::AclPacketBuilder> acl_data) {
+ auto bytes = std::make_shared<std::vector<uint8_t>>();
+ bluetooth::packet::BitInserter bit_inserter(*bytes);
+ bytes->reserve(acl_data->size());
+ acl_data->Serialize(bit_inserter);
+ callback(std::move(bytes));
+ };
+ link_layer_controller_.RegisterAclChannel(send_acl_);
}
void DualModeController::RegisterScoChannel(
@@ -302,114 +336,213 @@
send_sco_ = callback;
}
-void DualModeController::HciReset(packets::PacketView<true> args) {
- CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+void DualModeController::RegisterIsoChannel(
+ const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>&
+ callback) {
+ link_layer_controller_.RegisterIsoChannel(callback);
+ send_iso_ = callback;
+}
+
+void DualModeController::HciReset(bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size());
link_layer_controller_.Reset();
+ if (loopback_mode_ == bluetooth::hci::LoopbackMode::ENABLE_LOCAL) {
+ loopback_mode_ = bluetooth::hci::LoopbackMode::NO_LOOPBACK;
+ }
- SendCommandCompleteSuccess(OpCode::RESET);
+ send_event_(bluetooth::hci::ResetCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS));
}
-void DualModeController::HciReadBufferSize(packets::PacketView<true> args) {
- CHECK(args.size() == 0) << __func__ << " size=" << args.size();
- std::shared_ptr<packets::EventPacketBuilder> command_complete =
- packets::EventPacketBuilder::CreateCommandCompleteReadBufferSize(
- hci::Status::SUCCESS, properties_.GetAclDataPacketSize(), properties_.GetSynchronousDataPacketSize(),
- properties_.GetTotalNumAclDataPackets(), properties_.GetTotalNumSynchronousDataPackets());
+void DualModeController::HciReadBufferSize(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size());
- send_event_(command_complete->ToVector());
+ auto packet = bluetooth::hci::ReadBufferSizeCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+ properties_.GetAclDataPacketSize(),
+ properties_.GetSynchronousDataPacketSize(),
+ properties_.GetTotalNumAclDataPackets(),
+ properties_.GetTotalNumSynchronousDataPackets());
+ send_event_(std::move(packet));
}
-void DualModeController::HciHostBufferSize(packets::PacketView<true> args) {
- CHECK(args.size() == 7) << __func__ << " size=" << args.size();
- SendCommandCompleteSuccess(OpCode::HOST_BUFFER_SIZE);
-}
-
-void DualModeController::HciReadLocalVersionInformation(packets::PacketView<true> args) {
- CHECK(args.size() == 0) << __func__ << " size=" << args.size();
- std::shared_ptr<packets::EventPacketBuilder> command_complete =
- packets::EventPacketBuilder::CreateCommandCompleteReadLocalVersionInformation(
- hci::Status::SUCCESS, properties_.GetVersion(), properties_.GetRevision(), properties_.GetLmpPalVersion(),
- properties_.GetManufacturerName(), properties_.GetLmpPalSubversion());
- send_event_(command_complete->ToVector());
-}
-
-void DualModeController::HciReadRemoteVersionInformation(packets::PacketView<true> args) {
- CHECK(args.size() == 2) << __func__ << " size=" << args.size();
+void DualModeController::HciReadEncryptionKeySize(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 2, "%s size=%zu", __func__, args.size());
uint16_t handle = args.begin().extract<uint16_t>();
- hci::Status status =
- link_layer_controller_.SendCommandToRemoteByHandle(OpCode::READ_REMOTE_VERSION_INFORMATION, args, handle);
-
- SendCommandStatus(status, OpCode::READ_REMOTE_VERSION_INFORMATION);
+ auto packet = bluetooth::hci::ReadEncryptionKeySizeCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS, handle,
+ properties_.GetEncryptionKeySize());
+ send_event_(std::move(packet));
}
-void DualModeController::HciReadBdAddr(packets::PacketView<true> args) {
- CHECK(args.size() == 0) << __func__ << " size=" << args.size();
- std::shared_ptr<packets::EventPacketBuilder> command_complete =
- packets::EventPacketBuilder::CreateCommandCompleteReadBdAddr(hci::Status::SUCCESS, properties_.GetAddress());
- send_event_(command_complete->ToVector());
+void DualModeController::HciHostBufferSize(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 7, "%s size=%zu", __func__, args.size());
+ auto packet = bluetooth::hci::HostBufferSizeCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciReadLocalSupportedCommands(packets::PacketView<true> args) {
- CHECK(args.size() == 0) << __func__ << " size=" << args.size();
- std::shared_ptr<packets::EventPacketBuilder> command_complete =
- packets::EventPacketBuilder::CreateCommandCompleteReadLocalSupportedCommands(hci::Status::SUCCESS,
- properties_.GetSupportedCommands());
- send_event_(command_complete->ToVector());
+void DualModeController::HciReadLocalVersionInformation(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size());
+
+ bluetooth::hci::LocalVersionInformation local_version_information;
+ local_version_information.hci_version_ =
+ static_cast<bluetooth::hci::HciVersion>(properties_.GetVersion());
+ local_version_information.hci_revision_ = properties_.GetRevision();
+ local_version_information.lmp_version_ =
+ static_cast<bluetooth::hci::LmpVersion>(properties_.GetLmpPalVersion());
+ local_version_information.manufacturer_name_ =
+ properties_.GetManufacturerName();
+ local_version_information.lmp_subversion_ = properties_.GetLmpPalSubversion();
+ auto packet =
+ bluetooth::hci::ReadLocalVersionInformationCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+ local_version_information);
+ send_event_(std::move(packet));
}
-void DualModeController::HciReadLocalSupportedCodecs(packets::PacketView<true> args) {
- CHECK(args.size() == 0) << __func__ << " size=" << args.size();
- std::shared_ptr<packets::EventPacketBuilder> command_complete =
- packets::EventPacketBuilder::CreateCommandCompleteReadLocalSupportedCodecs(
- hci::Status::SUCCESS, properties_.GetSupportedCodecs(), properties_.GetVendorSpecificCodecs());
- send_event_(command_complete->ToVector());
+void DualModeController::HciReadRemoteVersionInformation(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 2, "%s size=%zu", __func__, args.size());
+
+ uint16_t handle = args.begin().extract<uint16_t>();
+
+ auto status = link_layer_controller_.SendCommandToRemoteByHandle(
+ bluetooth::hci::OpCode::READ_REMOTE_VERSION_INFORMATION, args, handle);
+
+ auto packet =
+ bluetooth::hci::ReadRemoteVersionInformationStatusBuilder::Create(
+ status, kNumCommandPackets);
+ send_event_(std::move(packet));
}
-void DualModeController::HciReadLocalExtendedFeatures(packets::PacketView<true> args) {
- CHECK(args.size() == 1) << __func__ << " size=" << args.size();
+void DualModeController::HciReadBdAddr(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size());
+ auto packet = bluetooth::hci::ReadBdAddrCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+ properties_.GetAddress());
+ send_event_(std::move(packet));
+}
+
+void DualModeController::HciReadLocalSupportedCommands(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size());
+
+ std::array<uint8_t, 64> supported_commands;
+ supported_commands.fill(0x00);
+ size_t len = properties_.GetSupportedCommands().size();
+ if (len > 64) {
+ len = 64;
+ }
+ std::copy_n(properties_.GetSupportedCommands().begin(), len,
+ supported_commands.begin());
+
+ auto packet =
+ bluetooth::hci::ReadLocalSupportedCommandsCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+ supported_commands);
+ send_event_(std::move(packet));
+}
+
+void DualModeController::HciReadLocalSupportedFeatures(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size());
+ auto packet =
+ bluetooth::hci::ReadLocalSupportedFeaturesCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+ properties_.GetSupportedFeatures());
+ send_event_(std::move(packet));
+}
+
+void DualModeController::HciReadLocalSupportedCodecs(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size());
+ auto packet = bluetooth::hci::ReadLocalSupportedCodecsCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+ properties_.GetSupportedCodecs(), properties_.GetVendorSpecificCodecs());
+ send_event_(std::move(packet));
+}
+
+void DualModeController::HciReadLocalExtendedFeatures(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 1, "%s size=%zu", __func__, args.size());
uint8_t page_number = args.begin().extract<uint8_t>();
- send_event_(packets::EventPacketBuilder::CreateCommandCompleteReadLocalExtendedFeatures(
- hci::Status::SUCCESS, page_number, properties_.GetExtendedFeaturesMaximumPageNumber(),
- properties_.GetExtendedFeatures(page_number))
- ->ToVector());
+
+ auto pakcet =
+ bluetooth::hci::ReadLocalExtendedFeaturesCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS, page_number,
+ properties_.GetExtendedFeaturesMaximumPageNumber(),
+ properties_.GetExtendedFeatures(page_number));
+ send_event_(std::move(pakcet));
}
-void DualModeController::HciReadRemoteExtendedFeatures(packets::PacketView<true> args) {
- CHECK(args.size() == 3) << __func__ << " size=" << args.size();
+void DualModeController::HciReadRemoteExtendedFeatures(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 3, "%s size=%zu", __func__, args.size());
uint16_t handle = args.begin().extract<uint16_t>();
- hci::Status status =
- link_layer_controller_.SendCommandToRemoteByHandle(OpCode::READ_REMOTE_EXTENDED_FEATURES, args, handle);
+ auto status = link_layer_controller_.SendCommandToRemoteByHandle(
+ bluetooth::hci::OpCode::READ_REMOTE_EXTENDED_FEATURES, args, handle);
- SendCommandStatus(status, OpCode::READ_REMOTE_EXTENDED_FEATURES);
+ auto packet = bluetooth::hci::ReadRemoteExtendedFeaturesStatusBuilder::Create(
+ status, kNumCommandPackets);
+ send_event_(std::move(packet));
}
-void DualModeController::HciReadRemoteSupportedFeatures(packets::PacketView<true> args) {
- CHECK(args.size() == 2) << __func__ << " size=" << args.size();
+void DualModeController::HciSwitchRole(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 7, "%s size=%zu", __func__, args.size());
+
+ Address address = args.begin().extract<Address>();
+ uint8_t role = args.begin().extract<uint8_t>();
+
+ auto status = link_layer_controller_.SwitchRole(address, role);
+
+ auto packet = bluetooth::hci::SwitchRoleStatusBuilder::Create(
+ status, kNumCommandPackets);
+ send_event_(std::move(packet));
+}
+
+void DualModeController::HciReadRemoteSupportedFeatures(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 2, "%s size=%zu", __func__, args.size());
uint16_t handle = args.begin().extract<uint16_t>();
- hci::Status status =
- link_layer_controller_.SendCommandToRemoteByHandle(OpCode::READ_REMOTE_SUPPORTED_FEATURES, args, handle);
+ auto status = link_layer_controller_.SendCommandToRemoteByHandle(
+ bluetooth::hci::OpCode::READ_REMOTE_SUPPORTED_FEATURES, args, handle);
- SendCommandStatus(status, OpCode::READ_REMOTE_SUPPORTED_FEATURES);
+ auto packet =
+ bluetooth::hci::ReadRemoteSupportedFeaturesStatusBuilder::Create(
+ status, kNumCommandPackets);
+ send_event_(std::move(packet));
}
-void DualModeController::HciReadClockOffset(packets::PacketView<true> args) {
- CHECK(args.size() == 2) << __func__ << " size=" << args.size();
+void DualModeController::HciReadClockOffset(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 2, "%s size=%zu", __func__, args.size());
uint16_t handle = args.begin().extract<uint16_t>();
- hci::Status status = link_layer_controller_.SendCommandToRemoteByHandle(OpCode::READ_CLOCK_OFFSET, args, handle);
+ auto status = link_layer_controller_.SendCommandToRemoteByHandle(
+ bluetooth::hci::OpCode::READ_CLOCK_OFFSET, args, handle);
- SendCommandStatus(status, OpCode::READ_CLOCK_OFFSET);
+ auto packet = bluetooth::hci::ReadClockOffsetStatusBuilder::Create(
+ status, kNumCommandPackets);
+ send_event_(std::move(packet));
}
-void DualModeController::HciIoCapabilityRequestReply(packets::PacketView<true> args) {
- CHECK(args.size() == 9) << __func__ << " size=" << args.size();
+void DualModeController::HciIoCapabilityRequestReply(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 9, "%s size=%zu", __func__, args.size());
auto args_itr = args.begin();
Address peer = args_itr.extract<Address>();
@@ -417,56 +550,76 @@
uint8_t oob_data_present_flag = args_itr.extract<uint8_t>();
uint8_t authentication_requirements = args_itr.extract<uint8_t>();
- hci::Status status = link_layer_controller_.IoCapabilityRequestReply(peer, io_capability, oob_data_present_flag,
- authentication_requirements);
+ auto status = link_layer_controller_.IoCapabilityRequestReply(
+ peer, io_capability, oob_data_present_flag, authentication_requirements);
+ auto packet = bluetooth::hci::IoCapabilityRequestReplyCompleteBuilder::Create(
+ kNumCommandPackets, status, peer);
- SendCommandCompleteStatusAndAddress(OpCode::IO_CAPABILITY_REQUEST_REPLY, status, peer);
+ send_event_(std::move(packet));
}
-void DualModeController::HciUserConfirmationRequestReply(packets::PacketView<true> args) {
- CHECK(args.size() == 6) << __func__ << " size=" << args.size();
+void DualModeController::HciUserConfirmationRequestReply(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 6, "%s size=%zu", __func__, args.size());
Address peer = args.begin().extract<Address>();
- hci::Status status = link_layer_controller_.UserConfirmationRequestReply(peer);
+ auto status = link_layer_controller_.UserConfirmationRequestReply(peer);
+ auto packet =
+ bluetooth::hci::UserConfirmationRequestReplyCompleteBuilder::Create(
+ kNumCommandPackets, status, peer);
- SendCommandCompleteStatusAndAddress(OpCode::USER_CONFIRMATION_REQUEST_REPLY, status, peer);
+ send_event_(std::move(packet));
}
-void DualModeController::HciUserConfirmationRequestNegativeReply(packets::PacketView<true> args) {
- CHECK(args.size() == 6) << __func__ << " size=" << args.size();
+void DualModeController::HciUserConfirmationRequestNegativeReply(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 6, "%s size=%zu", __func__, args.size());
Address peer = args.begin().extract<Address>();
- hci::Status status = link_layer_controller_.UserConfirmationRequestNegativeReply(peer);
+ auto status =
+ link_layer_controller_.UserConfirmationRequestNegativeReply(peer);
+ auto packet =
+ bluetooth::hci::UserConfirmationRequestNegativeReplyCompleteBuilder::
+ Create(kNumCommandPackets, status, peer);
- SendCommandCompleteStatusAndAddress(OpCode::USER_CONFIRMATION_REQUEST_NEGATIVE_REPLY, status, peer);
+ send_event_(std::move(packet));
}
-void DualModeController::HciUserPasskeyRequestReply(packets::PacketView<true> args) {
- CHECK(args.size() == 10) << __func__ << " size=" << args.size();
+void DualModeController::HciUserPasskeyRequestReply(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 10, "%s size=%zu", __func__, args.size());
auto args_itr = args.begin();
Address peer = args_itr.extract<Address>();
uint32_t numeric_value = args_itr.extract<uint32_t>();
- hci::Status status = link_layer_controller_.UserPasskeyRequestReply(peer, numeric_value);
+ auto status =
+ link_layer_controller_.UserPasskeyRequestReply(peer, numeric_value);
+ auto packet = bluetooth::hci::UserPasskeyRequestReplyCompleteBuilder::Create(
+ kNumCommandPackets, status, peer);
- SendCommandCompleteStatusAndAddress(OpCode::USER_PASSKEY_REQUEST_REPLY, status, peer);
+ send_event_(std::move(packet));
}
-void DualModeController::HciUserPasskeyRequestNegativeReply(packets::PacketView<true> args) {
- CHECK(args.size() == 6) << __func__ << " size=" << args.size();
+void DualModeController::HciUserPasskeyRequestNegativeReply(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 6, "%s size=%zu", __func__, args.size());
Address peer = args.begin().extract<Address>();
- hci::Status status = link_layer_controller_.UserPasskeyRequestNegativeReply(peer);
+ auto status = link_layer_controller_.UserPasskeyRequestNegativeReply(peer);
+ auto packet =
+ bluetooth::hci::UserPasskeyRequestNegativeReplyCompleteBuilder::Create(
+ kNumCommandPackets, status, peer);
- SendCommandCompleteStatusAndAddress(OpCode::USER_PASSKEY_REQUEST_NEGATIVE_REPLY, status, peer);
+ send_event_(std::move(packet));
}
-void DualModeController::HciRemoteOobDataRequestReply(packets::PacketView<true> args) {
- CHECK(args.size() == 38) << __func__ << " size=" << args.size();
+void DualModeController::HciRemoteOobDataRequestReply(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 38, "%s size=%zu", __func__, args.size());
auto args_itr = args.begin();
Address peer = args_itr.extract<Address>();
@@ -478,252 +631,508 @@
for (size_t i = 0; i < 16; i++) {
r.push_back(args_itr.extract<uint8_t>());
}
- hci::Status status = link_layer_controller_.RemoteOobDataRequestReply(peer, c, r);
+ auto status = link_layer_controller_.RemoteOobDataRequestReply(peer, c, r);
+ auto packet =
+ bluetooth::hci::RemoteOobDataRequestReplyCompleteBuilder::Create(
+ kNumCommandPackets, status, peer);
- SendCommandCompleteStatusAndAddress(OpCode::REMOTE_OOB_DATA_REQUEST_REPLY, status, peer);
+ send_event_(std::move(packet));
}
-void DualModeController::HciRemoteOobDataRequestNegativeReply(packets::PacketView<true> args) {
- CHECK(args.size() == 6) << __func__ << " size=" << args.size();
+void DualModeController::HciRemoteOobDataRequestNegativeReply(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 6, "%s size=%zu", __func__, args.size());
Address peer = args.begin().extract<Address>();
- hci::Status status = link_layer_controller_.RemoteOobDataRequestNegativeReply(peer);
+ auto status = link_layer_controller_.RemoteOobDataRequestNegativeReply(peer);
+ auto packet =
+ bluetooth::hci::RemoteOobDataRequestNegativeReplyCompleteBuilder::Create(
+ kNumCommandPackets, status, peer);
- SendCommandCompleteStatusAndAddress(OpCode::REMOTE_OOB_DATA_REQUEST_NEGATIVE_REPLY, status, peer);
+ send_event_(std::move(packet));
}
-void DualModeController::HciIoCapabilityRequestNegativeReply(packets::PacketView<true> args) {
- CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+void DualModeController::HciIoCapabilityRequestNegativeReply(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 7, "%s size=%zu", __func__, args.size());
auto args_itr = args.begin();
Address peer = args_itr.extract<Address>();
- hci::Status reason = args_itr.extract<hci::Status>();
+ bluetooth::hci::ErrorCode reason =
+ args_itr.extract<bluetooth::hci::ErrorCode>();
- hci::Status status = link_layer_controller_.IoCapabilityRequestNegativeReply(peer, reason);
+ auto status =
+ link_layer_controller_.IoCapabilityRequestNegativeReply(peer, reason);
+ auto packet =
+ bluetooth::hci::IoCapabilityRequestNegativeReplyCompleteBuilder::Create(
+ kNumCommandPackets, status, peer);
- SendCommandCompleteStatusAndAddress(OpCode::IO_CAPABILITY_REQUEST_NEGATIVE_REPLY, status, peer);
+ send_event_(std::move(packet));
}
-void DualModeController::HciWriteSimplePairingMode(packets::PacketView<true> args) {
- CHECK(args.size() == 1) << __func__ << " size=" << args.size();
- CHECK(args[0] == 1 || args[0] == 0);
+void DualModeController::HciWriteSimplePairingMode(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 1, "%s size=%zu", __func__, args.size());
+ ASSERT(args[0] == 1 || args[0] == 0);
link_layer_controller_.WriteSimplePairingMode(args[0] == 1);
- SendCommandCompleteSuccess(OpCode::WRITE_SIMPLE_PAIRING_MODE);
+ auto packet = bluetooth::hci::WriteSimplePairingModeCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciChangeConnectionPacketType(packets::PacketView<true> args) {
- CHECK(args.size() == 4) << __func__ << " size=" << args.size();
+void DualModeController::HciChangeConnectionPacketType(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 4, "%s size=%zu", __func__, args.size());
auto args_itr = args.begin();
uint16_t handle = args_itr.extract<uint16_t>();
uint16_t packet_type = args_itr.extract<uint16_t>();
- hci::Status status = link_layer_controller_.ChangeConnectionPacketType(handle, packet_type);
+ auto status =
+ link_layer_controller_.ChangeConnectionPacketType(handle, packet_type);
- SendCommandStatus(status, OpCode::CHANGE_CONNECTION_PACKET_TYPE);
+ auto packet = bluetooth::hci::ChangeConnectionPacketTypeStatusBuilder::Create(
+ status, kNumCommandPackets);
+ send_event_(std::move(packet));
}
-void DualModeController::HciWriteLeHostSupport(packets::PacketView<true> args) {
- CHECK(args.size() == 2) << __func__ << " size=" << args.size();
- SendCommandCompleteSuccess(OpCode::WRITE_LE_HOST_SUPPORT);
+void DualModeController::HciWriteLeHostSupport(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 2, "%s size=%zu", __func__, args.size());
+ auto packet = bluetooth::hci::WriteLeHostSupportCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciSetEventMask(packets::PacketView<true> args) {
- CHECK(args.size() == 8) << __func__ << " size=" << args.size();
- SendCommandCompleteSuccess(OpCode::SET_EVENT_MASK);
+void DualModeController::HciWriteSecureConnectionsHostSupport(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 1, "%s size=%zu", __func__, args.size());
+ properties_.SetExtendedFeatures(properties_.GetExtendedFeatures(1) | 0x8, 1);
+ auto packet =
+ bluetooth::hci::WriteSecureConnectionsHostSupportCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciWriteInquiryMode(packets::PacketView<true> args) {
- CHECK(args.size() == 1) << __func__ << " size=" << args.size();
+void DualModeController::HciSetEventMask(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 8, "%s size=%zu", __func__, args.size());
+ auto packet = bluetooth::hci::SetEventMaskCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
+}
+
+void DualModeController::HciWriteInquiryMode(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 1, "%s size=%zu", __func__, args.size());
link_layer_controller_.SetInquiryMode(args[0]);
- SendCommandCompleteSuccess(OpCode::WRITE_INQUIRY_MODE);
+ auto packet = bluetooth::hci::WriteInquiryModeCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciWritePageScanType(packets::PacketView<true> args) {
- CHECK(args.size() == 1) << __func__ << " size=" << args.size();
- SendCommandCompleteSuccess(OpCode::WRITE_PAGE_SCAN_TYPE);
+void DualModeController::HciWritePageScanType(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 1, "%s size=%zu", __func__, args.size());
+ auto packet = bluetooth::hci::WritePageScanTypeCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciWriteInquiryScanType(packets::PacketView<true> args) {
- CHECK(args.size() == 1) << __func__ << " size=" << args.size();
- SendCommandCompleteSuccess(OpCode::WRITE_INQUIRY_SCAN_TYPE);
+void DualModeController::HciWriteInquiryScanType(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 1, "%s size=%zu", __func__, args.size());
+ auto packet = bluetooth::hci::WriteInquiryScanTypeCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciAuthenticationRequested(packets::PacketView<true> args) {
- CHECK(args.size() == 2) << __func__ << " size=" << args.size();
+void DualModeController::HciAuthenticationRequested(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 2, "%s size=%zu", __func__, args.size());
uint16_t handle = args.begin().extract<uint16_t>();
- hci::Status status = link_layer_controller_.AuthenticationRequested(handle);
+ auto status = link_layer_controller_.AuthenticationRequested(handle);
- SendCommandStatus(status, OpCode::AUTHENTICATION_REQUESTED);
+ auto packet = bluetooth::hci::AuthenticationRequestedStatusBuilder::Create(
+ status, kNumCommandPackets);
+ send_event_(std::move(packet));
}
-void DualModeController::HciSetConnectionEncryption(packets::PacketView<true> args) {
- CHECK(args.size() == 3) << __func__ << " size=" << args.size();
+void DualModeController::HciSetConnectionEncryption(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 3, "%s size=%zu", __func__, args.size());
auto args_itr = args.begin();
uint16_t handle = args_itr.extract<uint16_t>();
uint8_t encryption_enable = args_itr.extract<uint8_t>();
- hci::Status status = link_layer_controller_.SetConnectionEncryption(handle, encryption_enable);
+ auto status =
+ link_layer_controller_.SetConnectionEncryption(handle, encryption_enable);
- SendCommandStatus(status, OpCode::SET_CONNECTION_ENCRYPTION);
+ auto packet = bluetooth::hci::SetConnectionEncryptionStatusBuilder::Create(
+ status, kNumCommandPackets);
+ send_event_(std::move(packet));
}
-void DualModeController::HciWriteAuthenticationEnable(packets::PacketView<true> args) {
- CHECK(args.size() == 1) << __func__ << " size=" << args.size();
+void DualModeController::HciChangeConnectionLinkKey(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 2, "%s size=%zu", __func__, args.size());
+ auto args_itr = args.begin();
+ uint16_t handle = args_itr.extract<uint16_t>();
+
+ auto status = link_layer_controller_.ChangeConnectionLinkKey(handle);
+
+ auto packet = bluetooth::hci::ChangeConnectionLinkKeyStatusBuilder::Create(
+ status, kNumCommandPackets);
+ send_event_(std::move(packet));
+}
+
+void DualModeController::HciMasterLinkKey(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 1, "%s size=%zu", __func__, args.size());
+ auto args_itr = args.begin();
+ uint8_t key_flag = args_itr.extract<uint8_t>();
+
+ auto status = link_layer_controller_.MasterLinkKey(key_flag);
+
+ auto packet = bluetooth::hci::MasterLinkKeyStatusBuilder::Create(
+ status, kNumCommandPackets);
+ send_event_(std::move(packet));
+}
+
+void DualModeController::HciWriteAuthenticationEnable(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 1, "%s size=%zu", __func__, args.size());
properties_.SetAuthenticationEnable(args[0]);
- SendCommandCompleteSuccess(OpCode::WRITE_AUTHENTICATION_ENABLE);
+ auto packet =
+ bluetooth::hci::WriteAuthenticationEnableCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciReadAuthenticationEnable(packets::PacketView<true> args) {
- CHECK(args.size() == 0) << __func__ << " size=" << args.size();
- std::shared_ptr<packets::EventPacketBuilder> command_complete =
- packets::EventPacketBuilder::CreateCommandCompleteReadAuthenticationEnable(hci::Status::SUCCESS,
- properties_.GetAuthenticationEnable());
- send_event_(command_complete->ToVector());
+void DualModeController::HciReadAuthenticationEnable(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size());
+ auto packet = bluetooth::hci::ReadAuthenticationEnableCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+ static_cast<bluetooth::hci::AuthenticationEnable>(
+ properties_.GetAuthenticationEnable()));
+ send_event_(std::move(packet));
}
-void DualModeController::HciWriteClassOfDevice(packets::PacketView<true> args) {
- CHECK(args.size() == 3) << __func__ << " size=" << args.size();
+void DualModeController::HciWriteClassOfDevice(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 3, "%s size=%zu", __func__, args.size());
properties_.SetClassOfDevice(args[0], args[1], args[2]);
- SendCommandCompleteSuccess(OpCode::WRITE_CLASS_OF_DEVICE);
+ auto packet = bluetooth::hci::WriteClassOfDeviceCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciWritePageTimeout(packets::PacketView<true> args) {
- CHECK(args.size() == 2) << __func__ << " size=" << args.size();
- SendCommandCompleteSuccess(OpCode::WRITE_PAGE_TIMEOUT);
+void DualModeController::HciWritePageTimeout(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 2, "%s size=%zu", __func__, args.size());
+ auto packet = bluetooth::hci::WritePageTimeoutCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciWriteDefaultLinkPolicySettings(packets::PacketView<true> args) {
- CHECK(args.size() == 2) << __func__ << " size=" << args.size();
- SendCommandCompleteSuccess(OpCode::WRITE_DEFAULT_LINK_POLICY_SETTINGS);
+void DualModeController::HciHoldMode(bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 6, "%s size=%zu", __func__, args.size());
+ auto args_itr = args.begin();
+ uint16_t handle = args_itr.extract<uint16_t>();
+ uint16_t hold_mode_max_interval = args_itr.extract<uint16_t>();
+ uint16_t hold_mode_min_interval = args_itr.extract<uint16_t>();
+
+ auto status = link_layer_controller_.HoldMode(handle, hold_mode_max_interval,
+ hold_mode_min_interval);
+
+ auto packet =
+ bluetooth::hci::HoldModeStatusBuilder::Create(status, kNumCommandPackets);
+ send_event_(std::move(packet));
}
-void DualModeController::HciWriteLinkPolicySettings(packets::PacketView<true> args) {
- CHECK(args.size() == 4) << __func__ << " size=" << args.size();
+void DualModeController::HciSniffMode(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 10, "%s size=%zu", __func__, args.size());
+ auto args_itr = args.begin();
+ uint16_t handle = args_itr.extract<uint16_t>();
+ uint16_t sniff_max_interval = args_itr.extract<uint16_t>();
+ uint16_t sniff_min_interval = args_itr.extract<uint16_t>();
+ uint16_t sniff_attempt = args_itr.extract<uint16_t>();
+ uint16_t sniff_timeout = args_itr.extract<uint16_t>();
+
+ auto status = link_layer_controller_.SniffMode(handle, sniff_max_interval,
+ sniff_min_interval,
+ sniff_attempt, sniff_timeout);
+
+ auto packet = bluetooth::hci::SniffModeStatusBuilder::Create(
+ status, kNumCommandPackets);
+ send_event_(std::move(packet));
+}
+
+void DualModeController::HciExitSniffMode(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 2, "%s size=%zu", __func__, args.size());
+ auto args_itr = args.begin();
+ uint16_t handle = args_itr.extract<uint16_t>();
+
+ auto status = link_layer_controller_.ExitSniffMode(handle);
+
+ auto packet = bluetooth::hci::ExitSniffModeStatusBuilder::Create(
+ status, kNumCommandPackets);
+ send_event_(std::move(packet));
+}
+
+void DualModeController::HciQosSetup(bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 20, "%s size=%zu", __func__, args.size());
+ auto args_itr = args.begin();
+ uint16_t handle = args_itr.extract<uint16_t>();
+ args_itr.extract<uint8_t>(); // unused
+ uint8_t service_type = args_itr.extract<uint8_t>();
+ uint32_t token_rate = args_itr.extract<uint32_t>();
+ uint32_t peak_bandwidth = args_itr.extract<uint32_t>();
+ uint32_t latency = args_itr.extract<uint32_t>();
+ uint32_t delay_variation = args_itr.extract<uint32_t>();
+
+ auto status =
+ link_layer_controller_.QosSetup(handle, service_type, token_rate,
+ peak_bandwidth, latency, delay_variation);
+
+ auto packet =
+ bluetooth::hci::QosSetupStatusBuilder::Create(status, kNumCommandPackets);
+ send_event_(std::move(packet));
+}
+
+void DualModeController::HciWriteDefaultLinkPolicySettings(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 2, "%s size=%zu", __func__, args.size());
+ auto packet =
+ bluetooth::hci::WriteDefaultLinkPolicySettingsCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
+}
+
+void DualModeController::HciFlowSpecification(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 21, "%s size=%zu", __func__, args.size());
+ auto args_itr = args.begin();
+ uint16_t handle = args_itr.extract<uint16_t>();
+ args_itr.extract<uint8_t>(); // unused
+ uint8_t flow_direction = args_itr.extract<uint8_t>();
+ uint8_t service_type = args_itr.extract<uint8_t>();
+ uint32_t token_rate = args_itr.extract<uint32_t>();
+ uint32_t token_bucket_size = args_itr.extract<uint32_t>();
+ uint32_t peak_bandwidth = args_itr.extract<uint32_t>();
+ uint32_t access_latency = args_itr.extract<uint32_t>();
+
+ auto status = link_layer_controller_.FlowSpecification(
+ handle, flow_direction, service_type, token_rate, token_bucket_size,
+ peak_bandwidth, access_latency);
+
+ auto packet = bluetooth::hci::FlowSpecificationStatusBuilder::Create(
+ status, kNumCommandPackets);
+ send_event_(std::move(packet));
+}
+
+void DualModeController::HciWriteLinkPolicySettings(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 4, "%s size=%zu", __func__, args.size());
auto args_itr = args.begin();
uint16_t handle = args_itr.extract<uint16_t>();
uint16_t settings = args_itr.extract<uint16_t>();
- hci::Status status = link_layer_controller_.WriteLinkPolicySettings(handle, settings);
+ auto status =
+ link_layer_controller_.WriteLinkPolicySettings(handle, settings);
- send_event_(packets::EventPacketBuilder::CreateCommandCompleteWriteLinkPolicySettings(status, handle)->ToVector());
+ auto packet = bluetooth::hci::WriteLinkPolicySettingsCompleteBuilder::Create(
+ kNumCommandPackets, status, handle);
+ send_event_(std::move(packet));
}
-void DualModeController::HciWriteLinkSupervisionTimeout(packets::PacketView<true> args) {
- CHECK(args.size() == 4) << __func__ << " size=" << args.size();
+void DualModeController::HciWriteLinkSupervisionTimeout(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 4, "%s size=%zu", __func__, args.size());
auto args_itr = args.begin();
uint16_t handle = args_itr.extract<uint16_t>();
uint16_t timeout = args_itr.extract<uint16_t>();
- hci::Status status = link_layer_controller_.WriteLinkSupervisionTimeout(handle, timeout);
-
- send_event_(
- packets::EventPacketBuilder::CreateCommandCompleteWriteLinkSupervisionTimeout(status, handle)->ToVector());
+ auto status =
+ link_layer_controller_.WriteLinkSupervisionTimeout(handle, timeout);
+ auto packet =
+ bluetooth::hci::WriteLinkSupervisionTimeoutCompleteBuilder::Create(
+ kNumCommandPackets, status, handle);
+ send_event_(std::move(packet));
}
-void DualModeController::HciReadLocalName(packets::PacketView<true> args) {
- CHECK(args.size() == 0) << __func__ << " size=" << args.size();
- std::shared_ptr<packets::EventPacketBuilder> command_complete =
- packets::EventPacketBuilder::CreateCommandCompleteReadLocalName(hci::Status::SUCCESS, properties_.GetName());
- send_event_(command_complete->ToVector());
+void DualModeController::HciReadLocalName(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size());
+
+ std::array<uint8_t, 248> local_name;
+ local_name.fill(0x00);
+ size_t len = properties_.GetName().size();
+ if (len > 247) {
+ len = 247; // one byte for NULL octet (0x00)
+ }
+ std::copy_n(properties_.GetName().begin(), len, local_name.begin());
+
+ auto packet = bluetooth::hci::ReadLocalNameCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS, local_name);
+ send_event_(std::move(packet));
}
-void DualModeController::HciWriteLocalName(packets::PacketView<true> args) {
- CHECK(args.size() == 248) << __func__ << " size=" << args.size();
+void DualModeController::HciWriteLocalName(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 248, "%s size=%zu", __func__, args.size());
std::vector<uint8_t> clipped(args.begin(), args.begin() + LastNonZero(args) + 1);
properties_.SetName(clipped);
- SendCommandCompleteSuccess(OpCode::WRITE_LOCAL_NAME);
+ auto packet = bluetooth::hci::WriteLocalNameCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciWriteExtendedInquiryResponse(packets::PacketView<true> args) {
- CHECK(args.size() == 241) << __func__ << " size=" << args.size();
+void DualModeController::HciWriteExtendedInquiryResponse(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 241, "%s size=%zu", __func__, args.size());
// Strip FEC byte and trailing zeros
std::vector<uint8_t> clipped(args.begin() + 1, args.begin() + LastNonZero(args) + 1);
properties_.SetExtendedInquiryData(clipped);
- LOG_WARN(LOG_TAG, "Write EIR Inquiry - Size = %d (%d)", static_cast<int>(properties_.GetExtendedInquiryData().size()),
- static_cast<int>(clipped.size()));
- SendCommandCompleteSuccess(OpCode::WRITE_EXTENDED_INQUIRY_RESPONSE);
+ auto packet =
+ bluetooth::hci::WriteExtendedInquiryResponseCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciWriteVoiceSetting(packets::PacketView<true> args) {
- CHECK(args.size() == 2) << __func__ << " size=" << args.size();
- SendCommandCompleteSuccess(OpCode::WRITE_VOICE_SETTING);
+void DualModeController::HciRefreshEncryptionKey(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 2, "%s size=%zu", __func__, args.size());
+ auto args_itr = args.begin();
+ uint16_t handle = args_itr.extract<uint16_t>();
+ auto status_packet =
+ bluetooth::hci::RefreshEncryptionKeyStatusBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, kNumCommandPackets);
+ send_event_(std::move(status_packet));
+ // TODO: Support this in the link layer
+ auto complete_packet =
+ bluetooth::hci::EncryptionKeyRefreshCompleteBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, handle);
+ send_event_(std::move(complete_packet));
}
-void DualModeController::HciWriteCurrentIacLap(packets::PacketView<true> args) {
- CHECK(args.size() > 0);
- CHECK(args.size() == 1 + (3 * args[0])); // count + 3-byte IACs
-
- SendCommandCompleteSuccess(OpCode::WRITE_CURRENT_IAC_LAP);
+void DualModeController::HciWriteVoiceSetting(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 2, "%s size=%zu", __func__, args.size());
+ auto packet = bluetooth::hci::WriteVoiceSettingCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciWriteInquiryScanActivity(packets::PacketView<true> args) {
- CHECK(args.size() == 4) << __func__ << " size=" << args.size();
- SendCommandCompleteSuccess(OpCode::WRITE_INQUIRY_SCAN_ACTIVITY);
+void DualModeController::HciWriteCurrentIacLap(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT(args.size() > 0);
+ ASSERT(args.size() == 1 + (3 * args[0])); // count + 3-byte IACs
+ auto packet = bluetooth::hci::WriteCurrentIacLapCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciWriteScanEnable(packets::PacketView<true> args) {
- CHECK(args.size() == 1) << __func__ << " size=" << args.size();
+void DualModeController::HciWriteInquiryScanActivity(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 4, "%s size=%zu", __func__, args.size());
+ auto packet = bluetooth::hci::WriteInquiryScanActivityCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
+}
+
+void DualModeController::HciWriteScanEnable(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 1, "%s size=%zu", __func__, args.size());
link_layer_controller_.SetInquiryScanEnable(args[0] & 0x1);
link_layer_controller_.SetPageScanEnable(args[0] & 0x2);
- SendCommandCompleteSuccess(OpCode::WRITE_SCAN_ENABLE);
+ auto packet = bluetooth::hci::WriteScanEnableCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciSetEventFilter(packets::PacketView<true> args) {
- CHECK(args.size() > 0);
- SendCommandCompleteSuccess(OpCode::SET_EVENT_FILTER);
+void DualModeController::HciSetEventFilter(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT(args.size() > 0);
+ auto packet = bluetooth::hci::SetEventFilterCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciInquiry(packets::PacketView<true> args) {
- CHECK(args.size() == 5) << __func__ << " size=" << args.size();
- link_layer_controller_.SetInquiryLAP(args[0] | (args[1] << 8) | (args[2] << 16));
+void DualModeController::HciInquiry(bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 5, "%s size=%zu", __func__, args.size());
+ link_layer_controller_.SetInquiryLAP(args[0] | (args[1], 8) | (args[2], 16));
link_layer_controller_.SetInquiryMaxResponses(args[4]);
link_layer_controller_.StartInquiry(std::chrono::milliseconds(args[3] * 1280));
- SendCommandStatusSuccess(OpCode::INQUIRY);
+ auto packet = bluetooth::hci::InquiryStatusBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, kNumCommandPackets);
+ send_event_(std::move(packet));
}
-void DualModeController::HciInquiryCancel(packets::PacketView<true> args) {
- CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+void DualModeController::HciInquiryCancel(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size());
link_layer_controller_.InquiryCancel();
- SendCommandCompleteSuccess(OpCode::INQUIRY_CANCEL);
+ auto packet = bluetooth::hci::InquiryCancelCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciAcceptConnectionRequest(packets::PacketView<true> args) {
- CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+void DualModeController::HciAcceptConnectionRequest(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 7, "%s size=%zu", __func__, args.size());
Address addr = args.begin().extract<Address>();
bool try_role_switch = args[6] == 0;
- hci::Status status = link_layer_controller_.AcceptConnectionRequest(addr, try_role_switch);
- SendCommandStatus(status, OpCode::ACCEPT_CONNECTION_REQUEST);
+ auto status =
+ link_layer_controller_.AcceptConnectionRequest(addr, try_role_switch);
+ auto packet = bluetooth::hci::AcceptConnectionRequestStatusBuilder::Create(
+ status, kNumCommandPackets);
+ send_event_(std::move(packet));
}
-void DualModeController::HciRejectConnectionRequest(packets::PacketView<true> args) {
- CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+void DualModeController::HciRejectConnectionRequest(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 7, "%s size=%zu", __func__, args.size());
auto args_itr = args.begin();
Address addr = args_itr.extract<Address>();
uint8_t reason = args_itr.extract<uint8_t>();
- hci::Status status = link_layer_controller_.RejectConnectionRequest(addr, reason);
- SendCommandStatus(status, OpCode::REJECT_CONNECTION_REQUEST);
+ auto status = link_layer_controller_.RejectConnectionRequest(addr, reason);
+ auto packet = bluetooth::hci::RejectConnectionRequestStatusBuilder::Create(
+ status, kNumCommandPackets);
+ send_event_(std::move(packet));
}
-void DualModeController::HciLinkKeyRequestReply(packets::PacketView<true> args) {
- CHECK(args.size() == 22) << __func__ << " size=" << args.size();
+void DualModeController::HciLinkKeyRequestReply(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 22, "%s size=%zu", __func__, args.size());
+ auto args_it = args.begin();
+ Address addr = args_it.extract<Address>();
+ auto key = args.begin().extract<std::array<uint8_t, 16>>();
+ auto status = link_layer_controller_.LinkKeyRequestReply(addr, key);
+ auto packet = bluetooth::hci::LinkKeyRequestReplyCompleteBuilder::Create(
+ kNumCommandPackets, status);
+ send_event_(std::move(packet));
+}
+
+void DualModeController::HciLinkKeyRequestNegativeReply(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 6, "%s size=%zu", __func__, args.size());
Address addr = args.begin().extract<Address>();
- packets::PacketView<true> key = args.SubViewLittleEndian(6, 22);
- hci::Status status = link_layer_controller_.LinkKeyRequestReply(addr, key);
- send_event_(packets::EventPacketBuilder::CreateCommandCompleteLinkKeyRequestReply(status, addr)->ToVector());
+ auto status = link_layer_controller_.LinkKeyRequestNegativeReply(addr);
+ auto packet =
+ bluetooth::hci::LinkKeyRequestNegativeReplyCompleteBuilder::Create(
+ kNumCommandPackets, status, addr);
+ send_event_(std::move(packet));
}
-void DualModeController::HciLinkKeyRequestNegativeReply(packets::PacketView<true> args) {
- CHECK(args.size() == 6) << __func__ << " size=" << args.size();
- Address addr = args.begin().extract<Address>();
- hci::Status status = link_layer_controller_.LinkKeyRequestNegativeReply(addr);
- send_event_(packets::EventPacketBuilder::CreateCommandCompleteLinkKeyRequestNegativeReply(status, addr)->ToVector());
-}
-
-void DualModeController::HciDeleteStoredLinkKey(packets::PacketView<true> args) {
- CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+void DualModeController::HciDeleteStoredLinkKey(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 7, "%s size=%zu", __func__, args.size());
uint16_t deleted_keys = 0;
@@ -736,83 +1145,142 @@
security_manager_.DeleteAllKeys();
}
- send_event_(packets::EventPacketBuilder::CreateCommandCompleteDeleteStoredLinkKey(hci::Status::SUCCESS, deleted_keys)
- ->ToVector());
+ auto packet = bluetooth::hci::DeleteStoredLinkKeyCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS, deleted_keys);
+
+ send_event_(std::move(packet));
}
-void DualModeController::HciRemoteNameRequest(packets::PacketView<true> args) {
- CHECK(args.size() == 10) << __func__ << " size=" << args.size();
+void DualModeController::HciRemoteNameRequest(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 10, "%s size=%zu", __func__, args.size());
Address remote_addr = args.begin().extract<Address>();
- hci::Status status =
- link_layer_controller_.SendCommandToRemoteByAddress(OpCode::REMOTE_NAME_REQUEST, args, remote_addr, false);
+ auto status = link_layer_controller_.SendCommandToRemoteByAddress(
+ bluetooth::hci::OpCode::REMOTE_NAME_REQUEST, args, remote_addr);
- SendCommandStatus(status, OpCode::REMOTE_NAME_REQUEST);
+ auto packet = bluetooth::hci::RemoteNameRequestStatusBuilder::Create(
+ status, kNumCommandPackets);
+ send_event_(std::move(packet));
}
-void DualModeController::HciLeSetEventMask(packets::PacketView<true> args) {
- CHECK(args.size() == 8) << __func__ << " size=" << args.size();
+void DualModeController::HciLeSetEventMask(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 8, "%s size=%zu", __func__, args.size());
/*
uint64_t mask = args.begin().extract<uint64_t>();
link_layer_controller_.SetLeEventMask(mask);
*/
- SendCommandCompleteSuccess(OpCode::LE_SET_EVENT_MASK);
+ auto packet = bluetooth::hci::LeSetEventMaskCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciLeReadBufferSize(packets::PacketView<true> args) {
- CHECK(args.size() == 0) << __func__ << " size=" << args.size();
- std::shared_ptr<packets::EventPacketBuilder> command_complete =
- packets::EventPacketBuilder::CreateCommandCompleteLeReadBufferSize(
- hci::Status::SUCCESS, properties_.GetLeDataPacketLength(), properties_.GetTotalNumLeDataPackets());
- send_event_(command_complete->ToVector());
+void DualModeController::HciLeReadBufferSize(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size());
+
+ bluetooth::hci::LeBufferSize le_buffer_size;
+ le_buffer_size.le_data_packet_length_ = properties_.GetLeDataPacketLength();
+ le_buffer_size.total_num_le_packets_ = properties_.GetTotalNumLeDataPackets();
+
+ auto packet = bluetooth::hci::LeReadBufferSizeCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS, le_buffer_size);
+ send_event_(std::move(packet));
}
-void DualModeController::HciLeReadLocalSupportedFeatures(packets::PacketView<true> args) {
- CHECK(args.size() == 0) << __func__ << " size=" << args.size();
- std::shared_ptr<packets::EventPacketBuilder> command_complete =
- packets::EventPacketBuilder::CreateCommandCompleteLeReadLocalSupportedFeatures(
- hci::Status::SUCCESS, properties_.GetLeSupportedFeatures());
- send_event_(command_complete->ToVector());
+void DualModeController::HciLeReadLocalSupportedFeatures(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size());
+ auto packet =
+ bluetooth::hci::LeReadLocalSupportedFeaturesCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+ properties_.GetLeSupportedFeatures());
+ send_event_(std::move(packet));
}
-void DualModeController::HciLeSetRandomAddress(packets::PacketView<true> args) {
- CHECK(args.size() == 6) << __func__ << " size=" << args.size();
+void DualModeController::HciLeSetRandomAddress(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 6, "%s size=%zu", __func__, args.size());
properties_.SetLeAddress(args.begin().extract<Address>());
- SendCommandCompleteSuccess(OpCode::LE_SET_RANDOM_ADDRESS);
+ auto packet = bluetooth::hci::LeSetRandomAddressCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciLeSetAdvertisingParameters(packets::PacketView<true> args) {
- CHECK(args.size() == 15) << __func__ << " size=" << args.size();
+void DualModeController::HciLeSetAdvertisingParameters(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 15, "%s size=%zu", __func__, args.size());
+ auto args_itr = args.begin();
+ properties_.SetLeAdvertisingParameters(
+ args_itr.extract<uint16_t>() /* AdverisingIntervalMin */,
+ args_itr.extract<uint16_t>() /* AdverisingIntervalMax */, args_itr.extract<uint8_t>() /* AdverisingType */,
+ args_itr.extract<uint8_t>() /* OwnAddressType */, args_itr.extract<uint8_t>() /* PeerAddressType */,
+ args_itr.extract<Address>() /* PeerAddress */, args_itr.extract<uint8_t>() /* AdvertisingChannelMap */,
+ args_itr.extract<uint8_t>() /* AdvertisingFilterPolicy */
+ );
- SendCommandCompleteSuccess(OpCode::LE_SET_ADVERTISING_PARAMETERS);
+ auto packet =
+ bluetooth::hci::LeSetAdvertisingParametersCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciLeSetAdvertisingData(packets::PacketView<true> args) {
- CHECK(args.size() > 0);
- SendCommandCompleteSuccess(OpCode::LE_SET_ADVERTISING_DATA);
+void DualModeController::HciLeSetAdvertisingData(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 32, "%s size=%zu", __func__, args.size());
+ properties_.SetLeAdvertisement(std::vector<uint8_t>(args.begin() + 1, args.end()));
+ auto packet = bluetooth::hci::LeSetAdvertisingDataCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciLeSetScanParameters(packets::PacketView<true> args) {
- CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+void DualModeController::HciLeSetScanResponseData(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 32, "%s size=%zu", __func__, args.size());
+ properties_.SetLeScanResponse(std::vector<uint8_t>(args.begin() + 1, args.end()));
+ auto packet = bluetooth::hci::LeSetScanResponseDataCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
+}
+
+void DualModeController::HciLeSetAdvertisingEnable(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 1, "%s size=%zu", __func__, args.size());
+ auto status = link_layer_controller_.SetLeAdvertisingEnable(
+ args.begin().extract<uint8_t>());
+ auto packet = bluetooth::hci::LeSetAdvertisingEnableCompleteBuilder::Create(
+ kNumCommandPackets, status);
+ send_event_(std::move(packet));
+}
+
+void DualModeController::HciLeSetScanParameters(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 7, "%s size=%zu", __func__, args.size());
link_layer_controller_.SetLeScanType(args[0]);
- link_layer_controller_.SetLeScanInterval(args[1] | (args[2] << 8));
- link_layer_controller_.SetLeScanWindow(args[3] | (args[4] << 8));
+ link_layer_controller_.SetLeScanInterval(args[1] | (args[2], 8));
+ link_layer_controller_.SetLeScanWindow(args[3] | (args[4], 8));
link_layer_controller_.SetLeAddressType(args[5]);
link_layer_controller_.SetLeScanFilterPolicy(args[6]);
- SendCommandCompleteSuccess(OpCode::LE_SET_SCAN_PARAMETERS);
+ auto packet = bluetooth::hci::LeSetScanParametersCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciLeSetScanEnable(packets::PacketView<true> args) {
- CHECK(args.size() == 2) << __func__ << " size=" << args.size();
- LOG_INFO(LOG_TAG, "SetScanEnable: %d %d", args[0], args[1]);
+void DualModeController::HciLeSetScanEnable(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 2, "%s size=%zu", __func__, args.size());
link_layer_controller_.SetLeScanEnable(args[0]);
link_layer_controller_.SetLeFilterDuplicates(args[1]);
- SendCommandCompleteSuccess(OpCode::LE_SET_SCAN_ENABLE);
+ auto packet = bluetooth::hci::LeSetScanEnableCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciLeCreateConnection(packets::PacketView<true> args) {
- CHECK(args.size() == 25) << __func__ << " size=" << args.size();
+void DualModeController::HciLeCreateConnection(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 25, "%s size=%zu", __func__, args.size());
auto args_itr = args.begin();
link_layer_controller_.SetLeScanInterval(args_itr.extract<uint16_t>());
link_layer_controller_.SetLeScanWindow(args_itr.extract<uint16_t>());
@@ -833,23 +1301,31 @@
link_layer_controller_.SetLeMinimumCeLength(args_itr.extract<uint16_t>());
link_layer_controller_.SetLeMaximumCeLength(args_itr.extract<uint16_t>());
- hci::Status status = link_layer_controller_.SetLeConnect(true);
+ auto status = link_layer_controller_.SetLeConnect(true);
- SendCommandStatus(status, OpCode::LE_CREATE_CONNECTION);
+ auto packet = bluetooth::hci::LeCreateConnectionStatusBuilder::Create(
+ status, kNumCommandPackets);
+ send_event_(std::move(packet));
}
-void DualModeController::HciLeConnectionUpdate(packets::PacketView<true> args) {
- CHECK(args.size() == 14) << __func__ << " size=" << args.size();
+void DualModeController::HciLeConnectionUpdate(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 14, "%s size=%zu", __func__, args.size());
- SendCommandStatus(hci::Status::CONNECTION_REJECTED_UNACCEPTABLE_BD_ADDR, OpCode::LE_CONNECTION_UPDATE);
+ auto status_packet = bluetooth::hci::LeConnectionUpdateStatusBuilder::Create(
+ bluetooth::hci::ErrorCode::CONNECTION_REJECTED_UNACCEPTABLE_BD_ADDR,
+ kNumCommandPackets);
+ send_event_(std::move(status_packet));
- send_event_(packets::EventPacketBuilder::CreateLeConnectionUpdateCompleteEvent(hci::Status::SUCCESS, 0x0002, 0x0006,
- 0x0000, 0x01f4)
- ->ToVector());
+ auto complete_packet =
+ bluetooth::hci::LeConnectionUpdateCompleteBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, 0x0002, 0x0006, 0x0000, 0x01f4);
+ send_event_(std::move(complete_packet));
}
-void DualModeController::HciCreateConnection(packets::PacketView<true> args) {
- CHECK(args.size() == 13) << __func__ << " size=" << args.size();
+void DualModeController::HciCreateConnection(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 13, "%s size=%zu", __func__, args.size());
auto args_itr = args.begin();
Address address = args_itr.extract<Address>();
@@ -858,150 +1334,262 @@
uint16_t clock_offset = args_itr.extract<uint16_t>();
uint8_t allow_role_switch = args_itr.extract<uint8_t>();
- hci::Status status =
- link_layer_controller_.CreateConnection(address, packet_type, page_scan_mode, clock_offset, allow_role_switch);
+ auto status = link_layer_controller_.CreateConnection(
+ address, packet_type, page_scan_mode, clock_offset, allow_role_switch);
- SendCommandStatus(status, OpCode::CREATE_CONNECTION);
+ auto packet = bluetooth::hci::CreateConnectionStatusBuilder::Create(
+ status, kNumCommandPackets);
+ send_event_(std::move(packet));
}
-void DualModeController::HciDisconnect(packets::PacketView<true> args) {
- CHECK(args.size() == 3) << __func__ << " size=" << args.size();
+void DualModeController::HciDisconnect(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 3, "%s size=%zu", __func__, args.size());
auto args_itr = args.begin();
uint16_t handle = args_itr.extract<uint16_t>();
uint8_t reason = args_itr.extract<uint8_t>();
- hci::Status status = link_layer_controller_.Disconnect(handle, reason);
+ auto status = link_layer_controller_.Disconnect(handle, reason);
- SendCommandStatus(status, OpCode::DISCONNECT);
+ auto packet = bluetooth::hci::DisconnectStatusBuilder::Create(
+ status, kNumCommandPackets);
+ send_event_(std::move(packet));
}
-void DualModeController::HciLeConnectionCancel(packets::PacketView<true> args) {
- CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+void DualModeController::HciLeConnectionCancel(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size());
link_layer_controller_.SetLeConnect(false);
- SendCommandStatusSuccess(OpCode::LE_CREATE_CONNECTION_CANCEL);
+ auto packet = bluetooth::hci::LeCreateConnectionCancelStatusBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, kNumCommandPackets);
+ send_event_(std::move(packet));
/* For testing Jakub's patch: Figure out a neat way to call this without
recompiling. I'm thinking about a bad device. */
/*
SendCommandCompleteOnlyStatus(OpCode::LE_CREATE_CONNECTION_CANCEL,
- Status::ERR_COMMAND_DISALLOWED);
+ bluetooth::hci::ErrorCode::COMMAND_DISALLOWED);
*/
}
-void DualModeController::HciLeReadWhiteListSize(packets::PacketView<true> args) {
- CHECK(args.size() == 0) << __func__ << " size=" << args.size();
- std::shared_ptr<packets::EventPacketBuilder> command_complete =
- packets::EventPacketBuilder::CreateCommandCompleteLeReadWhiteListSize(hci::Status::SUCCESS,
- properties_.GetLeWhiteListSize());
- send_event_(command_complete->ToVector());
+void DualModeController::HciLeReadWhiteListSize(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size());
+ auto packet = bluetooth::hci::LeReadWhiteListSizeCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+ properties_.GetLeWhiteListSize());
+ send_event_(std::move(packet));
}
-void DualModeController::HciLeClearWhiteList(packets::PacketView<true> args) {
- CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+void DualModeController::HciLeClearWhiteList(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size());
link_layer_controller_.LeWhiteListClear();
- SendCommandCompleteSuccess(OpCode::LE_CLEAR_WHITE_LIST);
+ auto packet = bluetooth::hci::LeClearWhiteListCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciLeAddDeviceToWhiteList(packets::PacketView<true> args) {
- CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+void DualModeController::HciLeAddDeviceToWhiteList(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 7, "%s size=%zu", __func__, args.size());
if (link_layer_controller_.LeWhiteListFull()) {
- SendCommandCompleteOnlyStatus(OpCode::LE_ADD_DEVICE_TO_WHITE_LIST, hci::Status::MEMORY_CAPACITY_EXCEEDED);
+ auto packet = bluetooth::hci::LeAddDeviceToWhiteListCompleteBuilder::Create(
+ kNumCommandPackets,
+ bluetooth::hci::ErrorCode::MEMORY_CAPACITY_EXCEEDED);
+ send_event_(std::move(packet));
return;
}
auto args_itr = args.begin();
uint8_t addr_type = args_itr.extract<uint8_t>();
Address address = args_itr.extract<Address>();
link_layer_controller_.LeWhiteListAddDevice(address, addr_type);
- SendCommandCompleteSuccess(OpCode::LE_ADD_DEVICE_TO_WHITE_LIST);
+ auto packet = bluetooth::hci::LeAddDeviceToWhiteListCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-void DualModeController::HciLeRemoveDeviceFromWhiteList(packets::PacketView<true> args) {
- CHECK(args.size() == 7) << __func__ << " size=" << args.size();
+void DualModeController::HciLeRemoveDeviceFromWhiteList(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 7, "%s size=%zu", __func__, args.size());
auto args_itr = args.begin();
uint8_t addr_type = args_itr.extract<uint8_t>();
Address address = args_itr.extract<Address>();
link_layer_controller_.LeWhiteListRemoveDevice(address, addr_type);
- SendCommandCompleteSuccess(OpCode::LE_REMOVE_DEVICE_FROM_WHITE_LIST);
+ auto packet =
+ bluetooth::hci::LeRemoveDeviceFromWhiteListCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-/*
-void DualModeController::HciLeReadRemoteUsedFeaturesRsp(uint16_t handle,
- uint64_t features) {
- std::shared_ptr<packets::EventPacketBuilder> event =
- packets::EventPacketBuilder::CreateLeRemoteUsedFeaturesEvent(
- hci::Status::SUCCESS, handle, features);
- send_event_(event->ToVector());
+void DualModeController::HciLeClearResolvingList(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size());
+ link_layer_controller_.LeResolvingListClear();
+ auto packet = bluetooth::hci::LeClearResolvingListCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
-*/
-void DualModeController::HciLeReadRemoteFeatures(packets::PacketView<true> args) {
- CHECK(args.size() == 2) << __func__ << " size=" << args.size();
+void DualModeController::HciLeAddDeviceToResolvingList(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 39, "%s size=%zu", __func__, args.size());
+
+ if (link_layer_controller_.LeResolvingListFull()) {
+ auto packet =
+ bluetooth::hci::LeAddDeviceToResolvingListCompleteBuilder::Create(
+ kNumCommandPackets,
+ bluetooth::hci::ErrorCode::MEMORY_CAPACITY_EXCEEDED);
+ send_event_(std::move(packet));
+ return;
+ }
+ auto args_itr = args.begin();
+ uint8_t addr_type = args_itr.extract<uint8_t>();
+ Address address = args_itr.extract<Address>();
+ std::array<uint8_t, LinkLayerController::kIrk_size> peerIrk;
+ std::array<uint8_t, LinkLayerController::kIrk_size> localIrk;
+ for (size_t irk_ind = 0; irk_ind < LinkLayerController::kIrk_size;
+ irk_ind++) {
+ peerIrk[irk_ind] = args_itr.extract<uint8_t>();
+ }
+
+ for (size_t irk_ind = 0; irk_ind < LinkLayerController::kIrk_size;
+ irk_ind++) {
+ localIrk[irk_ind] = args_itr.extract<uint8_t>();
+ }
+
+ link_layer_controller_.LeResolvingListAddDevice(address, addr_type, peerIrk,
+ localIrk);
+ auto packet =
+ bluetooth::hci::LeAddDeviceToResolvingListCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
+}
+
+void DualModeController::HciLeRemoveDeviceFromResolvingList(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 7, "%s size=%zu", __func__, args.size());
+
+ auto args_itr = args.begin();
+ uint8_t addr_type = args_itr.extract<uint8_t>();
+ Address address = args_itr.extract<Address>();
+ link_layer_controller_.LeResolvingListRemoveDevice(address, addr_type);
+ auto packet =
+ bluetooth::hci::LeRemoveDeviceFromResolvingListCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
+}
+
+void DualModeController::HciLeSetPrivacyMode(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 8, "%s size=%zu", __func__, args.size());
+
+ auto args_itr = args.begin();
+ uint8_t peer_identity_address_type = args_itr.extract<uint8_t>();
+ Address peer_identity_address = args_itr.extract<Address>();
+ uint8_t privacy_mode = args_itr.extract<uint8_t>();
+
+ if (link_layer_controller_.LeResolvingListContainsDevice(
+ peer_identity_address, peer_identity_address_type)) {
+ link_layer_controller_.LeSetPrivacyMode(
+ peer_identity_address_type, peer_identity_address, privacy_mode);
+ }
+
+ auto packet = bluetooth::hci::LeSetPrivacyModeCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
+}
+
+void DualModeController::HciLeReadRemoteFeatures(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 2, "%s size=%zu", __func__, args.size());
uint16_t handle = args.begin().extract<uint16_t>();
- hci::Status status =
- link_layer_controller_.SendCommandToRemoteByHandle(OpCode::LE_READ_REMOTE_FEATURES, args, handle);
+ auto status = link_layer_controller_.SendCommandToRemoteByHandle(
+ bluetooth::hci::OpCode::LE_READ_REMOTE_FEATURES, args, handle);
- SendCommandStatus(status, OpCode::LE_READ_REMOTE_FEATURES);
+ auto packet = bluetooth::hci::LeConnectionUpdateStatusBuilder::Create(
+ status, kNumCommandPackets);
+ send_event_(std::move(packet));
}
-void DualModeController::HciLeRand(packets::PacketView<true> args) {
- CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+void DualModeController::HciLeRand(bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size());
uint64_t random_val = 0;
for (size_t rand_bytes = 0; rand_bytes < sizeof(uint64_t); rand_bytes += sizeof(RAND_MAX)) {
random_val = (random_val << (8 * sizeof(RAND_MAX))) | random();
}
- std::shared_ptr<packets::EventPacketBuilder> command_complete =
- packets::EventPacketBuilder::CreateCommandCompleteLeRand(hci::Status::SUCCESS, random_val);
- send_event_(command_complete->ToVector());
+
+ auto packet = bluetooth::hci::LeRandCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS, random_val);
+ send_event_(std::move(packet));
}
-void DualModeController::HciLeReadSupportedStates(packets::PacketView<true> args) {
- CHECK(args.size() == 0) << __func__ << " size=" << args.size();
- std::shared_ptr<packets::EventPacketBuilder> command_complete =
- packets::EventPacketBuilder::CreateCommandCompleteLeReadSupportedStates(hci::Status::SUCCESS,
- properties_.GetLeSupportedStates());
- send_event_(command_complete->ToVector());
+void DualModeController::HciLeReadSupportedStates(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size());
+ auto packet = bluetooth::hci::LeReadSupportedStatesCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+ properties_.GetLeSupportedStates());
+ send_event_(std::move(packet));
}
-void DualModeController::HciLeVendorCap(packets::PacketView<true> args) {
- CHECK(args.size() == 0) << __func__ << " size=" << args.size();
+void DualModeController::HciLeVendorCap(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size());
vector<uint8_t> caps = properties_.GetLeVendorCap();
if (caps.size() == 0) {
- SendCommandCompleteOnlyStatus(OpCode::LE_GET_VENDOR_CAPABILITIES, hci::Status::UNKNOWN_COMMAND);
+ SendCommandCompleteUnknownOpCodeEvent(static_cast<uint16_t>(
+ bluetooth::hci::OpCode::LE_GET_VENDOR_CAPABILITIES));
return;
}
- std::shared_ptr<packets::EventPacketBuilder> command_complete =
- packets::EventPacketBuilder::CreateCommandCompleteLeGetVendorCapabilities(hci::Status::SUCCESS,
- properties_.GetLeVendorCap());
- send_event_(command_complete->ToVector());
+ std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr =
+ std::make_unique<bluetooth::packet::RawBuilder>();
+ raw_builder_ptr->AddOctets1(
+ static_cast<uint8_t>(bluetooth::hci::ErrorCode::SUCCESS));
+ raw_builder_ptr->AddOctets(properties_.GetLeVendorCap());
+
+ auto packet = bluetooth::hci::CommandCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::OpCode::LE_GET_VENDOR_CAPABILITIES,
+ std::move(raw_builder_ptr));
+ send_event_(std::move(packet));
}
-void DualModeController::HciLeVendorMultiAdv(packets::PacketView<true> args) {
- CHECK(args.size() > 0);
- SendCommandCompleteOnlyStatus(OpCode::LE_MULTI_ADVT, hci::Status::UNKNOWN_COMMAND);
+void DualModeController::HciLeVendorMultiAdv(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT(args.size() > 0);
+ SendCommandCompleteUnknownOpCodeEvent(
+ static_cast<uint16_t>(bluetooth::hci::OpCode::LE_MULTI_ADVT));
}
-void DualModeController::HciLeAdvertisingFilter(packets::PacketView<true> args) {
- CHECK(args.size() > 0);
- SendCommandCompleteOnlyStatus(OpCode::LE_ADV_FILTER, hci::Status::UNKNOWN_COMMAND);
+void DualModeController::HciLeAdvertisingFilter(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT(args.size() > 0);
+ SendCommandCompleteUnknownOpCodeEvent(
+ static_cast<uint16_t>(bluetooth::hci::OpCode::LE_ADV_FILTER));
}
-void DualModeController::HciLeEnergyInfo(packets::PacketView<true> args) {
- CHECK(args.size() > 0);
- SendCommandCompleteOnlyStatus(OpCode::LE_ENERGY_INFO, hci::Status::UNKNOWN_COMMAND);
+void DualModeController::HciLeEnergyInfo(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT(args.size() > 0);
+ SendCommandCompleteUnknownOpCodeEvent(
+ static_cast<uint16_t>(bluetooth::hci::OpCode::LE_ENERGY_INFO));
}
-void DualModeController::HciLeExtendedScanParams(packets::PacketView<true> args) {
- CHECK(args.size() > 0);
- SendCommandCompleteOnlyStatus(OpCode::LE_EXTENDED_SCAN_PARAMS, hci::Status::UNKNOWN_COMMAND);
+void DualModeController::HciLeExtendedScanParams(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT(args.size() > 0);
+ SendCommandCompleteUnknownOpCodeEvent(
+ static_cast<uint16_t>(bluetooth::hci::OpCode::LE_EXTENDED_SCAN_PARAMS));
}
-void DualModeController::HciLeStartEncryption(packets::PacketView<true> args) {
- CHECK(args.size() == 28) << __func__ << " size=" << args.size();
+void DualModeController::HciLeStartEncryption(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 28, "%s size=%zu", __func__, args.size());
auto args_itr = args.begin();
uint16_t handle = args_itr.extract<uint16_t>();
@@ -1011,9 +1599,14 @@
// for (size_t i = 0; i < 16; i++) {
// long_term_key.push_back(args_itr.extract<uint18_t>();
// }
- SendCommandStatus(hci::Status::SUCCESS, OpCode::LE_START_ENCRYPTION);
+ auto status_packet = bluetooth::hci::LeStartEncryptionStatusBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, kNumCommandPackets);
+ send_event_(std::move(status_packet));
- send_event_(packets::EventPacketBuilder::CreateEncryptionChange(hci::Status::SUCCESS, handle, 0x01)->ToVector());
+ auto complete_packet = bluetooth::hci::EncryptionChangeBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, handle,
+ bluetooth::hci::EncryptionEnabled::OFF);
+ send_event_(std::move(complete_packet));
#if 0
std::shared_ptr<packets::AclPacketBuilder> encryption_information =
@@ -1068,26 +1661,38 @@
#endif
}
-void DualModeController::HciReadLoopbackMode(packets::PacketView<true> args) {
- CHECK(args.size() == 0) << __func__ << " size=" << args.size();
- send_event_(packets::EventPacketBuilder::CreateCommandCompleteReadLoopbackMode(hci::Status::SUCCESS, loopback_mode_)
- ->ToVector());
+void DualModeController::HciReadLoopbackMode(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 0, "%s size=%zu", __func__, args.size());
+ auto packet = bluetooth::hci::ReadLoopbackModeCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS,
+ static_cast<bluetooth::hci::LoopbackMode>(loopback_mode_));
+ send_event_(std::move(packet));
}
-void DualModeController::HciWriteLoopbackMode(packets::PacketView<true> args) {
- CHECK(args.size() == 1) << __func__ << " size=" << args.size();
- loopback_mode_ = static_cast<hci::LoopbackMode>(args[0]);
+void DualModeController::HciWriteLoopbackMode(
+ bluetooth::packet::PacketView<true> args) {
+ ASSERT_LOG(args.size() == 1, "%s size=%zu", __func__, args.size());
+ loopback_mode_ = static_cast<bluetooth::hci::LoopbackMode>(args[0]);
// ACL channel
uint16_t acl_handle = 0x123;
- send_event_(packets::EventPacketBuilder::CreateConnectionCompleteEvent(
- hci::Status::SUCCESS, acl_handle, properties_.GetAddress(), hci::LinkType::ACL, false)
- ->ToVector());
+ auto packet_acl = bluetooth::hci::ConnectionCompleteBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, acl_handle, properties_.GetAddress(),
+ bluetooth::hci::LinkType::ACL, bluetooth::hci::Enable::DISABLED);
+ send_event_(std::move(packet_acl));
// SCO channel
uint16_t sco_handle = 0x345;
- send_event_(packets::EventPacketBuilder::CreateConnectionCompleteEvent(
- hci::Status::SUCCESS, sco_handle, properties_.GetAddress(), hci::LinkType::SCO, false)
- ->ToVector());
- SendCommandCompleteSuccess(OpCode::WRITE_LOOPBACK_MODE);
+ auto packet_sco = bluetooth::hci::ConnectionCompleteBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, sco_handle, properties_.GetAddress(),
+ bluetooth::hci::LinkType::SCO, bluetooth::hci::Enable::DISABLED);
+ send_event_(std::move(packet_sco));
+ auto packet = bluetooth::hci::WriteLoopbackModeCompleteBuilder::Create(
+ kNumCommandPackets, bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
+}
+
+void DualModeController::SetAddress(Address address) {
+ properties_.SetAddress(address);
}
} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.h b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.h
index f33bbb8..d7c41e5 100644
--- a/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.h
+++ b/vendor_libs/test_vendor_lib/model/controller/dual_mode_controller.h
@@ -24,14 +24,17 @@
#include <vector>
#include "base/time/time.h"
+#include "hci/address.h"
+#include "hci/hci_packets.h"
#include "link_layer_controller.h"
#include "model/devices/device.h"
#include "model/setup/async_manager.h"
#include "security_manager.h"
-#include "types/address.h"
namespace test_vendor_lib {
+using ::bluetooth::hci::Address;
+
// Emulates a dual mode BR/EDR + LE controller by maintaining the link layer
// state machine detailed in the Bluetooth Core Specification Version 4.2,
// Volume 6, Part B, Section 1.1 (page 30). Provides methods corresponding to
@@ -60,17 +63,16 @@
virtual std::string GetTypeString() const override;
- virtual void IncomingPacket(packets::LinkLayerPacketView incoming) override;
+ virtual void IncomingPacket(
+ model::packets::LinkLayerPacketView incoming) override;
virtual void TimerTick() override;
- // Send packets to remote devices
- void SendLinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> to_send, Phy::Type phy_type);
-
// Route commands and data from the stack.
void HandleAcl(std::shared_ptr<std::vector<uint8_t>> acl_packet);
void HandleCommand(std::shared_ptr<std::vector<uint8_t>> command_packet);
void HandleSco(std::shared_ptr<std::vector<uint8_t>> sco_packet);
+ void HandleIso(std::shared_ptr<std::vector<uint8_t>> iso_packet);
// Set the callbacks for scheduling tasks.
void RegisterTaskScheduler(std::function<AsyncTaskId(std::chrono::milliseconds, const TaskCallback&)> evtScheduler);
@@ -82,12 +84,21 @@
void RegisterTaskCancel(std::function<void(AsyncTaskId)> cancel);
// Set the callbacks for sending packets to the HCI.
- void RegisterEventChannel(const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& send_event);
+ void RegisterEventChannel(
+ const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>&
+ send_event);
void RegisterAclChannel(const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& send_acl);
void RegisterScoChannel(const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& send_sco);
+ void RegisterIsoChannel(
+ const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>&
+ send_iso);
+
+ // Set the device's address.
+ void SetAddress(Address address) override;
+
// Controller commands. For error codes, see the Bluetooth Core Specification,
// Version 4.2, Volume 2, Part D (page 370).
@@ -95,261 +106,326 @@
// Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.1
// 7.1.1
- void HciInquiry(packets::PacketView<true> args);
+ void HciInquiry(bluetooth::packet::PacketView<true> args);
// 7.1.2
- void HciInquiryCancel(packets::PacketView<true> args);
+ void HciInquiryCancel(bluetooth::packet::PacketView<true> args);
// 7.1.5
- void HciCreateConnection(packets::PacketView<true> args);
+ void HciCreateConnection(bluetooth::packet::PacketView<true> args);
// 7.1.6
- void HciDisconnect(packets::PacketView<true> args);
+ void HciDisconnect(bluetooth::packet::PacketView<true> args);
// 7.1.8
- void HciAcceptConnectionRequest(packets::PacketView<true> args);
+ void HciAcceptConnectionRequest(bluetooth::packet::PacketView<true> args);
// 7.1.9
- void HciRejectConnectionRequest(packets::PacketView<true> args);
+ void HciRejectConnectionRequest(bluetooth::packet::PacketView<true> args);
// 7.1.10
- void HciLinkKeyRequestReply(packets::PacketView<true> args);
+ void HciLinkKeyRequestReply(bluetooth::packet::PacketView<true> args);
// 7.1.11
- void HciLinkKeyRequestNegativeReply(packets::PacketView<true> args);
+ void HciLinkKeyRequestNegativeReply(bluetooth::packet::PacketView<true> args);
// 7.1.14
- void HciChangeConnectionPacketType(packets::PacketView<true> args);
+ void HciChangeConnectionPacketType(bluetooth::packet::PacketView<true> args);
// 7.1.15
- void HciAuthenticationRequested(packets::PacketView<true> args);
+ void HciAuthenticationRequested(bluetooth::packet::PacketView<true> args);
// 7.1.16
- void HciSetConnectionEncryption(packets::PacketView<true> args);
+ void HciSetConnectionEncryption(bluetooth::packet::PacketView<true> args);
+
+ // 7.1.17
+ void HciChangeConnectionLinkKey(bluetooth::packet::PacketView<true> args);
+
+ // 7.1.18
+ void HciMasterLinkKey(bluetooth::packet::PacketView<true> args);
// 7.1.19
- void HciRemoteNameRequest(packets::PacketView<true> args);
+ void HciRemoteNameRequest(bluetooth::packet::PacketView<true> args);
+
+ // 7.2.8
+ void HciSwitchRole(bluetooth::packet::PacketView<true> args);
// 7.1.21
- void HciReadRemoteSupportedFeatures(packets::PacketView<true> args);
+ void HciReadRemoteSupportedFeatures(bluetooth::packet::PacketView<true> args);
// 7.1.22
- void HciReadRemoteExtendedFeatures(packets::PacketView<true> args);
+ void HciReadRemoteExtendedFeatures(bluetooth::packet::PacketView<true> args);
// 7.1.23
- void HciReadRemoteVersionInformation(packets::PacketView<true> args);
+ void HciReadRemoteVersionInformation(
+ bluetooth::packet::PacketView<true> args);
// 7.1.24
- void HciReadClockOffset(packets::PacketView<true> args);
+ void HciReadClockOffset(bluetooth::packet::PacketView<true> args);
// 7.1.29
- void HciIoCapabilityRequestReply(packets::PacketView<true> args);
+ void HciIoCapabilityRequestReply(bluetooth::packet::PacketView<true> args);
// 7.1.30
- void HciUserConfirmationRequestReply(packets::PacketView<true> args);
+ void HciUserConfirmationRequestReply(
+ bluetooth::packet::PacketView<true> args);
// 7.1.31
- void HciUserConfirmationRequestNegativeReply(packets::PacketView<true> args);
+ void HciUserConfirmationRequestNegativeReply(
+ bluetooth::packet::PacketView<true> args);
// 7.1.32
- void HciUserPasskeyRequestReply(packets::PacketView<true> args);
+ void HciUserPasskeyRequestReply(bluetooth::packet::PacketView<true> args);
// 7.1.33
- void HciUserPasskeyRequestNegativeReply(packets::PacketView<true> args);
+ void HciUserPasskeyRequestNegativeReply(
+ bluetooth::packet::PacketView<true> args);
// 7.1.34
- void HciRemoteOobDataRequestReply(packets::PacketView<true> args);
+ void HciRemoteOobDataRequestReply(bluetooth::packet::PacketView<true> args);
// 7.1.35
- void HciRemoteOobDataRequestNegativeReply(packets::PacketView<true> args);
+ void HciRemoteOobDataRequestNegativeReply(
+ bluetooth::packet::PacketView<true> args);
// 7.1.36
- void HciIoCapabilityRequestNegativeReply(packets::PacketView<true> args);
+ void HciIoCapabilityRequestNegativeReply(
+ bluetooth::packet::PacketView<true> args);
// Link Policy Commands
// Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.2
+ // 7.2.1
+ void HciHoldMode(bluetooth::packet::PacketView<true> args);
+
+ // 7.2.2
+ void HciSniffMode(bluetooth::packet::PacketView<true> args);
+
+ // 7.2.3
+ void HciExitSniffMode(bluetooth::packet::PacketView<true> args);
+
+ // 7.2.6
+ void HciQosSetup(bluetooth::packet::PacketView<true> args);
+
// 7.2.10
- void HciWriteLinkPolicySettings(packets::PacketView<true> args);
+ void HciWriteLinkPolicySettings(bluetooth::packet::PacketView<true> args);
// 7.2.12
- void HciWriteDefaultLinkPolicySettings(packets::PacketView<true> args);
+ void HciWriteDefaultLinkPolicySettings(
+ bluetooth::packet::PacketView<true> args);
+
+ // 7.2.13
+ void HciFlowSpecification(bluetooth::packet::PacketView<true> args);
// 7.2.14
- void HciSniffSubrating(packets::PacketView<true> args);
+ void HciSniffSubrating(bluetooth::packet::PacketView<true> args);
// Link Controller Commands
// Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.3
// 7.3.1
- void HciSetEventMask(packets::PacketView<true> args);
+ void HciSetEventMask(bluetooth::packet::PacketView<true> args);
// 7.3.2
- void HciReset(packets::PacketView<true> args);
+ void HciReset(bluetooth::packet::PacketView<true> args);
// 7.3.3
- void HciSetEventFilter(packets::PacketView<true> args);
+ void HciSetEventFilter(bluetooth::packet::PacketView<true> args);
// 7.3.10
- void HciDeleteStoredLinkKey(packets::PacketView<true> args);
+ void HciDeleteStoredLinkKey(bluetooth::packet::PacketView<true> args);
// 7.3.11
- void HciWriteLocalName(packets::PacketView<true> args);
+ void HciWriteLocalName(bluetooth::packet::PacketView<true> args);
// 7.3.12
- void HciReadLocalName(packets::PacketView<true> args);
+ void HciReadLocalName(bluetooth::packet::PacketView<true> args);
// 7.3.16
- void HciWritePageTimeout(packets::PacketView<true> args);
+ void HciWritePageTimeout(bluetooth::packet::PacketView<true> args);
// 7.3.18
- void HciWriteScanEnable(packets::PacketView<true> args);
+ void HciWriteScanEnable(bluetooth::packet::PacketView<true> args);
// 7.3.22
- void HciWriteInquiryScanActivity(packets::PacketView<true> args);
+ void HciWriteInquiryScanActivity(bluetooth::packet::PacketView<true> args);
// 7.3.23
- void HciReadAuthenticationEnable(packets::PacketView<true> args);
+ void HciReadAuthenticationEnable(bluetooth::packet::PacketView<true> args);
// 7.3.24
- void HciWriteAuthenticationEnable(packets::PacketView<true> args);
+ void HciWriteAuthenticationEnable(bluetooth::packet::PacketView<true> args);
// 7.3.26
- void HciWriteClassOfDevice(packets::PacketView<true> args);
+ void HciWriteClassOfDevice(bluetooth::packet::PacketView<true> args);
// 7.3.28
- void HciWriteVoiceSetting(packets::PacketView<true> args);
+ void HciWriteVoiceSetting(bluetooth::packet::PacketView<true> args);
// 7.3.39
- void HciHostBufferSize(packets::PacketView<true> args);
+ void HciHostBufferSize(bluetooth::packet::PacketView<true> args);
// 7.3.42
- void HciWriteLinkSupervisionTimeout(packets::PacketView<true> args);
+ void HciWriteLinkSupervisionTimeout(bluetooth::packet::PacketView<true> args);
// 7.3.45
- void HciWriteCurrentIacLap(packets::PacketView<true> args);
+ void HciWriteCurrentIacLap(bluetooth::packet::PacketView<true> args);
// 7.3.48
- void HciWriteInquiryScanType(packets::PacketView<true> args);
+ void HciWriteInquiryScanType(bluetooth::packet::PacketView<true> args);
// 7.3.50
- void HciWriteInquiryMode(packets::PacketView<true> args);
+ void HciWriteInquiryMode(bluetooth::packet::PacketView<true> args);
// 7.3.52
- void HciWritePageScanType(packets::PacketView<true> args);
+ void HciWritePageScanType(bluetooth::packet::PacketView<true> args);
// 7.3.56
- void HciWriteExtendedInquiryResponse(packets::PacketView<true> args);
+ void HciWriteExtendedInquiryResponse(
+ bluetooth::packet::PacketView<true> args);
+
+ // 7.3.57
+ void HciRefreshEncryptionKey(bluetooth::packet::PacketView<true> args);
// 7.3.59
- void HciWriteSimplePairingMode(packets::PacketView<true> args);
+ void HciWriteSimplePairingMode(bluetooth::packet::PacketView<true> args);
// 7.3.79
- void HciWriteLeHostSupport(packets::PacketView<true> args);
+ void HciWriteLeHostSupport(bluetooth::packet::PacketView<true> args);
+
+ // 7.3.92
+ void HciWriteSecureConnectionsHostSupport(
+ bluetooth::packet::PacketView<true> args);
// Informational Parameters Commands
// Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.4
// 7.4.5
- void HciReadBufferSize(packets::PacketView<true> args);
+ void HciReadBufferSize(bluetooth::packet::PacketView<true> args);
// 7.4.1
- void HciReadLocalVersionInformation(packets::PacketView<true> args);
+ void HciReadLocalVersionInformation(bluetooth::packet::PacketView<true> args);
// 7.4.6
- void HciReadBdAddr(packets::PacketView<true> args);
+ void HciReadBdAddr(bluetooth::packet::PacketView<true> args);
// 7.4.2
- void HciReadLocalSupportedCommands(packets::PacketView<true> args);
+ void HciReadLocalSupportedCommands(bluetooth::packet::PacketView<true> args);
+
+ // 7.4.3
+ void HciReadLocalSupportedFeatures(bluetooth::packet::PacketView<true> args);
// 7.4.4
- void HciReadLocalExtendedFeatures(packets::PacketView<true> args);
+ void HciReadLocalExtendedFeatures(bluetooth::packet::PacketView<true> args);
// 7.4.8
- void HciReadLocalSupportedCodecs(packets::PacketView<true> args);
+ void HciReadLocalSupportedCodecs(bluetooth::packet::PacketView<true> args);
// Status Parameters Commands
// Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.5
+ // 7.5.7
+ void HciReadEncryptionKeySize(bluetooth::packet::PacketView<true> args);
+
// Test Commands
// Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.7
// 7.7.1
- void HciReadLoopbackMode(packets::PacketView<true> args);
+ void HciReadLoopbackMode(bluetooth::packet::PacketView<true> args);
// 7.7.2
- void HciWriteLoopbackMode(packets::PacketView<true> args);
+ void HciWriteLoopbackMode(bluetooth::packet::PacketView<true> args);
// LE Controller Commands
// Bluetooth Core Specification Version 4.2 Volume 2 Part E 7.8
// 7.8.1
- void HciLeSetEventMask(packets::PacketView<true> args);
+ void HciLeSetEventMask(bluetooth::packet::PacketView<true> args);
// 7.8.2
- void HciLeReadBufferSize(packets::PacketView<true> args);
+ void HciLeReadBufferSize(bluetooth::packet::PacketView<true> args);
// 7.8.3
- void HciLeReadLocalSupportedFeatures(packets::PacketView<true> args);
+ void HciLeReadLocalSupportedFeatures(
+ bluetooth::packet::PacketView<true> args);
// 7.8.4
- void HciLeSetRandomAddress(packets::PacketView<true> args);
+ void HciLeSetRandomAddress(bluetooth::packet::PacketView<true> args);
// 7.8.5
- void HciLeSetAdvertisingParameters(packets::PacketView<true> args);
+ void HciLeSetAdvertisingParameters(bluetooth::packet::PacketView<true> args);
// 7.8.7
- void HciLeSetAdvertisingData(packets::PacketView<true> args);
+ void HciLeSetAdvertisingData(bluetooth::packet::PacketView<true> args);
+
+ // 7.8.8
+ void HciLeSetScanResponseData(bluetooth::packet::PacketView<true> args);
+
+ // 7.8.9
+ void HciLeSetAdvertisingEnable(bluetooth::packet::PacketView<true> args);
// 7.8.10
- void HciLeSetScanParameters(packets::PacketView<true> args);
+ void HciLeSetScanParameters(bluetooth::packet::PacketView<true> args);
// 7.8.11
- void HciLeSetScanEnable(packets::PacketView<true> args);
+ void HciLeSetScanEnable(bluetooth::packet::PacketView<true> args);
// 7.8.12
- void HciLeCreateConnection(packets::PacketView<true> args);
+ void HciLeCreateConnection(bluetooth::packet::PacketView<true> args);
// 7.8.18
- void HciLeConnectionUpdate(packets::PacketView<true> args);
+ void HciLeConnectionUpdate(bluetooth::packet::PacketView<true> args);
// 7.8.13
- void HciLeConnectionCancel(packets::PacketView<true> args);
+ void HciLeConnectionCancel(bluetooth::packet::PacketView<true> args);
// 7.8.14
- void HciLeReadWhiteListSize(packets::PacketView<true> args);
+ void HciLeReadWhiteListSize(bluetooth::packet::PacketView<true> args);
// 7.8.15
- void HciLeClearWhiteList(packets::PacketView<true> args);
+ void HciLeClearWhiteList(bluetooth::packet::PacketView<true> args);
// 7.8.16
- void HciLeAddDeviceToWhiteList(packets::PacketView<true> args);
+ void HciLeAddDeviceToWhiteList(bluetooth::packet::PacketView<true> args);
// 7.8.17
- void HciLeRemoveDeviceFromWhiteList(packets::PacketView<true> args);
+ void HciLeRemoveDeviceFromWhiteList(bluetooth::packet::PacketView<true> args);
// 7.8.21
- void HciLeReadRemoteFeatures(packets::PacketView<true> args);
+ void HciLeReadRemoteFeatures(bluetooth::packet::PacketView<true> args);
// 7.8.23
- void HciLeRand(packets::PacketView<true> args);
+ void HciLeRand(bluetooth::packet::PacketView<true> args);
// 7.8.24
- void HciLeStartEncryption(packets::PacketView<true> args);
+ void HciLeStartEncryption(bluetooth::packet::PacketView<true> args);
// 7.8.27
- void HciLeReadSupportedStates(packets::PacketView<true> args);
+ void HciLeReadSupportedStates(bluetooth::packet::PacketView<true> args);
+
+ // 7.8.38
+ void HciLeAddDeviceToResolvingList(bluetooth::packet::PacketView<true> args);
+
+ // 7.8.39
+ void HciLeRemoveDeviceFromResolvingList(
+ bluetooth::packet::PacketView<true> args);
+
+ // 7.8.40
+ void HciLeClearResolvingList(bluetooth::packet::PacketView<true> args);
+
+ // 7.8.77
+ void HciLeSetPrivacyMode(bluetooth::packet::PacketView<true> args);
// Vendor-specific Commands
- void HciLeVendorSleepMode(packets::PacketView<true> args);
- void HciLeVendorCap(packets::PacketView<true> args);
- void HciLeVendorMultiAdv(packets::PacketView<true> args);
- void HciLeVendor155(packets::PacketView<true> args);
- void HciLeVendor157(packets::PacketView<true> args);
- void HciLeEnergyInfo(packets::PacketView<true> args);
- void HciLeAdvertisingFilter(packets::PacketView<true> args);
- void HciLeExtendedScanParams(packets::PacketView<true> args);
+ void HciLeVendorSleepMode(bluetooth::packet::PacketView<true> args);
+ void HciLeVendorCap(bluetooth::packet::PacketView<true> args);
+ void HciLeVendorMultiAdv(bluetooth::packet::PacketView<true> args);
+ void HciLeVendor155(bluetooth::packet::PacketView<true> args);
+ void HciLeVendor157(bluetooth::packet::PacketView<true> args);
+ void HciLeEnergyInfo(bluetooth::packet::PacketView<true> args);
+ void HciLeAdvertisingFilter(bluetooth::packet::PacketView<true> args);
+ void HciLeExtendedScanParams(bluetooth::packet::PacketView<true> args);
void SetTimerPeriod(std::chrono::milliseconds new_period);
void StartTimer();
@@ -364,37 +440,24 @@
void AddConnectionAction(const TaskCallback& callback, uint16_t handle);
- // Creates a command complete event and sends it back to the HCI.
- void SendCommandComplete(hci::OpCode command_opcode, const std::vector<uint8_t>& return_parameters) const;
-
- // Sends a command complete event with no return parameters.
- void SendCommandCompleteSuccess(hci::OpCode command_opcode) const;
-
void SendCommandCompleteUnknownOpCodeEvent(uint16_t command_opcode) const;
- // Sends a command complete event with no return parameters.
- void SendCommandCompleteOnlyStatus(hci::OpCode command_opcode, hci::Status status) const;
-
- void SendCommandCompleteStatusAndAddress(hci::OpCode command_opcode, hci::Status status,
- const Address& address) const;
-
- // Creates a command status event and sends it back to the HCI.
- void SendCommandStatus(hci::Status status, hci::OpCode command_opcode) const;
-
- // Sends a command status event with default event parameters.
- void SendCommandStatusSuccess(hci::OpCode command_opcode) const;
-
// Callbacks to send packets back to the HCI.
- std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_acl_;
- std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_event_;
+ std::function<void(std::shared_ptr<bluetooth::hci::AclPacketBuilder>)>
+ send_acl_;
+ std::function<void(std::shared_ptr<bluetooth::hci::EventPacketBuilder>)>
+ send_event_;
std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_sco_;
+ std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_iso_;
// Maintains the commands to be registered and used in the HciHandler object.
// Keys are command opcodes and values are the callbacks to handle each
// command.
- std::unordered_map<uint16_t, std::function<void(packets::PacketView<true>)>> active_hci_commands_;
+ std::unordered_map<uint16_t,
+ std::function<void(bluetooth::packet::PacketView<true>)>>
+ active_hci_commands_;
- hci::LoopbackMode loopback_mode_;
+ bluetooth::hci::LoopbackMode loopback_mode_;
SecurityManager security_manager_;
diff --git a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc
index ba11436..d5f3ba7 100644
--- a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc
+++ b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.cc
@@ -14,36 +14,19 @@
* limitations under the License.
*/
-#define LOG_TAG "link_layer_controller"
-
#include "link_layer_controller.h"
-#include <base/logging.h>
-
-#include "hci.h"
-#include "osi/include/log.h"
-#include "packets/hci/acl_packet_builder.h"
-#include "packets/hci/command_packet_view.h"
-#include "packets/hci/event_packet_builder.h"
-#include "packets/hci/sco_packet_builder.h"
-#include "packets/link_layer/command_builder.h"
-#include "packets/link_layer/command_view.h"
-#include "packets/link_layer/disconnect_view.h"
-#include "packets/link_layer/encrypt_connection_view.h"
-#include "packets/link_layer/inquiry_response_view.h"
-#include "packets/link_layer/inquiry_view.h"
-#include "packets/link_layer/io_capability_view.h"
-#include "packets/link_layer/le_advertisement_view.h"
-#include "packets/link_layer/page_response_view.h"
-#include "packets/link_layer/page_view.h"
-#include "packets/link_layer/response_view.h"
+#include "include/le_advertisement.h"
+#include "os/log.h"
+#include "packet/raw_builder.h"
using std::vector;
using namespace std::chrono;
-using namespace test_vendor_lib::packets;
namespace test_vendor_lib {
+constexpr uint16_t kNumCommandPackets = 0x01;
+
// TODO: Model Rssi?
static uint8_t GetRssi() {
static uint8_t rssi = 0;
@@ -54,70 +37,130 @@
return -(rssi);
}
-void LinkLayerController::SendLELinkLayerPacket(std::shared_ptr<LinkLayerPacketBuilder> packet) {
- if (schedule_task_) {
- schedule_task_(milliseconds(50), [this, packet]() { send_to_remote_(packet, Phy::Type::LOW_ENERGY); });
- } else {
- send_to_remote_(packet, Phy::Type::LOW_ENERGY);
- }
+void LinkLayerController::SendLeLinkLayerPacket(
+ std::unique_ptr<model::packets::LinkLayerPacketBuilder> packet) {
+ std::shared_ptr<model::packets::LinkLayerPacketBuilder> shared_packet =
+ std::move(packet);
+ ScheduleTask(milliseconds(50), [this, shared_packet]() {
+ send_to_remote_(std::move(shared_packet), Phy::Type::LOW_ENERGY);
+ });
}
-void LinkLayerController::SendLinkLayerPacket(std::shared_ptr<LinkLayerPacketBuilder> packet) {
- if (schedule_task_) {
- schedule_task_(milliseconds(50), [this, packet]() { send_to_remote_(packet, Phy::Type::BR_EDR); });
- } else {
- send_to_remote_(packet, Phy::Type::BR_EDR);
- }
+void LinkLayerController::SendLinkLayerPacket(
+ std::unique_ptr<model::packets::LinkLayerPacketBuilder> packet) {
+ std::shared_ptr<model::packets::LinkLayerPacketBuilder> shared_packet =
+ std::move(packet);
+ ScheduleTask(milliseconds(50), [this, shared_packet]() {
+ send_to_remote_(std::move(shared_packet), Phy::Type::BR_EDR);
+ });
}
-hci::Status LinkLayerController::SendCommandToRemoteByAddress(hci::OpCode opcode, PacketView<true> args,
- const Address& remote, bool use_public_address) {
- std::shared_ptr<LinkLayerPacketBuilder> command;
- Address local_address;
- if (use_public_address) {
- local_address = properties_.GetAddress();
- } else {
- local_address = properties_.GetLeAddress();
+bluetooth::hci::ErrorCode LinkLayerController::SendCommandToRemoteByAddress(
+ bluetooth::hci::OpCode opcode, bluetooth::packet::PacketView<true> args,
+ const Address& remote) {
+ Address local_address = properties_.GetAddress();
+
+ switch (opcode) {
+ case (bluetooth::hci::OpCode::REMOTE_NAME_REQUEST):
+ // LMP features get requested with remote name requests.
+ SendLinkLayerPacket(model::packets::ReadRemoteLmpFeaturesBuilder::Create(
+ local_address, remote));
+ SendLinkLayerPacket(model::packets::RemoteNameRequestBuilder::Create(
+ local_address, remote));
+ break;
+ case (bluetooth::hci::OpCode::READ_REMOTE_SUPPORTED_FEATURES):
+ SendLinkLayerPacket(
+ model::packets::ReadRemoteSupportedFeaturesBuilder::Create(
+ local_address, remote));
+ break;
+ case (bluetooth::hci::OpCode::READ_REMOTE_EXTENDED_FEATURES): {
+ uint8_t page_number =
+ (args.begin() + 2).extract<uint8_t>(); // skip the handle
+ SendLinkLayerPacket(
+ model::packets::ReadRemoteExtendedFeaturesBuilder::Create(
+ local_address, remote, page_number));
+ } break;
+ case (bluetooth::hci::OpCode::READ_REMOTE_VERSION_INFORMATION):
+ SendLinkLayerPacket(
+ model::packets::ReadRemoteVersionInformationBuilder::Create(
+ local_address, remote));
+ break;
+ case (bluetooth::hci::OpCode::READ_CLOCK_OFFSET):
+ SendLinkLayerPacket(model::packets::ReadClockOffsetBuilder::Create(
+ local_address, remote));
+ break;
+ default:
+ LOG_INFO("Dropping unhandled command 0x%04x",
+ static_cast<uint16_t>(opcode));
+ return bluetooth::hci::ErrorCode::UNKNOWN_HCI_COMMAND;
}
- command = LinkLayerPacketBuilder::WrapCommand(CommandBuilder::Create(static_cast<uint16_t>(opcode), args),
- local_address, remote);
- SendLinkLayerPacket(std::move(command));
- return hci::Status::SUCCESS;
+
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
-hci::Status LinkLayerController::SendCommandToRemoteByHandle(hci::OpCode opcode, PacketView<true> args,
- uint16_t handle) {
+bluetooth::hci::ErrorCode LinkLayerController::SendCommandToRemoteByHandle(
+ bluetooth::hci::OpCode opcode, bluetooth::packet::PacketView<true> args,
+ uint16_t handle) {
// TODO: Handle LE connections
- bool use_public_address = true;
- if (!classic_connections_.HasHandle(handle)) {
- return hci::Status::UNKNOWN_CONNECTION;
+ if (!connections_.HasHandle(handle)) {
+ return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
}
- return SendCommandToRemoteByAddress(opcode, args, classic_connections_.GetAddress(handle), use_public_address);
+ return SendCommandToRemoteByAddress(opcode, args,
+ connections_.GetAddress(handle));
}
-hci::Status LinkLayerController::SendAclToRemote(AclPacketView acl_packet) {
- // TODO: Handle LE connections
+bluetooth::hci::ErrorCode LinkLayerController::SendAclToRemote(
+ bluetooth::hci::AclPacketView acl_packet) {
uint16_t handle = acl_packet.GetHandle();
- if (!classic_connections_.HasHandle(handle)) {
- return hci::Status::UNKNOWN_CONNECTION;
+ if (!connections_.HasHandle(handle)) {
+ return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
}
- std::unique_ptr<ViewForwarderBuilder> acl_builder = ViewForwarderBuilder::Create(acl_packet);
+ Address my_address = properties_.GetAddress();
+ Address destination = connections_.GetAddress(handle);
+ if (connections_.GetOwnAddressType(handle) != 0) { // If it's not public, it must be LE
+ my_address = properties_.GetLeAddress();
+ }
- std::shared_ptr<LinkLayerPacketBuilder> acl = LinkLayerPacketBuilder::WrapAcl(
- std::move(acl_builder), properties_.GetAddress(), classic_connections_.GetAddress(handle));
-
- LOG_INFO(LOG_TAG, "%s(%s): handle 0x%x size %d", __func__, properties_.GetAddress().ToString().c_str(), handle,
+ LOG_INFO("%s(%s): handle 0x%x size %d", __func__, properties_.GetAddress().ToString().c_str(), handle,
static_cast<int>(acl_packet.size()));
- schedule_task_(milliseconds(5), [this, handle]() {
- send_event_(EventPacketBuilder::CreateNumberOfCompletedPacketsEvent(handle, 1)->ToVector());
+ ScheduleTask(milliseconds(5), [this, handle]() {
+ std::vector<bluetooth::hci::CompletedPackets> completed_packets;
+ bluetooth::hci::CompletedPackets cp;
+ cp.connection_handle_ = handle;
+ cp.host_num_of_completed_packets_ = kNumCommandPackets;
+ completed_packets.push_back(cp);
+ auto packet = bluetooth::hci::NumberOfCompletedPacketsBuilder::Create(
+ completed_packets);
+ send_event_(std::move(packet));
});
- SendLinkLayerPacket(acl);
- return hci::Status::SUCCESS;
+
+ auto acl_payload = acl_packet.GetPayload();
+
+ std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr =
+ std::make_unique<bluetooth::packet::RawBuilder>();
+ std::vector<uint8_t> payload_bytes(acl_payload.begin(), acl_payload.end());
+
+ uint16_t first_two_bytes =
+ static_cast<uint16_t>(acl_packet.GetHandle()) +
+ (static_cast<uint16_t>(acl_packet.GetPacketBoundaryFlag()) << 12) +
+ (static_cast<uint16_t>(acl_packet.GetBroadcastFlag()) << 14);
+ raw_builder_ptr->AddOctets2(first_two_bytes);
+ raw_builder_ptr->AddOctets2(static_cast<uint16_t>(payload_bytes.size()));
+ raw_builder_ptr->AddOctets(payload_bytes);
+
+ auto acl = model::packets::AclPacketBuilder::Create(
+ my_address, destination, std::move(raw_builder_ptr));
+
+ SendLinkLayerPacket(std::move(acl));
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
-void LinkLayerController::IncomingPacket(LinkLayerPacketView incoming) {
+void LinkLayerController::IncomingPacket(
+ model::packets::LinkLayerPacketView incoming) {
+ ASSERT(incoming.IsValid());
+
// TODO: Resolvable private addresses?
if (incoming.GetDestinationAddress() != properties_.GetAddress() &&
incoming.GetDestinationAddress() != properties_.GetLeAddress() &&
@@ -127,279 +170,480 @@
}
switch (incoming.GetType()) {
- case Link::PacketType::ACL:
+ case model::packets::PacketType::ACL:
IncomingAclPacket(incoming);
break;
- case Link::PacketType::COMMAND:
- IncomingCommandPacket(incoming);
- break;
- case Link::PacketType::DISCONNECT:
+ case model::packets::PacketType::DISCONNECT:
IncomingDisconnectPacket(incoming);
break;
- case Link::PacketType::ENCRYPT_CONNECTION:
+ case model::packets::PacketType::ENCRYPT_CONNECTION:
IncomingEncryptConnection(incoming);
break;
- case Link::PacketType::ENCRYPT_CONNECTION_RESPONSE:
+ case model::packets::PacketType::ENCRYPT_CONNECTION_RESPONSE:
IncomingEncryptConnectionResponse(incoming);
break;
- case Link::PacketType::INQUIRY:
+ case model::packets::PacketType::INQUIRY:
if (inquiry_scans_enabled_) {
IncomingInquiryPacket(incoming);
}
break;
- case Link::PacketType::INQUIRY_RESPONSE:
+ case model::packets::PacketType::INQUIRY_RESPONSE:
IncomingInquiryResponsePacket(incoming);
break;
- case Link::PacketType::IO_CAPABILITY_REQUEST:
+ case model::packets::PacketType::IO_CAPABILITY_REQUEST:
IncomingIoCapabilityRequestPacket(incoming);
break;
- case Link::PacketType::IO_CAPABILITY_RESPONSE:
+ case model::packets::PacketType::IO_CAPABILITY_RESPONSE:
IncomingIoCapabilityResponsePacket(incoming);
break;
- case Link::PacketType::IO_CAPABILITY_NEGATIVE_RESPONSE:
+ case model::packets::PacketType::IO_CAPABILITY_NEGATIVE_RESPONSE:
IncomingIoCapabilityNegativeResponsePacket(incoming);
break;
- case Link::PacketType::LE_ADVERTISEMENT:
+ case model::packets::PacketType::LE_ADVERTISEMENT:
if (le_scan_enable_ || le_connect_) {
IncomingLeAdvertisementPacket(incoming);
}
break;
- case Link::PacketType::LE_SCAN:
+ case model::packets::PacketType::LE_CONNECT:
+ IncomingLeConnectPacket(incoming);
+ break;
+ case model::packets::PacketType::LE_CONNECT_COMPLETE:
+ IncomingLeConnectCompletePacket(incoming);
+ break;
+ case model::packets::PacketType::LE_SCAN:
// TODO: Check Advertising flags and see if we are scannable.
IncomingLeScanPacket(incoming);
break;
- case Link::PacketType::LE_SCAN_RESPONSE:
+ case model::packets::PacketType::LE_SCAN_RESPONSE:
if (le_scan_enable_ && le_scan_type_ == 1) {
IncomingLeScanResponsePacket(incoming);
}
break;
- case Link::PacketType::PAGE:
+ case model::packets::PacketType::PAGE:
if (page_scans_enabled_) {
IncomingPagePacket(incoming);
}
break;
- case Link::PacketType::PAGE_RESPONSE:
+ case model::packets::PacketType::PAGE_RESPONSE:
IncomingPageResponsePacket(incoming);
break;
- case Link::PacketType::RESPONSE:
- IncomingResponsePacket(incoming);
+ case model::packets::PacketType::PAGE_REJECT:
+ IncomingPageRejectPacket(incoming);
+ break;
+ case (model::packets::PacketType::REMOTE_NAME_REQUEST):
+ IncomingRemoteNameRequest(incoming);
+ break;
+ case (model::packets::PacketType::REMOTE_NAME_REQUEST_RESPONSE):
+ IncomingRemoteNameRequestResponse(incoming);
+ break;
+ case (model::packets::PacketType::READ_REMOTE_SUPPORTED_FEATURES):
+ IncomingReadRemoteSupportedFeatures(incoming);
+ break;
+ case (model::packets::PacketType::READ_REMOTE_SUPPORTED_FEATURES_RESPONSE):
+ IncomingReadRemoteSupportedFeaturesResponse(incoming);
+ break;
+ case (model::packets::PacketType::READ_REMOTE_LMP_FEATURES):
+ IncomingReadRemoteLmpFeatures(incoming);
+ break;
+ case (model::packets::PacketType::READ_REMOTE_LMP_FEATURES_RESPONSE):
+ IncomingReadRemoteLmpFeaturesResponse(incoming);
+ break;
+ case (model::packets::PacketType::READ_REMOTE_EXTENDED_FEATURES):
+ IncomingReadRemoteExtendedFeatures(incoming);
+ break;
+ case (model::packets::PacketType::READ_REMOTE_EXTENDED_FEATURES_RESPONSE):
+ IncomingReadRemoteExtendedFeaturesResponse(incoming);
+ break;
+ case (model::packets::PacketType::READ_REMOTE_VERSION_INFORMATION):
+ IncomingReadRemoteVersion(incoming);
+ break;
+ case (model::packets::PacketType::READ_REMOTE_VERSION_INFORMATION_RESPONSE):
+ IncomingReadRemoteVersionResponse(incoming);
+ break;
+ case (model::packets::PacketType::READ_CLOCK_OFFSET):
+ IncomingReadClockOffset(incoming);
+ break;
+ case (model::packets::PacketType::READ_CLOCK_OFFSET_RESPONSE):
+ IncomingReadClockOffsetResponse(incoming);
break;
default:
- LOG_WARN(LOG_TAG, "Dropping unhandled packet of type %d", static_cast<int32_t>(incoming.GetType()));
+ LOG_WARN("Dropping unhandled packet of type %s",
+ model::packets::PacketTypeText(incoming.GetType()).c_str());
}
}
-void LinkLayerController::IncomingAclPacket(LinkLayerPacketView incoming) {
- LOG_INFO(LOG_TAG, "Acl Packet %s -> %s", incoming.GetSourceAddress().ToString().c_str(),
+void LinkLayerController::IncomingAclPacket(
+ model::packets::LinkLayerPacketView incoming) {
+ LOG_INFO("Acl Packet %s -> %s", incoming.GetSourceAddress().ToString().c_str(),
incoming.GetDestinationAddress().ToString().c_str());
- AclPacketView acl_view = AclPacketView::Create(incoming.GetPayload());
- LOG_INFO(LOG_TAG, "%s: remote handle 0x%x size %d", __func__, acl_view.GetHandle(),
- static_cast<int>(acl_view.size()));
- uint16_t local_handle = classic_connections_.GetHandle(incoming.GetSourceAddress());
- LOG_INFO(LOG_TAG, "%s: local handle 0x%x", __func__, local_handle);
- acl::PacketBoundaryFlagsType boundary_flags = acl_view.GetPacketBoundaryFlags();
- acl::BroadcastFlagsType broadcast_flags = acl_view.GetBroadcastFlags();
- std::unique_ptr<ViewForwarderBuilder> builder = ViewForwarderBuilder::Create(acl_view.GetPayload());
- std::unique_ptr<AclPacketBuilder> local_acl =
- AclPacketBuilder::Create(local_handle, boundary_flags, broadcast_flags, std::move(builder));
- send_acl_(local_acl->ToVector());
+ auto acl = model::packets::AclPacketView::Create(incoming);
+ ASSERT(acl.IsValid());
+ auto payload = acl.GetPayload();
+ std::shared_ptr<std::vector<uint8_t>> payload_bytes =
+ std::make_shared<std::vector<uint8_t>>(payload.begin(), payload.end());
+
+ bluetooth::hci::PacketView<bluetooth::hci::kLittleEndian> raw_packet(
+ payload_bytes);
+ auto acl_view = bluetooth::hci::AclPacketView::Create(raw_packet);
+ ASSERT(acl_view.IsValid());
+
+ LOG_INFO("%s: remote handle 0x%x size %d", __func__, acl_view.GetHandle(), static_cast<int>(acl_view.size()));
+ uint16_t local_handle = connections_.GetHandle(incoming.GetSourceAddress());
+ LOG_INFO("%s: local handle 0x%x", __func__, local_handle);
+
+ std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr =
+ std::make_unique<bluetooth::packet::RawBuilder>();
+ std::vector<uint8_t> payload_data(acl_view.GetPayload().begin(),
+ acl_view.GetPayload().end());
+ raw_builder_ptr->AddOctets(payload_data);
+
+ auto acl_packet = bluetooth::hci::AclPacketBuilder::Create(
+ local_handle, acl_view.GetPacketBoundaryFlag(),
+ acl_view.GetBroadcastFlag(), std::move(raw_builder_ptr));
+
+ send_acl_(std::move(acl_packet));
}
-void LinkLayerController::IncomingCommandPacket(LinkLayerPacketView incoming) {
- // TODO: Check the destination address to see if this packet is for me.
- CommandView command = CommandView::GetCommand(incoming);
- hci::OpCode opcode = static_cast<hci::OpCode>(command.GetOpcode());
- auto args = command.GetData();
- std::vector<uint64_t> response_data;
+void LinkLayerController::IncomingRemoteNameRequest(
+ model::packets::LinkLayerPacketView packet) {
+ auto view = model::packets::RemoteNameRequestView::Create(packet);
+ ASSERT(view.IsValid());
- switch (opcode) {
- case (hci::OpCode::REMOTE_NAME_REQUEST): {
- std::vector<uint8_t> name = properties_.GetName();
- LOG_INFO(LOG_TAG, "Remote Name (Local Name) %d", static_cast<int>(name.size()));
- response_data.push_back(static_cast<uint8_t>(hci::Status::SUCCESS));
- response_data.push_back(name.size());
- uint64_t word = 0;
- for (size_t i = 0; i < name.size(); i++) {
- if (i > 0 && (i % 8 == 0)) {
- response_data.push_back(word);
- word = 0;
- }
- word |= static_cast<uint64_t>(name[i]) << (8 * (i % 8));
- }
- response_data.push_back(word);
- } break;
- case (hci::OpCode::READ_REMOTE_SUPPORTED_FEATURES):
- LOG_INFO(LOG_TAG, "(%s) Remote Supported Features Requested by: %s %x",
- incoming.GetDestinationAddress().ToString().c_str(), incoming.GetSourceAddress().ToString().c_str(),
- static_cast<int>(properties_.GetSupportedFeatures()));
- response_data.push_back(static_cast<uint8_t>(hci::Status::SUCCESS));
- response_data.push_back(properties_.GetSupportedFeatures());
- break;
- case (hci::OpCode::READ_REMOTE_EXTENDED_FEATURES): {
- uint8_t page_number = (args + 2).extract<uint8_t>(); // skip the handle
- LOG_INFO(LOG_TAG, "(%s) Remote Extended Features %d Requested by: %s",
- incoming.GetDestinationAddress().ToString().c_str(), page_number,
- incoming.GetSourceAddress().ToString().c_str());
- uint8_t max_page_number = properties_.GetExtendedFeaturesMaximumPageNumber();
- if (page_number > max_page_number) {
- response_data.push_back(static_cast<uint8_t>(hci::Status::INVALID_HCI_COMMAND_PARAMETERS));
- response_data.push_back(page_number);
- response_data.push_back(max_page_number);
- response_data.push_back(0);
- } else {
- response_data.push_back(static_cast<uint8_t>(hci::Status::SUCCESS));
- response_data.push_back(page_number);
- response_data.push_back(max_page_number);
- response_data.push_back(properties_.GetExtendedFeatures(page_number));
- }
- } break;
- case (hci::OpCode::READ_REMOTE_VERSION_INFORMATION):
- response_data.push_back(static_cast<uint8_t>(hci::Status::SUCCESS));
- response_data.push_back(properties_.GetLmpPalVersion());
- response_data.push_back(properties_.GetManufacturerName());
- response_data.push_back(properties_.GetLmpPalSubversion());
- break;
- case (hci::OpCode::READ_CLOCK_OFFSET):
- response_data.push_back(static_cast<uint8_t>(hci::Status::SUCCESS));
- response_data.push_back(properties_.GetClockOffset());
- break;
- default:
- LOG_INFO(LOG_TAG, "Dropping unhandled command 0x%04x", static_cast<uint16_t>(opcode));
- return;
+ SendLinkLayerPacket(model::packets::RemoteNameRequestResponseBuilder::Create(
+ packet.GetDestinationAddress(), packet.GetSourceAddress(),
+ properties_.GetName()));
+}
+
+void LinkLayerController::IncomingRemoteNameRequestResponse(
+ model::packets::LinkLayerPacketView packet) {
+ auto view = model::packets::RemoteNameRequestResponseView::Create(packet);
+ ASSERT(view.IsValid());
+
+ send_event_(bluetooth::hci::RemoteNameRequestCompleteBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, packet.GetSourceAddress(),
+ view.GetName()));
+}
+
+void LinkLayerController::IncomingReadRemoteLmpFeatures(
+ model::packets::LinkLayerPacketView packet) {
+ SendLinkLayerPacket(
+ model::packets::ReadRemoteLmpFeaturesResponseBuilder::Create(
+ packet.GetDestinationAddress(), packet.GetSourceAddress(),
+ properties_.GetExtendedFeatures(1)));
+}
+
+void LinkLayerController::IncomingReadRemoteLmpFeaturesResponse(
+ model::packets::LinkLayerPacketView packet) {
+ auto view = model::packets::ReadRemoteLmpFeaturesResponseView::Create(packet);
+ ASSERT(view.IsValid());
+ send_event_(
+ bluetooth::hci::RemoteHostSupportedFeaturesNotificationBuilder::Create(
+ packet.GetSourceAddress(), view.GetFeatures()));
+}
+
+void LinkLayerController::IncomingReadRemoteSupportedFeatures(
+ model::packets::LinkLayerPacketView packet) {
+ SendLinkLayerPacket(
+ model::packets::ReadRemoteSupportedFeaturesResponseBuilder::Create(
+ packet.GetDestinationAddress(), packet.GetSourceAddress(),
+ properties_.GetSupportedFeatures()));
+}
+
+void LinkLayerController::IncomingReadRemoteSupportedFeaturesResponse(
+ model::packets::LinkLayerPacketView packet) {
+ auto view =
+ model::packets::ReadRemoteSupportedFeaturesResponseView::Create(packet);
+ ASSERT(view.IsValid());
+ Address source = packet.GetSourceAddress();
+ if (connections_.IsDeviceConnected(source)) {
+ uint16_t handle = connections_.GetHandle(source);
+ send_event_(
+ bluetooth::hci::ReadRemoteSupportedFeaturesCompleteBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, handle, view.GetFeatures()));
+ } else {
+ LOG_INFO("Discarding response from a disconnected device %s",
+ source.ToString().c_str());
+ }
+}
+
+void LinkLayerController::IncomingReadRemoteExtendedFeatures(
+ model::packets::LinkLayerPacketView packet) {
+ auto view = model::packets::ReadRemoteExtendedFeaturesView::Create(packet);
+ ASSERT(view.IsValid());
+ uint8_t page_number = view.GetPageNumber();
+ uint8_t error_code = static_cast<uint8_t>(bluetooth::hci::ErrorCode::SUCCESS);
+ if (page_number > properties_.GetExtendedFeaturesMaximumPageNumber()) {
+ error_code = static_cast<uint8_t>(
+ bluetooth::hci::ErrorCode::INVALID_LMP_OR_LL_PARAMETERS);
}
SendLinkLayerPacket(
- LinkLayerPacketBuilder::WrapResponse(ResponseBuilder::Create(static_cast<uint16_t>(opcode), response_data),
- properties_.GetAddress(), incoming.GetSourceAddress()));
+ model::packets::ReadRemoteExtendedFeaturesResponseBuilder::Create(
+ packet.GetDestinationAddress(), packet.GetSourceAddress(), error_code,
+ page_number, properties_.GetExtendedFeaturesMaximumPageNumber(),
+ properties_.GetExtendedFeatures(view.GetPageNumber())));
}
-void LinkLayerController::IncomingDisconnectPacket(LinkLayerPacketView incoming) {
- LOG_INFO(LOG_TAG, "Disconnect Packet");
- DisconnectView disconnect = DisconnectView::GetDisconnect(incoming);
+void LinkLayerController::IncomingReadRemoteExtendedFeaturesResponse(
+ model::packets::LinkLayerPacketView packet) {
+ auto view =
+ model::packets::ReadRemoteExtendedFeaturesResponseView::Create(packet);
+ ASSERT(view.IsValid());
+ Address source = packet.GetSourceAddress();
+ if (connections_.IsDeviceConnected(source)) {
+ uint16_t handle = connections_.GetHandle(packet.GetSourceAddress());
+ send_event_(
+ bluetooth::hci::ReadRemoteExtendedFeaturesCompleteBuilder::Create(
+ static_cast<bluetooth::hci::ErrorCode>(view.GetStatus()), handle,
+ view.GetPageNumber(), view.GetMaxPageNumber(), view.GetFeatures()));
+ } else {
+ LOG_INFO("Discarding response from a disconnected device %s",
+ source.ToString().c_str());
+ }
+}
+
+void LinkLayerController::IncomingReadRemoteVersion(
+ model::packets::LinkLayerPacketView packet) {
+ SendLinkLayerPacket(
+ model::packets::ReadRemoteSupportedFeaturesResponseBuilder::Create(
+ packet.GetDestinationAddress(), packet.GetSourceAddress(),
+ properties_.GetSupportedFeatures()));
+}
+
+void LinkLayerController::IncomingReadRemoteVersionResponse(
+ model::packets::LinkLayerPacketView packet) {
+ auto view =
+ model::packets::ReadRemoteVersionInformationResponseView::Create(packet);
+ ASSERT(view.IsValid());
+ Address source = packet.GetSourceAddress();
+ if (connections_.IsDeviceConnected(source)) {
+ uint16_t handle = connections_.GetHandle(packet.GetSourceAddress());
+ send_event_(
+ bluetooth::hci::ReadRemoteVersionInformationCompleteBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, handle, view.GetLmpVersion(),
+ view.GetManufacturerName(), view.GetLmpSubversion()));
+ } else {
+ LOG_INFO("Discarding response from a disconnected device %s",
+ source.ToString().c_str());
+ }
+}
+
+void LinkLayerController::IncomingReadClockOffset(
+ model::packets::LinkLayerPacketView packet) {
+ SendLinkLayerPacket(model::packets::ReadClockOffsetResponseBuilder::Create(
+ packet.GetDestinationAddress(), packet.GetSourceAddress(),
+ properties_.GetClockOffset()));
+}
+
+void LinkLayerController::IncomingReadClockOffsetResponse(
+ model::packets::LinkLayerPacketView packet) {
+ auto view = model::packets::ReadClockOffsetResponseView::Create(packet);
+ ASSERT(view.IsValid());
+ Address source = packet.GetSourceAddress();
+ if (connections_.IsDeviceConnected(source)) {
+ uint16_t handle = connections_.GetHandle(packet.GetSourceAddress());
+ send_event_(bluetooth::hci::ReadClockOffsetCompleteBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, handle, view.GetOffset()));
+ } else {
+ LOG_INFO("Discarding response from a disconnected device %s",
+ source.ToString().c_str());
+ }
+}
+
+void LinkLayerController::IncomingDisconnectPacket(
+ model::packets::LinkLayerPacketView incoming) {
+ LOG_INFO("Disconnect Packet");
+ auto disconnect = model::packets::DisconnectView::Create(incoming);
+ ASSERT(disconnect.IsValid());
+
Address peer = incoming.GetSourceAddress();
- uint16_t handle = classic_connections_.GetHandle(peer);
+ uint16_t handle = connections_.GetHandle(peer);
if (handle == acl::kReservedHandle) {
- LOG_INFO(LOG_TAG, "%s: Unknown connection @%s", __func__, peer.ToString().c_str());
+ LOG_INFO("%s: Unknown connection @%s", __func__, peer.ToString().c_str());
return;
}
- CHECK(classic_connections_.Disconnect(handle)) << "GetHandle() returned invalid handle " << handle;
+ ASSERT_LOG(connections_.Disconnect(handle), "GetHandle() returned invalid handle %hx", handle);
uint8_t reason = disconnect.GetReason();
- schedule_task_(milliseconds(20), [this, handle, reason]() { DisconnectCleanup(handle, reason); });
+ ScheduleTask(milliseconds(20), [this, handle, reason]() { DisconnectCleanup(handle, reason); });
}
-void LinkLayerController::IncomingEncryptConnection(LinkLayerPacketView incoming) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+void LinkLayerController::IncomingEncryptConnection(
+ model::packets::LinkLayerPacketView incoming) {
+ LOG_INFO("%s", __func__);
+
// TODO: Check keys
Address peer = incoming.GetSourceAddress();
- uint16_t handle = classic_connections_.GetHandle(peer);
+ uint16_t handle = connections_.GetHandle(peer);
if (handle == acl::kReservedHandle) {
- LOG_INFO(LOG_TAG, "%s: Unknown connection @%s", __func__, peer.ToString().c_str());
+ LOG_INFO("%s: Unknown connection @%s", __func__, peer.ToString().c_str());
return;
}
- send_event_(EventPacketBuilder::CreateEncryptionChange(hci::Status::SUCCESS, handle, 1)->ToVector());
- SendLinkLayerPacket(LinkLayerPacketBuilder::WrapEncryptConnectionResponse(
- EncryptConnectionBuilder::Create(security_manager_.GetKey(peer)), properties_.GetAddress(), peer));
+ send_event_(bluetooth::hci::EncryptionChangeBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, handle,
+ bluetooth::hci::EncryptionEnabled::ON));
+
+ uint16_t count = security_manager_.ReadKey(peer);
+ if (count == 0) {
+ LOG_ERROR("NO KEY HERE for %s", peer.ToString().c_str());
+ return;
+ }
+ auto array = security_manager_.GetKey(peer);
+ std::vector<uint8_t> key_vec{array.begin(), array.end()};
+ auto response = model::packets::EncryptConnectionResponseBuilder::Create(
+ properties_.GetAddress(), peer, key_vec);
+ SendLinkLayerPacket(std::move(response));
}
-void LinkLayerController::IncomingEncryptConnectionResponse(LinkLayerPacketView incoming) {
- LOG_INFO(LOG_TAG, "%s", __func__);
+void LinkLayerController::IncomingEncryptConnectionResponse(
+ model::packets::LinkLayerPacketView incoming) {
+ LOG_INFO("%s", __func__);
// TODO: Check keys
- uint16_t handle = classic_connections_.GetHandle(incoming.GetSourceAddress());
+ uint16_t handle = connections_.GetHandle(incoming.GetSourceAddress());
if (handle == acl::kReservedHandle) {
- LOG_INFO(LOG_TAG, "%s: Unknown connection @%s", __func__, incoming.GetSourceAddress().ToString().c_str());
+ LOG_INFO("%s: Unknown connection @%s", __func__, incoming.GetSourceAddress().ToString().c_str());
return;
}
- send_event_(EventPacketBuilder::CreateEncryptionChange(hci::Status::SUCCESS, handle, 1)->ToVector());
+ auto packet = bluetooth::hci::EncryptionChangeBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, handle,
+ bluetooth::hci::EncryptionEnabled::ON);
+ send_event_(std::move(packet));
}
-void LinkLayerController::IncomingInquiryPacket(LinkLayerPacketView incoming) {
- InquiryView inquiry = InquiryView::GetInquiry(incoming);
- std::unique_ptr<InquiryResponseBuilder> inquiry_response;
- switch (inquiry.GetType()) {
- case (Inquiry::InquiryType::STANDARD):
- inquiry_response = InquiryResponseBuilder::CreateStandard(
- properties_.GetPageScanRepetitionMode(), properties_.GetClassOfDevice(), properties_.GetClockOffset());
- break;
+void LinkLayerController::IncomingInquiryPacket(
+ model::packets::LinkLayerPacketView incoming) {
+ auto inquiry = model::packets::InquiryView::Create(incoming);
+ ASSERT(inquiry.IsValid());
- case (Inquiry::InquiryType::RSSI):
- inquiry_response =
- InquiryResponseBuilder::CreateRssi(properties_.GetPageScanRepetitionMode(), properties_.GetClassOfDevice(),
- properties_.GetClockOffset(), GetRssi());
- break;
+ Address peer = incoming.GetSourceAddress();
- case (Inquiry::InquiryType::EXTENDED):
- inquiry_response = InquiryResponseBuilder::CreateExtended(
- properties_.GetPageScanRepetitionMode(), properties_.GetClassOfDevice(), properties_.GetClockOffset(),
- GetRssi(), properties_.GetExtendedInquiryData());
- break;
+ switch (inquiry.GetInquiryType()) {
+ case (model::packets::InquiryType::STANDARD): {
+ auto inquiry_response = model::packets::InquiryResponseBuilder::Create(
+ properties_.GetAddress(), peer,
+ properties_.GetPageScanRepetitionMode(),
+ properties_.GetClassOfDevice(), properties_.GetClockOffset());
+ SendLinkLayerPacket(std::move(inquiry_response));
+ } break;
+ case (model::packets::InquiryType::RSSI): {
+ auto inquiry_response =
+ model::packets::InquiryResponseWithRssiBuilder::Create(
+ properties_.GetAddress(), peer,
+ properties_.GetPageScanRepetitionMode(),
+ properties_.GetClassOfDevice(), properties_.GetClockOffset(),
+ GetRssi());
+ SendLinkLayerPacket(std::move(inquiry_response));
+ } break;
+ case (model::packets::InquiryType::EXTENDED): {
+ auto inquiry_response =
+ model::packets::ExtendedInquiryResponseBuilder::Create(
+ properties_.GetAddress(), peer,
+ properties_.GetPageScanRepetitionMode(),
+ properties_.GetClassOfDevice(), properties_.GetClockOffset(),
+ GetRssi(), properties_.GetExtendedInquiryData());
+ SendLinkLayerPacket(std::move(inquiry_response));
+
+ } break;
default:
- LOG_WARN(LOG_TAG, "Unhandled Incoming Inquiry of type %d", static_cast<int>(inquiry.GetType()));
+ LOG_WARN("Unhandled Incoming Inquiry of type %d", static_cast<int>(inquiry.GetType()));
return;
}
- SendLinkLayerPacket(LinkLayerPacketBuilder::WrapInquiryResponse(std::move(inquiry_response), properties_.GetAddress(),
- incoming.GetSourceAddress()));
- // TODO: Send an Inquriy Response Notification Event 7.7.74
+ // TODO: Send an Inquiry Response Notification Event 7.7.74
}
-void LinkLayerController::IncomingInquiryResponsePacket(LinkLayerPacketView incoming) {
- InquiryResponseView inquiry_response = InquiryResponseView::GetInquiryResponse(incoming);
+void LinkLayerController::IncomingInquiryResponsePacket(
+ model::packets::LinkLayerPacketView incoming) {
+ auto basic_inquiry_response =
+ model::packets::BasicInquiryResponseView::Create(incoming);
+ ASSERT(basic_inquiry_response.IsValid());
std::vector<uint8_t> eir;
- switch (inquiry_response.GetType()) {
- case (Inquiry::InquiryType::STANDARD): {
- LOG_WARN(LOG_TAG, "Incoming Standard Inquiry Response");
+ switch (basic_inquiry_response.GetInquiryType()) {
+ case (model::packets::InquiryType::STANDARD): {
// TODO: Support multiple inquiries in the same packet.
- std::unique_ptr<EventPacketBuilder> inquiry_result = EventPacketBuilder::CreateInquiryResultEvent();
- bool result_added =
- inquiry_result->AddInquiryResult(incoming.GetSourceAddress(), inquiry_response.GetPageScanRepetitionMode(),
- inquiry_response.GetClassOfDevice(), inquiry_response.GetClockOffset());
- CHECK(result_added);
- send_event_(inquiry_result->ToVector());
+ auto inquiry_response =
+ model::packets::InquiryResponseView::Create(basic_inquiry_response);
+ ASSERT(inquiry_response.IsValid());
+
+ auto page_scan_repetition_mode =
+ (bluetooth::hci::PageScanRepetitionMode)
+ inquiry_response.GetPageScanRepetitionMode();
+
+ auto packet = bluetooth::hci::InquiryResultBuilder::Create(
+ 0x01, inquiry_response.GetSourceAddress(), page_scan_repetition_mode,
+ inquiry_response.GetClassOfDevice(),
+ inquiry_response.GetClockOffset());
+
+ send_event_(std::move(packet));
} break;
- case (Inquiry::InquiryType::RSSI):
- LOG_WARN(LOG_TAG, "Incoming RSSI Inquiry Response");
- send_event_(EventPacketBuilder::CreateExtendedInquiryResultEvent(
- incoming.GetSourceAddress(), inquiry_response.GetPageScanRepetitionMode(),
- inquiry_response.GetClassOfDevice(), inquiry_response.GetClockOffset(), GetRssi(), eir)
- ->ToVector());
- break;
+ case (model::packets::InquiryType::RSSI): {
+ auto inquiry_response =
+ model::packets::InquiryResponseWithRssiView::Create(
+ basic_inquiry_response);
+ ASSERT(inquiry_response.IsValid());
- case (Inquiry::InquiryType::EXTENDED): {
- LOG_WARN(LOG_TAG, "Incoming Extended Inquiry Response");
- auto eir_itr = inquiry_response.GetExtendedData();
- size_t eir_bytes = eir_itr.NumBytesRemaining();
- LOG_WARN(LOG_TAG, "Payload size = %d", static_cast<int>(eir_bytes));
- for (size_t i = 0; i < eir_bytes; i++) {
- eir.push_back(eir_itr.extract<uint8_t>());
+ auto page_scan_repetition_mode =
+ (bluetooth::hci::PageScanRepetitionMode)
+ inquiry_response.GetPageScanRepetitionMode();
+
+ auto packet = bluetooth::hci::InquiryResultWithRssiBuilder::Create(
+ 0x01, inquiry_response.GetSourceAddress(), page_scan_repetition_mode,
+ inquiry_response.GetClassOfDevice(),
+ inquiry_response.GetClockOffset(), inquiry_response.GetRssi());
+ send_event_(std::move(packet));
+ } break;
+
+ case (model::packets::InquiryType::EXTENDED): {
+ auto inquiry_response =
+ model::packets::ExtendedInquiryResponseView::Create(
+ basic_inquiry_response);
+ ASSERT(inquiry_response.IsValid());
+
+ std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr =
+ std::make_unique<bluetooth::packet::RawBuilder>();
+ raw_builder_ptr->AddOctets1(kNumCommandPackets);
+ raw_builder_ptr->AddAddress(inquiry_response.GetSourceAddress());
+ raw_builder_ptr->AddOctets1(inquiry_response.GetPageScanRepetitionMode());
+ raw_builder_ptr->AddOctets1(0x00); // _reserved_
+ auto class_of_device = inquiry_response.GetClassOfDevice();
+ for (unsigned int i = 0; i < class_of_device.kLength; i++) {
+ raw_builder_ptr->AddOctets1(class_of_device.cod[i]);
}
- send_event_(EventPacketBuilder::CreateExtendedInquiryResultEvent(
- incoming.GetSourceAddress(), inquiry_response.GetPageScanRepetitionMode(),
- inquiry_response.GetClassOfDevice(), inquiry_response.GetClockOffset(), GetRssi(), eir)
- ->ToVector());
+ raw_builder_ptr->AddOctets2(inquiry_response.GetClockOffset());
+ raw_builder_ptr->AddOctets1(inquiry_response.GetRssi());
+ raw_builder_ptr->AddOctets(inquiry_response.GetExtendedData());
+
+ auto packet = bluetooth::hci::EventPacketBuilder::Create(
+ bluetooth::hci::EventCode::EXTENDED_INQUIRY_RESULT,
+ std::move(raw_builder_ptr));
+ send_event_(std::move(packet));
} break;
default:
- LOG_WARN(LOG_TAG, "Unhandled Incoming Inquiry Response of type %d", static_cast<int>(inquiry_response.GetType()));
+ LOG_WARN("Unhandled Incoming Inquiry Response of type %d",
+ static_cast<int>(basic_inquiry_response.GetInquiryType()));
}
}
-void LinkLayerController::IncomingIoCapabilityRequestPacket(LinkLayerPacketView incoming) {
- LOG_DEBUG(LOG_TAG, "%s", __func__);
+void LinkLayerController::IncomingIoCapabilityRequestPacket(
+ model::packets::LinkLayerPacketView incoming) {
+ LOG_DEBUG("%s", __func__);
if (!simple_pairing_mode_enabled_) {
- LOG_WARN(LOG_TAG, "%s: Only simple pairing mode is implemented", __func__);
+ LOG_WARN("%s: Only simple pairing mode is implemented", __func__);
return;
}
- auto request = IoCapabilityView::GetIoCapability(incoming);
- Address peer = incoming.GetSourceAddress();
+ auto request = model::packets::IoCapabilityRequestView::Create(incoming);
+ ASSERT(request.IsValid());
+
+ Address peer = incoming.GetSourceAddress();
uint8_t io_capability = request.GetIoCapability();
uint8_t oob_data_present = request.GetOobDataPresent();
uint8_t authentication_requirements = request.GetAuthenticationRequirements();
- uint16_t handle = classic_connections_.GetHandle(peer);
+ uint16_t handle = connections_.GetHandle(peer);
if (handle == acl::kReservedHandle) {
- LOG_INFO(LOG_TAG, "%s: Device not connected %s", __func__, peer.ToString().c_str());
+ LOG_INFO("%s: Device not connected %s", __func__, peer.ToString().c_str());
return;
}
@@ -407,251 +651,324 @@
security_manager_.SetPeerIoCapability(peer, io_capability, oob_data_present, authentication_requirements);
- send_event_(EventPacketBuilder::CreateIoCapabilityResponseEvent(peer, io_capability, oob_data_present,
- authentication_requirements)
- ->ToVector());
+ auto packet = bluetooth::hci::IoCapabilityResponseBuilder::Create(
+ peer, static_cast<bluetooth::hci::IoCapability>(io_capability),
+ static_cast<bluetooth::hci::OobDataPresent>(oob_data_present),
+ static_cast<bluetooth::hci::AuthenticationRequirements>(
+ authentication_requirements));
+ send_event_(std::move(packet));
StartSimplePairing(peer);
}
-void LinkLayerController::IncomingIoCapabilityResponsePacket(LinkLayerPacketView incoming) {
- LOG_DEBUG(LOG_TAG, "%s", __func__);
- auto response = IoCapabilityView::GetIoCapability(incoming);
+void LinkLayerController::IncomingIoCapabilityResponsePacket(
+ model::packets::LinkLayerPacketView incoming) {
+ LOG_DEBUG("%s", __func__);
+
+ auto response = model::packets::IoCapabilityResponseView::Create(incoming);
+ ASSERT(response.IsValid());
+
Address peer = incoming.GetSourceAddress();
uint8_t io_capability = response.GetIoCapability();
uint8_t oob_data_present = response.GetOobDataPresent();
uint8_t authentication_requirements = response.GetAuthenticationRequirements();
- security_manager_.SetPeerIoCapability(peer, io_capability, oob_data_present, authentication_requirements);
+ security_manager_.SetPeerIoCapability(peer, io_capability, oob_data_present,
+ authentication_requirements);
- send_event_(EventPacketBuilder::CreateIoCapabilityResponseEvent(peer, io_capability, oob_data_present,
- authentication_requirements)
- ->ToVector());
+ auto packet = bluetooth::hci::IoCapabilityResponseBuilder::Create(
+ peer, static_cast<bluetooth::hci::IoCapability>(io_capability),
+ static_cast<bluetooth::hci::OobDataPresent>(oob_data_present),
+ static_cast<bluetooth::hci::AuthenticationRequirements>(
+ authentication_requirements));
+ send_event_(std::move(packet));
PairingType pairing_type = security_manager_.GetSimplePairingType();
if (pairing_type != PairingType::INVALID) {
- schedule_task_(milliseconds(5), [this, peer, pairing_type]() { AuthenticateRemoteStage1(peer, pairing_type); });
+ ScheduleTask(milliseconds(5), [this, peer, pairing_type]() {
+ AuthenticateRemoteStage1(peer, pairing_type);
+ });
} else {
- LOG_INFO(LOG_TAG, "%s: Security Manager returned INVALID", __func__);
+ LOG_INFO("%s: Security Manager returned INVALID", __func__);
}
}
-void LinkLayerController::IncomingIoCapabilityNegativeResponsePacket(LinkLayerPacketView incoming) {
- LOG_DEBUG(LOG_TAG, "%s", __func__);
+void LinkLayerController::IncomingIoCapabilityNegativeResponsePacket(
+ model::packets::LinkLayerPacketView incoming) {
+ LOG_DEBUG("%s", __func__);
Address peer = incoming.GetSourceAddress();
- CHECK(security_manager_.GetAuthenticationAddress() == peer);
+ ASSERT(security_manager_.GetAuthenticationAddress() == peer);
security_manager_.InvalidateIoCapabilities();
}
-void LinkLayerController::IncomingLeAdvertisementPacket(LinkLayerPacketView incoming) {
+void LinkLayerController::IncomingLeAdvertisementPacket(
+ model::packets::LinkLayerPacketView incoming) {
// TODO: Handle multiple advertisements per packet.
- LeAdvertisementView advertisement = LeAdvertisementView::GetLeAdvertisementView(incoming);
- LeAdvertisement::AdvertisementType adv_type = advertisement.GetAdvertisementType();
- LeAdvertisement::AddressType addr_type = advertisement.GetAddressType();
+ Address address = incoming.GetSourceAddress();
+ auto advertisement = model::packets::LeAdvertisementView::Create(incoming);
+ ASSERT(advertisement.IsValid());
+ auto adv_type = static_cast<LeAdvertisement::AdvertisementType>(
+ advertisement.GetAdvertisementType());
+ auto address_type =
+ static_cast<LeAdvertisement::AddressType>(advertisement.GetAddressType());
if (le_scan_enable_) {
- vector<uint8_t> ad;
- auto itr = advertisement.GetData();
- size_t ad_size = itr.NumBytesRemaining();
- for (size_t i = 0; i < ad_size; i++) {
- ad.push_back(itr.extract<uint8_t>());
- }
- std::unique_ptr<EventPacketBuilder> le_adverts = EventPacketBuilder::CreateLeAdvertisingReportEvent();
+ vector<uint8_t> ad = advertisement.GetData();
- if (!le_adverts->AddLeAdvertisingReport(adv_type, addr_type, incoming.GetSourceAddress(), ad, GetRssi())) {
- LOG_INFO(LOG_TAG, "Couldn't add the advertising report.");
- } else {
- send_event_(le_adverts->ToVector());
- }
+ std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr =
+ std::make_unique<bluetooth::packet::RawBuilder>();
+ raw_builder_ptr->AddOctets1(
+ static_cast<uint8_t>(bluetooth::hci::SubeventCode::ADVERTISING_REPORT));
+ raw_builder_ptr->AddOctets1(0x01); // num reports
+ raw_builder_ptr->AddOctets1(static_cast<uint8_t>(adv_type));
+ raw_builder_ptr->AddOctets1(static_cast<uint8_t>(address_type));
+ raw_builder_ptr->AddAddress(address);
+ raw_builder_ptr->AddOctets1(ad.size());
+ raw_builder_ptr->AddOctets(ad);
+ raw_builder_ptr->AddOctets1(GetRssi());
+ auto packet = bluetooth::hci::EventPacketBuilder::Create(
+ bluetooth::hci::EventCode::LE_META_EVENT, std::move(raw_builder_ptr));
+ send_event_(std::move(packet));
}
-#if 0
- // Connect
- if (le_connect_ && (adv_type == BTM_BLE_CONNECT_EVT ||
- adv_type == BTM_BLE_CONNECT_DIR_EVT)) {
- LOG_INFO(LOG_TAG, "Connecting to device %d", static_cast<int>(dev));
- if (le_peer_address_ == addr && le_peer_address_type_ == addr_type &&
- remote_devices_[dev]->LeConnect()) {
- uint16_t handle = LeGetHandle();
- send_event_(EventPacketBuilder::CreateLeConnectionCompleteEvent(
- hci::Status::SUCCESS, handle, HCI_ROLE_MASTER, addr_type, addr, 1,
- 2, 3)->ToVector());
-
- // TODO: LeGetConnInterval(), LeGetConnLatency(),
- // LeGetSupervisionTimeout()));
- le_connect_ = false;
-
- std::shared_ptr<Connection> new_connection =
- std::make_shared<Connection>(remote_devices_[dev], handle);
- /*
- connections_.push_back(new_connection);
-
- remote_devices_[dev]->SetConnection(new_connection);
- */
- }
-
- if (LeWhiteListContainsDevice(addr, addr_type) &&
- remote_devices_[dev]->LeConnect()) {
- LOG_INFO(LOG_TAG, "White List Connecting to device %d",
- static_cast<int>(dev));
- uint16_t handle = LeGetHandle();
- send_event_(EventPacketBuilder::CreateLeConnectionCompleteEvent(
- hci::Status::SUCCESS, handle, HCI_ROLE_MASTER, addr_type, addr, 1,
- 2, 3)->ToVector());
- // TODO: LeGetConnInterval(), LeGetConnLatency(),
- // LeGetSupervisionTimeout()));
- le_connect_ = false;
-
- std::shared_ptr<Connection> new_connection =
- std::make_shared<Connection>(remote_devices_[dev], handle);
- /*
- connections_.push_back(new_connection);
- remote_devices_[dev]->SetConnection(new_connection);
- */
- }
- }
-#endif
-
// Active scanning
if (le_scan_enable_ && le_scan_type_ == 1) {
- std::shared_ptr<LinkLayerPacketBuilder> to_send =
- LinkLayerPacketBuilder::WrapLeScan(properties_.GetLeAddress(), incoming.GetSourceAddress());
- SendLELinkLayerPacket(to_send);
+ auto to_send = model::packets::LeScanBuilder::Create(
+ properties_.GetLeAddress(), address);
+ SendLeLinkLayerPacket(std::move(to_send));
+ }
+
+ // Connect
+ if ((le_connect_ && le_peer_address_ == address && le_peer_address_type_ == static_cast<uint8_t>(address_type) &&
+ (adv_type == LeAdvertisement::AdvertisementType::ADV_IND ||
+ adv_type == LeAdvertisement::AdvertisementType::ADV_DIRECT_IND)) ||
+ (LeWhiteListContainsDevice(address, static_cast<uint8_t>(address_type)))) {
+ if (!connections_.CreatePendingLeConnection(incoming.GetSourceAddress(), static_cast<uint8_t>(address_type))) {
+ LOG_WARN("%s: CreatePendingLeConnection failed for connection to %s (type %hhx)", __func__,
+ incoming.GetSourceAddress().ToString().c_str(), address_type);
+ }
+ LOG_INFO("%s: connecting to %s (type %hhx)", __func__, incoming.GetSourceAddress().ToString().c_str(),
+ address_type);
+ le_connect_ = false;
+ le_scan_enable_ = false;
+
+ auto to_send = model::packets::LeConnectBuilder::Create(
+ properties_.GetLeAddress(), incoming.GetSourceAddress(),
+ le_connection_interval_min_, le_connection_interval_max_,
+ le_connection_latency_, le_connection_supervision_timeout_,
+ static_cast<uint8_t>(le_address_type_));
+
+ SendLeLinkLayerPacket(std::move(to_send));
}
}
-void LinkLayerController::IncomingLeScanPacket(LinkLayerPacketView incoming) {
- LOG_INFO(LOG_TAG, "LE Scan Packet");
- std::unique_ptr<LeAdvertisementBuilder> response = LeAdvertisementBuilder::Create(
- static_cast<LeAdvertisement::AddressType>(properties_.GetLeAddressType()),
- static_cast<LeAdvertisement::AdvertisementType>(properties_.GetLeAdvertisementType()),
- properties_.GetLeScanResponse());
- std::shared_ptr<LinkLayerPacketBuilder> to_send = LinkLayerPacketBuilder::WrapLeScanResponse(
- std::move(response), properties_.GetLeAddress(), incoming.GetSourceAddress());
- SendLELinkLayerPacket(to_send);
-}
-
-void LinkLayerController::IncomingLeScanResponsePacket(LinkLayerPacketView incoming) {
- LeAdvertisementView scan_response = LeAdvertisementView::GetLeAdvertisementView(incoming);
- vector<uint8_t> ad;
- auto itr = scan_response.GetData();
- size_t scan_size = itr.NumBytesRemaining();
- for (size_t i = 0; i < scan_size; i++) {
- ad.push_back(itr.extract<uint8_t>());
- }
-
- std::unique_ptr<EventPacketBuilder> le_adverts = EventPacketBuilder::CreateLeAdvertisingReportEvent();
-
- if (!le_adverts->AddLeAdvertisingReport(scan_response.GetAdvertisementType(), scan_response.GetAddressType(),
- incoming.GetSourceAddress(), ad, GetRssi())) {
- LOG_INFO(LOG_TAG, "Couldn't add the scan response.");
- } else {
- LOG_INFO(LOG_TAG, "Sending scan response");
- send_event_(le_adverts->ToVector());
- }
-}
-
-void LinkLayerController::IncomingPagePacket(LinkLayerPacketView incoming) {
- PageView page = PageView::GetPage(incoming);
- LOG_INFO(LOG_TAG, "%s from %s", __func__, incoming.GetSourceAddress().ToString().c_str());
-
- if (!classic_connections_.CreatePendingConnection(incoming.GetSourceAddress())) {
- // Send a response to indicate that we're busy, or drop the packet?
- LOG_WARN(LOG_TAG, "%s: Failed to create a pending connection", __func__);
- }
-
- send_event_(EventPacketBuilder::CreateConnectionRequestEvent(incoming.GetSourceAddress(), page.GetClassOfDevice(),
- hci::LinkType::ACL)
- ->ToVector());
-}
-
-void LinkLayerController::IncomingPageResponsePacket(LinkLayerPacketView incoming) {
- LOG_INFO(LOG_TAG, "%s: %s", __func__, incoming.GetSourceAddress().ToString().c_str());
- uint16_t handle = classic_connections_.CreateConnection(incoming.GetSourceAddress());
+void LinkLayerController::HandleLeConnection(Address address, uint8_t address_type, uint8_t own_address_type,
+ uint8_t role, uint16_t connection_interval, uint16_t connection_latency,
+ uint16_t supervision_timeout) {
+ // TODO: Choose between LeConnectionComplete and LeEnhancedConnectionComplete
+ uint16_t handle = connections_.CreateLeConnection(address, address_type, own_address_type);
if (handle == acl::kReservedHandle) {
- LOG_WARN(LOG_TAG, "%s: No free handles", __func__);
+ LOG_WARN("%s: No pending connection for connection from %s (type %hhx)", __func__, address.ToString().c_str(),
+ address_type);
return;
}
- LOG_INFO(LOG_TAG, "%s: Sending CreateConnectionComplete", __func__);
- send_event_(EventPacketBuilder::CreateConnectionCompleteEvent(hci::Status::SUCCESS, handle,
- incoming.GetSourceAddress(), hci::LinkType::ACL, false)
- ->ToVector());
+ auto packet = bluetooth::hci::LeConnectionCompleteBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, handle,
+ static_cast<bluetooth::hci::Role>(role),
+ static_cast<bluetooth::hci::AddressType>(address_type), address,
+ connection_interval, connection_latency, supervision_timeout,
+ static_cast<bluetooth::hci::MasterClockAccuracy>(0x00));
+ send_event_(std::move(packet));
}
-void LinkLayerController::IncomingResponsePacket(LinkLayerPacketView incoming) {
- ResponseView response = ResponseView::GetResponse(incoming);
+void LinkLayerController::IncomingLeConnectPacket(
+ model::packets::LinkLayerPacketView incoming) {
+ auto connect = model::packets::LeConnectView::Create(incoming);
+ ASSERT(connect.IsValid());
+ uint16_t connection_interval = (connect.GetLeConnectionIntervalMax() + connect.GetLeConnectionIntervalMin()) / 2;
+ if (!connections_.CreatePendingLeConnection(incoming.GetSourceAddress(),
+ static_cast<uint8_t>(connect.GetAddressType()))) {
+ LOG_WARN("%s: CreatePendingLeConnection failed for connection from %s (type %hhx)", __func__,
+ incoming.GetSourceAddress().ToString().c_str(), connect.GetAddressType());
+ return;
+ }
+ HandleLeConnection(
+ incoming.GetSourceAddress(),
+ static_cast<uint8_t>(connect.GetAddressType()),
+ static_cast<uint8_t>(properties_.GetLeAdvertisingOwnAddressType()),
+ static_cast<uint8_t>(bluetooth::hci::Role::SLAVE), connection_interval,
+ connect.GetLeConnectionLatency(),
+ connect.GetLeConnectionSupervisionTimeout());
- // TODO: Check to see if I'm expecting this response.
+ auto to_send = model::packets::LeConnectCompleteBuilder::Create(
+ incoming.GetDestinationAddress(), incoming.GetSourceAddress(),
+ connection_interval, connect.GetLeConnectionLatency(),
+ connect.GetLeConnectionSupervisionTimeout(),
+ properties_.GetLeAdvertisingOwnAddressType());
+ SendLeLinkLayerPacket(std::move(to_send));
+}
- hci::OpCode opcode = static_cast<hci::OpCode>(response.GetOpcode());
- auto args = response.GetResponseData();
- hci::Status status = static_cast<hci::Status>(args.extract<uint64_t>());
+void LinkLayerController::IncomingLeConnectCompletePacket(
+ model::packets::LinkLayerPacketView incoming) {
+ auto complete = model::packets::LeConnectCompleteView::Create(incoming);
+ ASSERT(complete.IsValid());
+ HandleLeConnection(incoming.GetSourceAddress(),
+ static_cast<uint8_t>(complete.GetAddressType()),
+ static_cast<uint8_t>(le_address_type_),
+ static_cast<uint8_t>(bluetooth::hci::Role::MASTER),
+ complete.GetLeConnectionInterval(),
+ complete.GetLeConnectionLatency(),
+ complete.GetLeConnectionSupervisionTimeout());
+}
- uint16_t handle = classic_connections_.GetHandle(incoming.GetSourceAddress());
+void LinkLayerController::IncomingLeScanPacket(
+ model::packets::LinkLayerPacketView incoming) {
+ LOG_INFO("LE Scan Packet");
- switch (opcode) {
- case (hci::OpCode::REMOTE_NAME_REQUEST): {
- std::string remote_name = "";
- size_t length = args.extract<uint64_t>();
- uint64_t word = 0;
- for (size_t b = 0; b < length; b++) {
- size_t byte = b % 8;
- if (byte == 0) {
- word = args.extract<uint64_t>();
- }
- remote_name += static_cast<uint8_t>(word >> (byte * 8));
- }
- send_event_(
- EventPacketBuilder::CreateRemoteNameRequestCompleteEvent(status, incoming.GetSourceAddress(), remote_name)
- ->ToVector());
- } break;
- case (hci::OpCode::READ_REMOTE_SUPPORTED_FEATURES): {
- send_event_(
- EventPacketBuilder::CreateRemoteSupportedFeaturesEvent(status, handle, args.extract<uint64_t>())->ToVector());
- } break;
- case (hci::OpCode::READ_REMOTE_EXTENDED_FEATURES): {
- if (status == hci::Status::SUCCESS) {
- send_event_(EventPacketBuilder::CreateReadRemoteExtendedFeaturesEvent(
- status, handle, args.extract<uint64_t>(), args.extract<uint64_t>(), args.extract<uint64_t>())
- ->ToVector());
- } else {
- send_event_(EventPacketBuilder::CreateReadRemoteExtendedFeaturesEvent(status, handle, 0, 0, 0)->ToVector());
- }
- } break;
- case (hci::OpCode::READ_REMOTE_VERSION_INFORMATION): {
- send_event_(EventPacketBuilder::CreateReadRemoteVersionInformationEvent(
- status, handle, args.extract<uint64_t>(), args.extract<uint64_t>(), args.extract<uint64_t>())
- ->ToVector());
- LOG_INFO(LOG_TAG, "Read remote version handle 0x%04x", handle);
- } break;
- case (hci::OpCode::READ_CLOCK_OFFSET): {
- send_event_(EventPacketBuilder::CreateReadClockOffsetEvent(status, handle, args.extract<uint64_t>())->ToVector());
- } break;
- default:
- LOG_INFO(LOG_TAG, "Unhandled response to command 0x%04x", static_cast<uint16_t>(opcode));
+ auto to_send = model::packets::LeScanResponseBuilder::Create(
+ properties_.GetLeAddress(), incoming.GetSourceAddress(),
+ static_cast<model::packets::AddressType>(properties_.GetLeAddressType()),
+ static_cast<model::packets::AdvertisementType>(
+ properties_.GetLeAdvertisementType()),
+ properties_.GetLeScanResponse());
+
+ SendLeLinkLayerPacket(std::move(to_send));
+}
+
+void LinkLayerController::IncomingLeScanResponsePacket(
+ model::packets::LinkLayerPacketView incoming) {
+ auto scan_response = model::packets::LeScanResponseView::Create(incoming);
+ ASSERT(scan_response.IsValid());
+ vector<uint8_t> ad = scan_response.GetData();
+ auto adv_type = static_cast<LeAdvertisement::AdvertisementType>(
+ scan_response.GetAdvertisementType());
+ auto address_type =
+ static_cast<LeAdvertisement::AddressType>(scan_response.GetAddressType());
+
+ std::unique_ptr<bluetooth::packet::RawBuilder> raw_builder_ptr =
+ std::make_unique<bluetooth::packet::RawBuilder>();
+ raw_builder_ptr->AddOctets1(
+ static_cast<uint8_t>(bluetooth::hci::SubeventCode::ADVERTISING_REPORT));
+ raw_builder_ptr->AddOctets1(0x01); // num reports
+ raw_builder_ptr->AddOctets1(static_cast<uint8_t>(adv_type));
+ raw_builder_ptr->AddOctets1(static_cast<uint8_t>(address_type));
+ raw_builder_ptr->AddAddress(incoming.GetSourceAddress());
+ raw_builder_ptr->AddOctets1(ad.size());
+ raw_builder_ptr->AddOctets(ad);
+ raw_builder_ptr->AddOctets1(GetRssi());
+ auto packet = bluetooth::hci::EventPacketBuilder::Create(
+ bluetooth::hci::EventCode::LE_META_EVENT, std::move(raw_builder_ptr));
+ send_event_(std::move(packet));
+}
+
+void LinkLayerController::IncomingPagePacket(
+ model::packets::LinkLayerPacketView incoming) {
+ auto page = model::packets::PageView::Create(incoming);
+ ASSERT(page.IsValid());
+ LOG_INFO("%s from %s", __func__, incoming.GetSourceAddress().ToString().c_str());
+
+ if (!connections_.CreatePendingConnection(
+ incoming.GetSourceAddress(), properties_.GetAuthenticationEnable())) {
+ // Send a response to indicate that we're busy, or drop the packet?
+ LOG_WARN("%s: Failed to create a pending connection for %s", __func__,
+ incoming.GetSourceAddress().ToString().c_str());
+ }
+
+ bluetooth::hci::Address source_address;
+ bluetooth::hci::Address::FromString(page.GetSourceAddress().ToString(),
+ source_address);
+
+ auto packet = bluetooth::hci::ConnectionRequestBuilder::Create(
+ source_address, page.GetClassOfDevice(),
+ bluetooth::hci::ConnectionRequestLinkType::ACL);
+
+ send_event_(std::move(packet));
+}
+
+void LinkLayerController::IncomingPageRejectPacket(
+ model::packets::LinkLayerPacketView incoming) {
+ LOG_INFO("%s: %s", __func__, incoming.GetSourceAddress().ToString().c_str());
+ auto reject = model::packets::PageRejectView::Create(incoming);
+ ASSERT(reject.IsValid());
+ LOG_INFO("%s: Sending CreateConnectionComplete", __func__);
+ auto packet = bluetooth::hci::ConnectionCompleteBuilder::Create(
+ static_cast<bluetooth::hci::ErrorCode>(reject.GetReason()), 0x0eff,
+ incoming.GetSourceAddress(), bluetooth::hci::LinkType::ACL,
+ bluetooth::hci::Enable::DISABLED);
+ send_event_(std::move(packet));
+}
+
+void LinkLayerController::IncomingPageResponsePacket(
+ model::packets::LinkLayerPacketView incoming) {
+ Address peer = incoming.GetSourceAddress();
+ LOG_INFO("%s: %s", __func__, peer.ToString().c_str());
+ bool awaiting_authentication = connections_.AuthenticatePendingConnection();
+ uint16_t handle = connections_.CreateConnection(peer);
+ if (handle == acl::kReservedHandle) {
+ LOG_WARN("%s: No free handles", __func__);
+ return;
+ }
+ auto packet = bluetooth::hci::ConnectionCompleteBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, handle, incoming.GetSourceAddress(),
+ bluetooth::hci::LinkType::ACL, bluetooth::hci::Enable::DISABLED);
+ send_event_(std::move(packet));
+
+ if (awaiting_authentication) {
+ ScheduleTask(milliseconds(5), [this, peer, handle]() {
+ HandleAuthenticationRequest(peer, handle);
+ });
}
}
void LinkLayerController::TimerTick() {
if (inquiry_state_ == Inquiry::InquiryState::INQUIRY) Inquiry();
if (inquiry_state_ == Inquiry::InquiryState::INQUIRY) PageScan();
+ LeAdvertising();
Connections();
}
+void LinkLayerController::LeAdvertising() {
+ if (!le_advertising_enable_) {
+ return;
+ }
+ steady_clock::time_point now = steady_clock::now();
+ if (duration_cast<milliseconds>(now - last_le_advertisement_) < milliseconds(200)) {
+ return;
+ }
+ last_le_advertisement_ = now;
+
+ auto own_address_type = static_cast<model::packets::AddressType>(
+ properties_.GetLeAdvertisingOwnAddressType());
+ Address advertising_address = Address::kEmpty;
+ if (own_address_type == model::packets::AddressType::PUBLIC) {
+ advertising_address = properties_.GetAddress();
+ } else if (own_address_type == model::packets::AddressType::RANDOM) {
+ advertising_address = properties_.GetLeAddress();
+ }
+ ASSERT(advertising_address != Address::kEmpty);
+ auto to_send = model::packets::LeAdvertisementBuilder::Create(
+ advertising_address, Address::kEmpty, own_address_type,
+ static_cast<model::packets::AdvertisementType>(own_address_type),
+ properties_.GetLeAdvertisement());
+ SendLeLinkLayerPacket(std::move(to_send));
+}
+
void LinkLayerController::Connections() {
// TODO: Keep connections alive?
}
void LinkLayerController::RegisterEventChannel(
- const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& callback) {
+ const std::function<
+ void(std::shared_ptr<bluetooth::hci::EventPacketBuilder>)>& callback) {
send_event_ = callback;
}
void LinkLayerController::RegisterAclChannel(
- const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& callback) {
+ const std::function<
+ void(std::shared_ptr<bluetooth::hci::AclPacketBuilder>)>& callback) {
send_acl_ = callback;
}
@@ -660,8 +977,16 @@
send_sco_ = callback;
}
+void LinkLayerController::RegisterIsoChannel(
+ const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>&
+ callback) {
+ send_iso_ = callback;
+}
+
void LinkLayerController::RegisterRemoteChannel(
- const std::function<void(std::shared_ptr<LinkLayerPacketBuilder>, Phy::Type)>& callback) {
+ const std::function<void(
+ std::shared_ptr<model::packets::LinkLayerPacketBuilder>, Phy::Type)>&
+ callback) {
send_to_remote_ = callback;
}
@@ -670,27 +995,43 @@
schedule_task_ = event_scheduler;
}
+AsyncTaskId LinkLayerController::ScheduleTask(milliseconds delay_ms, const TaskCallback& callback) {
+ if (schedule_task_) {
+ return schedule_task_(delay_ms, callback);
+ } else {
+ callback();
+ return 0;
+ }
+}
+
void LinkLayerController::RegisterPeriodicTaskScheduler(
std::function<AsyncTaskId(milliseconds, milliseconds, const TaskCallback&)> periodic_event_scheduler) {
schedule_periodic_task_ = periodic_event_scheduler;
}
+void LinkLayerController::CancelScheduledTask(AsyncTaskId task_id) {
+ if (schedule_task_ && cancel_task_) {
+ cancel_task_(task_id);
+ }
+}
+
void LinkLayerController::RegisterTaskCancel(std::function<void(AsyncTaskId)> task_cancel) {
cancel_task_ = task_cancel;
}
void LinkLayerController::AddControllerEvent(milliseconds delay, const TaskCallback& task) {
- controller_events_.push_back(schedule_task_(delay, task));
+ controller_events_.push_back(ScheduleTask(delay, task));
}
void LinkLayerController::WriteSimplePairingMode(bool enabled) {
- CHECK(enabled) << "The spec says don't disable this!";
+ ASSERT_LOG(enabled, "The spec says don't disable this!");
simple_pairing_mode_enabled_ = enabled;
}
void LinkLayerController::StartSimplePairing(const Address& address) {
// IO Capability Exchange (See the Diagram in the Spec)
- send_event_(EventPacketBuilder::CreateIoCapabilityRequestEvent(address)->ToVector());
+ auto packet = bluetooth::hci::IoCapabilityRequestBuilder::Create(address);
+ send_event_(std::move(packet));
// Get a Key, then authenticate
// PublicKeyExchange(address);
@@ -699,337 +1040,492 @@
}
void LinkLayerController::AuthenticateRemoteStage1(const Address& peer, PairingType pairing_type) {
- CHECK(security_manager_.GetAuthenticationAddress() == peer);
+ ASSERT(security_manager_.GetAuthenticationAddress() == peer);
// TODO: Public key exchange first?
switch (pairing_type) {
case PairingType::AUTO_CONFIRMATION:
- send_event_(EventPacketBuilder::CreateUserConfirmationRequestEvent(peer, 123456)->ToVector());
+ send_event_(
+ bluetooth::hci::UserConfirmationRequestBuilder::Create(peer, 123456));
break;
case PairingType::CONFIRM_Y_N:
- CHECK(false) << __func__ << "Unimplemented PairingType" << static_cast<int>(pairing_type);
+ send_event_(
+ bluetooth::hci::UserConfirmationRequestBuilder::Create(peer, 123456));
break;
case PairingType::DISPLAY_PIN:
- CHECK(false) << __func__ << "Unimplemented PairingType" << static_cast<int>(pairing_type);
+ send_event_(
+ bluetooth::hci::UserConfirmationRequestBuilder::Create(peer, 123456));
break;
case PairingType::DISPLAY_AND_CONFIRM:
- CHECK(false) << __func__ << "Unimplemented PairingType" << static_cast<int>(pairing_type);
+ send_event_(
+ bluetooth::hci::UserConfirmationRequestBuilder::Create(peer, 123456));
break;
case PairingType::INPUT_PIN:
- CHECK(false) << __func__ << "Unimplemented PairingType" << static_cast<int>(pairing_type);
- break;
- case PairingType::INVALID:
- CHECK(false) << __func__ << "Unimplemented PairingType" << static_cast<int>(pairing_type);
+ send_event_(bluetooth::hci::UserPasskeyRequestBuilder::Create(peer));
break;
default:
- CHECK(false) << __func__ << ": Invalid PairingType " << static_cast<int>(pairing_type);
+ LOG_ALWAYS_FATAL("Invalid PairingType %d", static_cast<int>(pairing_type));
}
}
void LinkLayerController::AuthenticateRemoteStage2(const Address& peer) {
uint16_t handle = security_manager_.GetAuthenticationHandle();
- CHECK(security_manager_.GetAuthenticationAddress() == peer);
+ ASSERT(security_manager_.GetAuthenticationAddress() == peer);
// Check key in security_manager_ ?
- send_event_(EventPacketBuilder::CreateAuthenticationCompleteEvent(hci::Status::SUCCESS, handle)->ToVector());
+ auto packet = bluetooth::hci::AuthenticationCompleteBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, handle);
+ send_event_(std::move(packet));
}
-hci::Status LinkLayerController::LinkKeyRequestReply(const Address& peer, PacketView<true> key) {
- std::vector<uint8_t> key_vec(key.begin(), key.end());
- security_manager_.WriteKey(peer, key_vec);
+bluetooth::hci::ErrorCode LinkLayerController::LinkKeyRequestReply(
+ const Address& peer, const std::array<uint8_t, 16>& key) {
+ security_manager_.WriteKey(peer, key);
security_manager_.AuthenticationRequestFinished();
- schedule_task_(milliseconds(5), [this, peer]() { AuthenticateRemoteStage2(peer); });
+ ScheduleTask(milliseconds(5), [this, peer]() { AuthenticateRemoteStage2(peer); });
- return hci::Status::SUCCESS;
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
-hci::Status LinkLayerController::LinkKeyRequestNegativeReply(const Address& address) {
+bluetooth::hci::ErrorCode LinkLayerController::LinkKeyRequestNegativeReply(
+ const Address& address) {
security_manager_.DeleteKey(address);
// Simple pairing to get a key
- uint16_t handle = classic_connections_.GetHandle(address);
+ uint16_t handle = connections_.GetHandle(address);
if (handle == acl::kReservedHandle) {
- LOG_INFO(LOG_TAG, "%s: Device not connected %s", __func__, address.ToString().c_str());
- return hci::Status::UNKNOWN_CONNECTION;
+ LOG_INFO("%s: Device not connected %s", __func__, address.ToString().c_str());
+ return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
}
security_manager_.AuthenticationRequest(address, handle);
- schedule_task_(milliseconds(5), [this, address]() { StartSimplePairing(address); });
- return hci::Status::SUCCESS;
+ ScheduleTask(milliseconds(5), [this, address]() { StartSimplePairing(address); });
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
-hci::Status LinkLayerController::IoCapabilityRequestReply(const Address& peer, uint8_t io_capability,
- uint8_t oob_data_present_flag,
- uint8_t authentication_requirements) {
+bluetooth::hci::ErrorCode LinkLayerController::IoCapabilityRequestReply(
+ const Address& peer, uint8_t io_capability, uint8_t oob_data_present_flag,
+ uint8_t authentication_requirements) {
security_manager_.SetLocalIoCapability(peer, io_capability, oob_data_present_flag, authentication_requirements);
PairingType pairing_type = security_manager_.GetSimplePairingType();
+
if (pairing_type != PairingType::INVALID) {
- schedule_task_(milliseconds(5), [this, peer, pairing_type]() { AuthenticateRemoteStage1(peer, pairing_type); });
- SendLinkLayerPacket(LinkLayerPacketBuilder::WrapIoCapabilityResponse(
- IoCapabilityBuilder::Create(io_capability, oob_data_present_flag, authentication_requirements),
- properties_.GetAddress(), peer));
+ ScheduleTask(milliseconds(5), [this, peer, pairing_type]() {
+ AuthenticateRemoteStage1(peer, pairing_type);
+ });
+ SendLinkLayerPacket(model::packets::IoCapabilityResponseBuilder::Create(
+ properties_.GetAddress(), peer, io_capability, oob_data_present_flag,
+ authentication_requirements));
} else {
- LOG_INFO(LOG_TAG, "%s: Requesting remote capability", __func__);
- SendLinkLayerPacket(LinkLayerPacketBuilder::WrapIoCapabilityRequest(
- IoCapabilityBuilder::Create(io_capability, oob_data_present_flag, authentication_requirements),
- properties_.GetAddress(), peer));
+ LOG_INFO("%s: Requesting remote capability", __func__);
+
+ SendLinkLayerPacket(model::packets::IoCapabilityRequestBuilder::Create(
+ properties_.GetAddress(), peer, io_capability, oob_data_present_flag,
+ authentication_requirements));
}
- return hci::Status::SUCCESS;
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
-hci::Status LinkLayerController::IoCapabilityRequestNegativeReply(const Address& peer, hci::Status reason) {
+bluetooth::hci::ErrorCode LinkLayerController::IoCapabilityRequestNegativeReply(
+ const Address& peer, bluetooth::hci::ErrorCode reason) {
if (security_manager_.GetAuthenticationAddress() != peer) {
- return hci::Status::AUTHENTICATION_FAILURE;
+ return bluetooth::hci::ErrorCode::AUTHENTICATION_FAILURE;
}
security_manager_.InvalidateIoCapabilities();
- SendLinkLayerPacket(LinkLayerPacketBuilder::WrapIoCapabilityNegativeResponse(
- IoCapabilityNegativeResponseBuilder::Create(static_cast<uint8_t>(reason)), properties_.GetAddress(), peer));
+ auto packet = model::packets::IoCapabilityNegativeResponseBuilder::Create(
+ properties_.GetAddress(), peer, static_cast<uint8_t>(reason));
+ SendLinkLayerPacket(std::move(packet));
- return hci::Status::SUCCESS;
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
-hci::Status LinkLayerController::UserConfirmationRequestReply(const Address& peer) {
+bluetooth::hci::ErrorCode LinkLayerController::UserConfirmationRequestReply(
+ const Address& peer) {
if (security_manager_.GetAuthenticationAddress() != peer) {
- return hci::Status::AUTHENTICATION_FAILURE;
+ return bluetooth::hci::ErrorCode::AUTHENTICATION_FAILURE;
}
// TODO: Key could be calculated here.
- std::vector<uint8_t> key_vec{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
+ std::array<uint8_t, 16> key_vec{1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16};
security_manager_.WriteKey(peer, key_vec);
security_manager_.AuthenticationRequestFinished();
- schedule_task_(milliseconds(5), [this, peer]() { AuthenticateRemoteStage2(peer); });
- return hci::Status::SUCCESS;
+ ScheduleTask(milliseconds(5), [this, peer, key_vec]() {
+ send_event_(bluetooth::hci::LinkKeyNotificationBuilder::Create(
+ peer, key_vec, bluetooth::hci::KeyType::AUTHENTICATED_P256));
+ });
+
+ ScheduleTask(milliseconds(15),
+ [this, peer]() { AuthenticateRemoteStage2(peer); });
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
-hci::Status LinkLayerController::UserConfirmationRequestNegativeReply(const Address& peer) {
+bluetooth::hci::ErrorCode
+LinkLayerController::UserConfirmationRequestNegativeReply(const Address& peer) {
if (security_manager_.GetAuthenticationAddress() != peer) {
- return hci::Status::AUTHENTICATION_FAILURE;
+ return bluetooth::hci::ErrorCode::AUTHENTICATION_FAILURE;
}
- return hci::Status::SUCCESS;
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
-hci::Status LinkLayerController::UserPasskeyRequestReply(const Address& peer, uint32_t numeric_value) {
+bluetooth::hci::ErrorCode LinkLayerController::UserPasskeyRequestReply(
+ const Address& peer, uint32_t numeric_value) {
if (security_manager_.GetAuthenticationAddress() != peer) {
- return hci::Status::AUTHENTICATION_FAILURE;
+ return bluetooth::hci::ErrorCode::AUTHENTICATION_FAILURE;
}
- LOG_INFO(LOG_TAG, "TODO:Do something with the passkey %06d", numeric_value);
- return hci::Status::SUCCESS;
+ LOG_INFO("TODO:Do something with the passkey %06d", numeric_value);
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
-hci::Status LinkLayerController::UserPasskeyRequestNegativeReply(const Address& peer) {
+bluetooth::hci::ErrorCode LinkLayerController::UserPasskeyRequestNegativeReply(
+ const Address& peer) {
if (security_manager_.GetAuthenticationAddress() != peer) {
- return hci::Status::AUTHENTICATION_FAILURE;
+ return bluetooth::hci::ErrorCode::AUTHENTICATION_FAILURE;
}
- return hci::Status::SUCCESS;
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
-hci::Status LinkLayerController::RemoteOobDataRequestReply(const Address& peer, const std::vector<uint8_t>& c,
- const std::vector<uint8_t>& r) {
+bluetooth::hci::ErrorCode LinkLayerController::RemoteOobDataRequestReply(
+ const Address& peer, const std::vector<uint8_t>& c,
+ const std::vector<uint8_t>& r) {
if (security_manager_.GetAuthenticationAddress() != peer) {
- return hci::Status::AUTHENTICATION_FAILURE;
+ return bluetooth::hci::ErrorCode::AUTHENTICATION_FAILURE;
}
- LOG_INFO(LOG_TAG, "TODO:Do something with the OOB data c=%d r=%d", c[0], r[0]);
- return hci::Status::SUCCESS;
+ LOG_INFO("TODO:Do something with the OOB data c=%d r=%d", c[0], r[0]);
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
-hci::Status LinkLayerController::RemoteOobDataRequestNegativeReply(const Address& peer) {
+bluetooth::hci::ErrorCode
+LinkLayerController::RemoteOobDataRequestNegativeReply(const Address& peer) {
if (security_manager_.GetAuthenticationAddress() != peer) {
- return hci::Status::AUTHENTICATION_FAILURE;
+ return bluetooth::hci::ErrorCode::AUTHENTICATION_FAILURE;
}
- return hci::Status::SUCCESS;
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
void LinkLayerController::HandleAuthenticationRequest(const Address& address, uint16_t handle) {
if (simple_pairing_mode_enabled_ == true) {
security_manager_.AuthenticationRequest(address, handle);
- send_event_(EventPacketBuilder::CreateLinkKeyRequestEvent(address)->ToVector());
+ auto packet = bluetooth::hci::LinkKeyRequestBuilder::Create(address);
+ send_event_(std::move(packet));
} else { // Should never happen for our phones
// Check for a key, try to authenticate, ask for a PIN.
- send_event_(
- EventPacketBuilder::CreateAuthenticationCompleteEvent(hci::Status::AUTHENTICATION_FAILURE, handle)->ToVector());
+ auto packet = bluetooth::hci::AuthenticationCompleteBuilder::Create(
+ bluetooth::hci::ErrorCode::AUTHENTICATION_FAILURE, handle);
+ send_event_(std::move(packet));
}
}
-hci::Status LinkLayerController::AuthenticationRequested(uint16_t handle) {
- if (!classic_connections_.HasHandle(handle)) {
- LOG_INFO(LOG_TAG, "Authentication Requested for unknown handle %04x", handle);
- return hci::Status::UNKNOWN_CONNECTION;
+bluetooth::hci::ErrorCode LinkLayerController::AuthenticationRequested(
+ uint16_t handle) {
+ if (!connections_.HasHandle(handle)) {
+ LOG_INFO("Authentication Requested for unknown handle %04x", handle);
+ return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
}
- Address remote = classic_connections_.GetAddress(handle);
+ Address remote = connections_.GetAddress(handle);
- schedule_task_(milliseconds(5), [this, remote, handle]() { HandleAuthenticationRequest(remote, handle); });
+ ScheduleTask(milliseconds(5), [this, remote, handle]() { HandleAuthenticationRequest(remote, handle); });
- return hci::Status::SUCCESS;
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
void LinkLayerController::HandleSetConnectionEncryption(const Address& peer, uint16_t handle,
uint8_t encryption_enable) {
// TODO: Block ACL traffic or at least guard against it
- if (classic_connections_.IsEncrypted(handle) && encryption_enable) {
- send_event_(
- EventPacketBuilder::CreateEncryptionChange(hci::Status::SUCCESS, handle, encryption_enable)->ToVector());
+ if (connections_.IsEncrypted(handle) && encryption_enable) {
+ auto packet = bluetooth::hci::EncryptionChangeBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, handle,
+ static_cast<bluetooth::hci::EncryptionEnabled>(encryption_enable));
+ send_event_(std::move(packet));
return;
}
- SendLinkLayerPacket(LinkLayerPacketBuilder::WrapEncryptConnection(
- EncryptConnectionBuilder::Create(security_manager_.GetKey(peer)), properties_.GetAddress(), peer));
+ uint16_t count = security_manager_.ReadKey(peer);
+ if (count == 0) {
+ LOG_ERROR("NO KEY HERE for %s", peer.ToString().c_str());
+ return;
+ }
+ auto array = security_manager_.GetKey(peer);
+ std::vector<uint8_t> key_vec{array.begin(), array.end()};
+ auto packet = model::packets::EncryptConnectionBuilder::Create(
+ properties_.GetAddress(), peer, key_vec);
+ SendLinkLayerPacket(std::move(packet));
}
-hci::Status LinkLayerController::SetConnectionEncryption(uint16_t handle, uint8_t encryption_enable) {
- if (!classic_connections_.HasHandle(handle)) {
- LOG_INFO(LOG_TAG, "Authentication Requested for unknown handle %04x", handle);
- return hci::Status::UNKNOWN_CONNECTION;
+bluetooth::hci::ErrorCode LinkLayerController::SetConnectionEncryption(
+ uint16_t handle, uint8_t encryption_enable) {
+ if (!connections_.HasHandle(handle)) {
+ LOG_INFO("Set Connection Encryption for unknown handle %04x", handle);
+ return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
}
- if (classic_connections_.IsEncrypted(handle) && !encryption_enable) {
- return hci::Status::ENCRYPTION_MODE_NOT_ACCEPTABLE;
+ if (connections_.IsEncrypted(handle) && !encryption_enable) {
+ return bluetooth::hci::ErrorCode::ENCRYPTION_MODE_NOT_ACCEPTABLE;
}
- Address remote = classic_connections_.GetAddress(handle);
+ Address remote = connections_.GetAddress(handle);
- schedule_task_(milliseconds(5), [this, remote, handle, encryption_enable]() {
+ if (security_manager_.ReadKey(remote) == 0) {
+ return bluetooth::hci::ErrorCode::PIN_OR_KEY_MISSING;
+ }
+
+ ScheduleTask(milliseconds(5), [this, remote, handle, encryption_enable]() {
HandleSetConnectionEncryption(remote, handle, encryption_enable);
});
-
- return hci::Status::SUCCESS;
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
-hci::Status LinkLayerController::AcceptConnectionRequest(const Address& addr, bool try_role_switch) {
- if (!classic_connections_.HasPendingConnection(addr)) {
- LOG_INFO(LOG_TAG, "%s: No pending connection", __func__);
- return hci::Status::UNKNOWN_CONNECTION;
+bluetooth::hci::ErrorCode LinkLayerController::AcceptConnectionRequest(
+ const Address& addr, bool try_role_switch) {
+ if (!connections_.HasPendingConnection(addr)) {
+ LOG_INFO("%s: No pending connection for %s", __func__, addr.ToString().c_str());
+ return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
}
- LOG_INFO(LOG_TAG, "%s: Accept in 200ms", __func__);
- schedule_task_(milliseconds(200), [this, addr, try_role_switch]() {
- LOG_INFO(LOG_TAG, "%s: Accepted", __func__);
+ LOG_INFO("%s: Accept in 200ms", __func__);
+ ScheduleTask(milliseconds(200), [this, addr, try_role_switch]() {
+ LOG_INFO("%s: Accepted", __func__);
MakeSlaveConnection(addr, try_role_switch);
});
- return hci::Status::SUCCESS;
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
void LinkLayerController::MakeSlaveConnection(const Address& addr, bool try_role_switch) {
- std::shared_ptr<LinkLayerPacketBuilder> to_send = LinkLayerPacketBuilder::WrapPageResponse(
- PageResponseBuilder::Create(try_role_switch), properties_.GetAddress(), addr);
- LOG_INFO(LOG_TAG, "%s sending page response to %s", __func__, addr.ToString().c_str());
- SendLinkLayerPacket(to_send);
+ LOG_INFO("%s sending page response to %s", __func__, addr.ToString().c_str());
+ auto to_send = model::packets::PageResponseBuilder::Create(
+ properties_.GetAddress(), addr, try_role_switch);
+ SendLinkLayerPacket(std::move(to_send));
- uint16_t handle = classic_connections_.CreateConnection(addr);
+ uint16_t handle = connections_.CreateConnection(addr);
if (handle == acl::kReservedHandle) {
- LOG_INFO(LOG_TAG, "%s CreateConnection failed", __func__);
+ LOG_INFO("%s CreateConnection failed", __func__);
return;
}
- LOG_INFO(LOG_TAG, "%s CreateConnection returned handle 0x%x", __func__, handle);
- send_event_(
- EventPacketBuilder::CreateConnectionCompleteEvent(hci::Status::SUCCESS, handle, addr, hci::LinkType::ACL, false)
- ->ToVector());
+ LOG_INFO("%s CreateConnection returned handle 0x%x", __func__, handle);
+ auto packet = bluetooth::hci::ConnectionCompleteBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, handle, addr,
+ bluetooth::hci::LinkType::ACL, bluetooth::hci::Enable::DISABLED);
+ send_event_(std::move(packet));
}
-hci::Status LinkLayerController::RejectConnectionRequest(const Address& addr, uint8_t reason) {
- if (!classic_connections_.HasPendingConnection(addr)) {
- LOG_INFO(LOG_TAG, "%s: No pending connection", __func__);
- return hci::Status::UNKNOWN_CONNECTION;
+bluetooth::hci::ErrorCode LinkLayerController::RejectConnectionRequest(
+ const Address& addr, uint8_t reason) {
+ if (!connections_.HasPendingConnection(addr)) {
+ LOG_INFO("%s: No pending connection for %s", __func__, addr.ToString().c_str());
+ return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
}
- LOG_INFO(LOG_TAG, "%s: Reject in 200ms", __func__);
- schedule_task_(milliseconds(200), [this, addr, reason]() {
- LOG_INFO(LOG_TAG, "%s: Reject", __func__);
- RejectSlaveConnection(addr, reason);
- });
+ ScheduleTask(milliseconds(200),
+ [this, addr, reason]() { RejectSlaveConnection(addr, reason); });
- return hci::Status::SUCCESS;
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
void LinkLayerController::RejectSlaveConnection(const Address& addr, uint8_t reason) {
- CHECK(reason > 0x0f || reason < 0x0d);
- send_event_(EventPacketBuilder::CreateConnectionCompleteEvent(static_cast<hci::Status>(reason), 0xeff, addr,
- hci::LinkType::ACL, false)
- ->ToVector());
+ auto to_send = model::packets::PageRejectBuilder::Create(
+ properties_.GetAddress(), addr, reason);
+ LOG_INFO("%s sending page reject to %s (reason 0x%02hhx)", __func__,
+ addr.ToString().c_str(), reason);
+ SendLinkLayerPacket(std::move(to_send));
+
+ auto packet = bluetooth::hci::ConnectionCompleteBuilder::Create(
+ static_cast<bluetooth::hci::ErrorCode>(reason), 0xeff, addr,
+ bluetooth::hci::LinkType::ACL, bluetooth::hci::Enable::DISABLED);
+ send_event_(std::move(packet));
}
-hci::Status LinkLayerController::CreateConnection(const Address& addr, uint16_t, uint8_t, uint16_t,
- uint8_t allow_role_switch) {
- if (!classic_connections_.CreatePendingConnection(addr)) {
- return hci::Status::CONTROLLER_BUSY;
+bluetooth::hci::ErrorCode LinkLayerController::CreateConnection(
+ const Address& addr, uint16_t, uint8_t, uint16_t,
+ uint8_t allow_role_switch) {
+ if (!connections_.CreatePendingConnection(
+ addr, properties_.GetAuthenticationEnable() == 1)) {
+ return bluetooth::hci::ErrorCode::CONTROLLER_BUSY;
}
+ auto page = model::packets::PageBuilder::Create(
+ properties_.GetAddress(), addr, properties_.GetClassOfDevice(),
+ allow_role_switch);
+ SendLinkLayerPacket(std::move(page));
- std::unique_ptr<PageBuilder> page = PageBuilder::Create(properties_.GetClassOfDevice(), allow_role_switch);
- SendLinkLayerPacket(LinkLayerPacketBuilder::WrapPage(std::move(page), properties_.GetAddress(), addr));
-
- return hci::Status::SUCCESS;
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
-hci::Status LinkLayerController::CreateConnectionCancel(const Address& addr) {
- if (!classic_connections_.CancelPendingConnection(addr)) {
- return hci::Status::UNKNOWN_CONNECTION;
+bluetooth::hci::ErrorCode LinkLayerController::CreateConnectionCancel(
+ const Address& addr) {
+ if (!connections_.CancelPendingConnection(addr)) {
+ return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
}
- return hci::Status::SUCCESS;
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
-hci::Status LinkLayerController::Disconnect(uint16_t handle, uint8_t reason) {
+bluetooth::hci::ErrorCode LinkLayerController::Disconnect(uint16_t handle,
+ uint8_t reason) {
// TODO: Handle LE
- if (!classic_connections_.HasHandle(handle)) {
- return hci::Status::UNKNOWN_CONNECTION;
+ if (!connections_.HasHandle(handle)) {
+ return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
}
- const Address& remote = classic_connections_.GetAddress(handle);
- std::shared_ptr<LinkLayerPacketBuilder> to_send =
- LinkLayerPacketBuilder::WrapDisconnect(DisconnectBuilder::Create(reason), properties_.GetAddress(), remote);
- SendLinkLayerPacket(to_send);
- CHECK(classic_connections_.Disconnect(handle)) << "Disconnecting " << handle;
+ const Address& remote = connections_.GetAddress(handle);
+ auto packet = model::packets::DisconnectBuilder::Create(
+ properties_.GetAddress(), remote, reason);
+ SendLinkLayerPacket(std::move(packet));
+ ASSERT_LOG(connections_.Disconnect(handle), "Disconnecting %hx", handle);
- schedule_task_(milliseconds(20), [this, handle]() {
- DisconnectCleanup(handle, static_cast<uint8_t>(hci::Status::CONNECTION_TERMINATED_BY_LOCAL_HOST));
+ ScheduleTask(milliseconds(20), [this, handle]() {
+ DisconnectCleanup(
+ handle,
+ static_cast<uint8_t>(
+ bluetooth::hci::ErrorCode::CONNECTION_TERMINATED_BY_LOCAL_HOST));
});
- return hci::Status::SUCCESS;
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
void LinkLayerController::DisconnectCleanup(uint16_t handle, uint8_t reason) {
// TODO: Clean up other connection state.
- send_event_(EventPacketBuilder::CreateDisconnectionCompleteEvent(hci::Status::SUCCESS, handle, reason)->ToVector());
+ auto packet = bluetooth::hci::DisconnectionCompleteBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, handle,
+ static_cast<bluetooth::hci::ErrorCode>(reason));
+ send_event_(std::move(packet));
}
-hci::Status LinkLayerController::ChangeConnectionPacketType(uint16_t handle, uint16_t types) {
- if (!classic_connections_.HasHandle(handle)) {
- return hci::Status::UNKNOWN_CONNECTION;
+bluetooth::hci::ErrorCode LinkLayerController::ChangeConnectionPacketType(
+ uint16_t handle, uint16_t types) {
+ if (!connections_.HasHandle(handle)) {
+ return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
}
- std::unique_ptr<EventPacketBuilder> packet =
- EventPacketBuilder::CreateConnectionPacketTypeChangedEvent(hci::Status::SUCCESS, handle, types);
- std::shared_ptr<std::vector<uint8_t>> raw_packet = packet->ToVector();
- if (schedule_task_) {
- schedule_task_(milliseconds(20), [this, raw_packet]() { send_event_(raw_packet); });
- } else {
- send_event_(raw_packet);
- }
+ auto packet = bluetooth::hci::ConnectionPacketTypeChangedBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS, handle, types);
+ std::shared_ptr<bluetooth::hci::ConnectionPacketTypeChangedBuilder>
+ shared_packet = std::move(packet);
+ ScheduleTask(milliseconds(20), [this, shared_packet]() {
+ send_event_(std::move(shared_packet));
+ });
- return hci::Status::SUCCESS;
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
-hci::Status LinkLayerController::WriteLinkPolicySettings(uint16_t handle, uint16_t) {
- if (!classic_connections_.HasHandle(handle)) {
- return hci::Status::UNKNOWN_CONNECTION;
+bluetooth::hci::ErrorCode LinkLayerController::ChangeConnectionLinkKey(
+ uint16_t handle) {
+ if (!connections_.HasHandle(handle)) {
+ return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
}
- return hci::Status::SUCCESS;
+
+ // TODO: implement real logic
+ return bluetooth::hci::ErrorCode::COMMAND_DISALLOWED;
}
-hci::Status LinkLayerController::WriteLinkSupervisionTimeout(uint16_t handle, uint16_t) {
- if (!classic_connections_.HasHandle(handle)) {
- return hci::Status::UNKNOWN_CONNECTION;
+bluetooth::hci::ErrorCode LinkLayerController::MasterLinkKey(
+ uint8_t /* key_flag */) {
+ // TODO: implement real logic
+ return bluetooth::hci::ErrorCode::COMMAND_DISALLOWED;
+}
+
+bluetooth::hci::ErrorCode LinkLayerController::HoldMode(
+ uint16_t handle, uint16_t hold_mode_max_interval,
+ uint16_t hold_mode_min_interval) {
+ if (!connections_.HasHandle(handle)) {
+ return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
}
- return hci::Status::SUCCESS;
+
+ if (hold_mode_max_interval < hold_mode_min_interval) {
+ return bluetooth::hci::ErrorCode::INVALID_HCI_COMMAND_PARAMETERS;
+ }
+
+ // TODO: implement real logic
+ return bluetooth::hci::ErrorCode::COMMAND_DISALLOWED;
+}
+
+bluetooth::hci::ErrorCode LinkLayerController::SniffMode(
+ uint16_t handle, uint16_t sniff_max_interval, uint16_t sniff_min_interval,
+ uint16_t sniff_attempt, uint16_t sniff_timeout) {
+ if (!connections_.HasHandle(handle)) {
+ return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
+ }
+
+ if (sniff_max_interval < sniff_min_interval || sniff_attempt < 0x0001 || sniff_attempt > 0x7FFF ||
+ sniff_timeout > 0x7FFF) {
+ return bluetooth::hci::ErrorCode::INVALID_HCI_COMMAND_PARAMETERS;
+ }
+
+ // TODO: implement real logic
+ return bluetooth::hci::ErrorCode::COMMAND_DISALLOWED;
+}
+
+bluetooth::hci::ErrorCode LinkLayerController::ExitSniffMode(uint16_t handle) {
+ if (!connections_.HasHandle(handle)) {
+ return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
+ }
+
+ // TODO: implement real logic
+ return bluetooth::hci::ErrorCode::COMMAND_DISALLOWED;
+}
+
+bluetooth::hci::ErrorCode LinkLayerController::QosSetup(
+ uint16_t handle, uint8_t service_type, uint32_t /* token_rate */,
+ uint32_t /* peak_bandwidth */, uint32_t /* latency */,
+ uint32_t /* delay_variation */) {
+ if (!connections_.HasHandle(handle)) {
+ return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
+ }
+
+ if (service_type > 0x02) {
+ return bluetooth::hci::ErrorCode::INVALID_HCI_COMMAND_PARAMETERS;
+ }
+
+ // TODO: implement real logic
+ return bluetooth::hci::ErrorCode::COMMAND_DISALLOWED;
+}
+
+bluetooth::hci::ErrorCode LinkLayerController::SwitchRole(Address /* bd_addr */,
+ uint8_t /* role */) {
+ // TODO: implement real logic
+ return bluetooth::hci::ErrorCode::COMMAND_DISALLOWED;
+}
+
+bluetooth::hci::ErrorCode LinkLayerController::WriteLinkPolicySettings(
+ uint16_t handle, uint16_t) {
+ if (!connections_.HasHandle(handle)) {
+ return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
+ }
+ return bluetooth::hci::ErrorCode::SUCCESS;
+}
+
+bluetooth::hci::ErrorCode LinkLayerController::FlowSpecification(
+ uint16_t handle, uint8_t flow_direction, uint8_t service_type,
+ uint32_t /* token_rate */, uint32_t /* token_bucket_size */,
+ uint32_t /* peak_bandwidth */, uint32_t /* access_latency */) {
+ if (!connections_.HasHandle(handle)) {
+ return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
+ }
+
+ if (flow_direction > 0x01 || service_type > 0x02) {
+ return bluetooth::hci::ErrorCode::INVALID_HCI_COMMAND_PARAMETERS;
+ }
+
+ // TODO: implement real logic
+ return bluetooth::hci::ErrorCode::COMMAND_DISALLOWED;
+}
+
+bluetooth::hci::ErrorCode LinkLayerController::WriteLinkSupervisionTimeout(
+ uint16_t handle, uint16_t) {
+ if (!connections_.HasHandle(handle)) {
+ return bluetooth::hci::ErrorCode::UNKNOWN_CONNECTION;
+ }
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
void LinkLayerController::LeWhiteListClear() {
le_white_list_.clear();
}
+void LinkLayerController::LeResolvingListClear() { le_resolving_list_.clear(); }
+
void LinkLayerController::LeWhiteListAddDevice(Address addr, uint8_t addr_type) {
std::tuple<Address, uint8_t> new_tuple = std::make_tuple(addr, addr_type);
for (auto dev : le_white_list_) {
@@ -1040,6 +1536,30 @@
le_white_list_.emplace_back(new_tuple);
}
+void LinkLayerController::LeResolvingListAddDevice(
+ Address addr, uint8_t addr_type, std::array<uint8_t, kIrk_size> peerIrk,
+ std::array<uint8_t, kIrk_size> localIrk) {
+ std::tuple<Address, uint8_t, std::array<uint8_t, kIrk_size>,
+ std::array<uint8_t, kIrk_size>>
+ new_tuple = std::make_tuple(addr, addr_type, peerIrk, localIrk);
+ for (size_t i = 0; i < le_white_list_.size(); i++) {
+ auto curr = le_white_list_[i];
+ if (std::get<0>(curr) == addr && std::get<1>(curr) == addr_type) {
+ le_resolving_list_[i] = new_tuple;
+ return;
+ }
+ }
+ le_resolving_list_.emplace_back(new_tuple);
+}
+
+void LinkLayerController::LeSetPrivacyMode(uint8_t address_type, Address addr,
+ uint8_t mode) {
+ // set mode for addr
+ LOG_INFO("address type = %d ", address_type);
+ LOG_INFO("address = %s ", addr.ToString().c_str());
+ LOG_INFO("mode = %d ", mode);
+}
+
void LinkLayerController::LeWhiteListRemoveDevice(Address addr, uint8_t addr_type) {
// TODO: Add checks to see if advertising, scanning, or a connection request
// with the white list is ongoing.
@@ -1051,6 +1571,18 @@
}
}
+void LinkLayerController::LeResolvingListRemoveDevice(Address addr,
+ uint8_t addr_type) {
+ // TODO: Add checks to see if advertising, scanning, or a connection request
+ // with the white list is ongoing.
+ for (size_t i = 0; i < le_white_list_.size(); i++) {
+ auto curr = le_white_list_[i];
+ if (std::get<0>(curr) == addr && std::get<1>(curr) == addr_type) {
+ le_resolving_list_.erase(le_resolving_list_.begin() + i);
+ }
+ }
+}
+
bool LinkLayerController::LeWhiteListContainsDevice(Address addr, uint8_t addr_type) {
std::tuple<Address, uint8_t> sought_tuple = std::make_tuple(addr, addr_type);
for (size_t i = 0; i < le_white_list_.size(); i++) {
@@ -1061,39 +1593,56 @@
return false;
}
+bool LinkLayerController::LeResolvingListContainsDevice(Address addr,
+ uint8_t addr_type) {
+ for (size_t i = 0; i < le_white_list_.size(); i++) {
+ auto curr = le_white_list_[i];
+ if (std::get<0>(curr) == addr && std::get<1>(curr) == addr_type) {
+ return true;
+ }
+ }
+ return false;
+}
+
bool LinkLayerController::LeWhiteListFull() {
return le_white_list_.size() >= properties_.GetLeWhiteListSize();
}
+bool LinkLayerController::LeResolvingListFull() {
+ return le_resolving_list_.size() >= properties_.GetLeResolvingListSize();
+}
+
void LinkLayerController::Reset() {
inquiry_state_ = Inquiry::InquiryState::STANDBY;
last_inquiry_ = steady_clock::now();
le_scan_enable_ = 0;
+ le_advertising_enable_ = 0;
le_connect_ = 0;
}
void LinkLayerController::PageScan() {}
void LinkLayerController::StartInquiry(milliseconds timeout) {
- schedule_task_(milliseconds(timeout), [this]() { LinkLayerController::InquiryTimeout(); });
+ ScheduleTask(milliseconds(timeout), [this]() { LinkLayerController::InquiryTimeout(); });
inquiry_state_ = Inquiry::InquiryState::INQUIRY;
- LOG_INFO(LOG_TAG, "InquiryState = %d ", static_cast<int>(inquiry_state_));
}
void LinkLayerController::InquiryCancel() {
- CHECK(inquiry_state_ == Inquiry::InquiryState::INQUIRY);
+ ASSERT(inquiry_state_ == Inquiry::InquiryState::INQUIRY);
inquiry_state_ = Inquiry::InquiryState::STANDBY;
}
void LinkLayerController::InquiryTimeout() {
if (inquiry_state_ == Inquiry::InquiryState::INQUIRY) {
inquiry_state_ = Inquiry::InquiryState::STANDBY;
- send_event_(EventPacketBuilder::CreateInquiryCompleteEvent(hci::Status::SUCCESS)->ToVector());
+ auto packet = bluetooth::hci::InquiryCompleteBuilder::Create(
+ bluetooth::hci::ErrorCode::SUCCESS);
+ send_event_(std::move(packet));
}
}
void LinkLayerController::SetInquiryMode(uint8_t mode) {
- inquiry_mode_ = static_cast<Inquiry::InquiryType>(mode);
+ inquiry_mode_ = static_cast<model::packets::InquiryType>(mode);
}
void LinkLayerController::SetInquiryLAP(uint64_t lap) {
@@ -1109,11 +1658,10 @@
if (duration_cast<milliseconds>(now - last_inquiry_) < milliseconds(2000)) {
return;
}
- LOG_INFO(LOG_TAG, "Inquiry ");
- std::unique_ptr<InquiryBuilder> inquiry = InquiryBuilder::Create(inquiry_mode_);
- std::shared_ptr<LinkLayerPacketBuilder> to_send =
- LinkLayerPacketBuilder::WrapInquiry(std::move(inquiry), properties_.GetAddress());
- SendLinkLayerPacket(to_send);
+
+ auto packet = model::packets::InquiryBuilder::Create(
+ properties_.GetAddress(), Address::kEmpty, inquiry_mode_);
+ SendLinkLayerPacket(std::move(packet));
last_inquiry_ = now;
}
@@ -1125,18 +1673,4 @@
page_scans_enabled_ = enable;
}
-/* TODO: Connection handling
- // TODO: Handle in the link manager.
- uint16_t handle = LeGetHandle();
-
- std::shared_ptr<Connection> new_connection =
- std::make_shared<Connection>(peer, handle);
- connections_.push_back(new_connection);
- peer->SetConnection(new_connection);
-
- send_event_(EventPacketBuilder::CreateLeEnhancedConnectionCompleteEvent(
- hci::Status::SUCCESS, handle, 0x00, // role
- le_peer_address_type_, le_peer_address_, Address::kEmpty,
- Address::kEmpty, 0x0024, 0x0000, 0x01f4)->ToVector());
-*/
} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h
index 5cec196..487109f 100644
--- a/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h
+++ b/vendor_libs/test_vendor_lib/model/controller/link_layer_controller.h
@@ -17,77 +17,111 @@
#pragma once
#include "acl_connection_handler.h"
+#include "hci/address.h"
+#include "hci/hci_packets.h"
#include "include/hci.h"
#include "include/inquiry.h"
-#include "include/link.h"
#include "include/phy.h"
#include "model/devices/device_properties.h"
#include "model/setup/async_manager.h"
-#include "packets/hci/acl_packet_view.h"
-#include "packets/hci/sco_packet_view.h"
-#include "packets/link_layer/link_layer_packet_builder.h"
-#include "packets/link_layer/link_layer_packet_view.h"
+#include "packets/link_layer_packets.h"
#include "security_manager.h"
-#include "types/address.h"
namespace test_vendor_lib {
+using ::bluetooth::hci::Address;
+
class LinkLayerController {
public:
+ static constexpr size_t kIrk_size = 16;
+
LinkLayerController(const DeviceProperties& properties) : properties_(properties) {}
- hci::Status SendCommandToRemoteByAddress(hci::OpCode opcode, packets::PacketView<true> args, const Address& remote,
- bool use_public_address);
- hci::Status SendCommandToRemoteByHandle(hci::OpCode opcode, packets::PacketView<true> args, uint16_t handle);
- hci::Status SendScoToRemote(packets::ScoPacketView sco_packet);
- hci::Status SendAclToRemote(packets::AclPacketView acl_packet);
+ bluetooth::hci::ErrorCode SendCommandToRemoteByAddress(
+ bluetooth::hci::OpCode opcode, bluetooth::packet::PacketView<true> args,
+ const Address& remote);
+ bluetooth::hci::ErrorCode SendCommandToRemoteByHandle(
+ bluetooth::hci::OpCode opcode, bluetooth::packet::PacketView<true> args,
+ uint16_t handle);
+ bluetooth::hci::ErrorCode SendScoToRemote(
+ bluetooth::hci::ScoPacketView sco_packet);
+ bluetooth::hci::ErrorCode SendAclToRemote(
+ bluetooth::hci::AclPacketView acl_packet);
void WriteSimplePairingMode(bool enabled);
void StartSimplePairing(const Address& address);
void AuthenticateRemoteStage1(const Address& address, PairingType pairing_type);
void AuthenticateRemoteStage2(const Address& address);
- hci::Status LinkKeyRequestReply(const Address& address, packets::PacketView<true> key);
- hci::Status LinkKeyRequestNegativeReply(const Address& address);
- hci::Status IoCapabilityRequestReply(const Address& peer, uint8_t io_capability, uint8_t oob_data_present_flag,
- uint8_t authentication_requirements);
- hci::Status IoCapabilityRequestNegativeReply(const Address& peer, hci::Status reason);
- hci::Status UserConfirmationRequestReply(const Address& peer);
- hci::Status UserConfirmationRequestNegativeReply(const Address& peer);
- hci::Status UserPasskeyRequestReply(const Address& peer, uint32_t numeric_value);
- hci::Status UserPasskeyRequestNegativeReply(const Address& peer);
- hci::Status RemoteOobDataRequestReply(const Address& peer, const std::vector<uint8_t>& c,
- const std::vector<uint8_t>& r);
- hci::Status RemoteOobDataRequestNegativeReply(const Address& peer);
+ bluetooth::hci::ErrorCode LinkKeyRequestReply(
+ const Address& address, const std::array<uint8_t, 16>& key);
+ bluetooth::hci::ErrorCode LinkKeyRequestNegativeReply(const Address& address);
+ bluetooth::hci::ErrorCode IoCapabilityRequestReply(
+ const Address& peer, uint8_t io_capability, uint8_t oob_data_present_flag,
+ uint8_t authentication_requirements);
+ bluetooth::hci::ErrorCode IoCapabilityRequestNegativeReply(
+ const Address& peer, bluetooth::hci::ErrorCode reason);
+ bluetooth::hci::ErrorCode UserConfirmationRequestReply(const Address& peer);
+ bluetooth::hci::ErrorCode UserConfirmationRequestNegativeReply(
+ const Address& peer);
+ bluetooth::hci::ErrorCode UserPasskeyRequestReply(const Address& peer,
+ uint32_t numeric_value);
+ bluetooth::hci::ErrorCode UserPasskeyRequestNegativeReply(
+ const Address& peer);
+ bluetooth::hci::ErrorCode RemoteOobDataRequestReply(
+ const Address& peer, const std::vector<uint8_t>& c,
+ const std::vector<uint8_t>& r);
+ bluetooth::hci::ErrorCode RemoteOobDataRequestNegativeReply(
+ const Address& peer);
void HandleSetConnectionEncryption(const Address& address, uint16_t handle, uint8_t encryption_enable);
- hci::Status SetConnectionEncryption(uint16_t handle, uint8_t encryption_enable);
+ bluetooth::hci::ErrorCode SetConnectionEncryption(uint16_t handle,
+ uint8_t encryption_enable);
void HandleAuthenticationRequest(const Address& address, uint16_t handle);
- hci::Status AuthenticationRequested(uint16_t handle);
+ bluetooth::hci::ErrorCode AuthenticationRequested(uint16_t handle);
- hci::Status AcceptConnectionRequest(const Address& addr, bool try_role_switch);
+ bluetooth::hci::ErrorCode AcceptConnectionRequest(const Address& addr,
+ bool try_role_switch);
void MakeSlaveConnection(const Address& addr, bool try_role_switch);
- hci::Status RejectConnectionRequest(const Address& addr, uint8_t reason);
+ bluetooth::hci::ErrorCode RejectConnectionRequest(const Address& addr,
+ uint8_t reason);
void RejectSlaveConnection(const Address& addr, uint8_t reason);
- hci::Status CreateConnection(const Address& addr, uint16_t packet_type, uint8_t page_scan_mode, uint16_t clock_offset,
- uint8_t allow_role_switch);
- hci::Status CreateConnectionCancel(const Address& addr);
- hci::Status Disconnect(uint16_t handle, uint8_t reason);
+ bluetooth::hci::ErrorCode CreateConnection(const Address& addr,
+ uint16_t packet_type,
+ uint8_t page_scan_mode,
+ uint16_t clock_offset,
+ uint8_t allow_role_switch);
+ bluetooth::hci::ErrorCode CreateConnectionCancel(const Address& addr);
+ bluetooth::hci::ErrorCode Disconnect(uint16_t handle, uint8_t reason);
private:
void DisconnectCleanup(uint16_t handle, uint8_t reason);
public:
- void IncomingPacket(packets::LinkLayerPacketView incoming);
+ void IncomingPacket(model::packets::LinkLayerPacketView incoming);
void TimerTick();
- // Set the callbacks for sending packets to the HCI.
- void RegisterEventChannel(const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& send_event);
+ AsyncTaskId ScheduleTask(std::chrono::milliseconds delay_ms, const TaskCallback& task);
- void RegisterAclChannel(const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& send_acl);
+ void CancelScheduledTask(AsyncTaskId task);
+
+ // Set the callbacks for sending packets to the HCI.
+ void RegisterEventChannel(
+ const std::function<void(
+ std::shared_ptr<bluetooth::hci::EventPacketBuilder>)>& send_event);
+
+ void RegisterAclChannel(
+ const std::function<
+ void(std::shared_ptr<bluetooth::hci::AclPacketBuilder>)>& send_acl);
void RegisterScoChannel(const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>& send_sco);
+ void RegisterIsoChannel(
+ const std::function<void(std::shared_ptr<std::vector<uint8_t>>)>&
+ send_iso);
+
void RegisterRemoteChannel(
- const std::function<void(std::shared_ptr<packets::LinkLayerPacketBuilder>, Phy::Type)>& send_to_remote);
+ const std::function<void(
+ std::shared_ptr<model::packets::LinkLayerPacketBuilder>, Phy::Type)>&
+ send_to_remote);
// Set the callbacks for scheduling tasks.
void RegisterTaskScheduler(
@@ -104,11 +138,31 @@
void PageScan();
void Connections();
+ void LeAdvertising();
+
+ void HandleLeConnection(Address addr, uint8_t addr_type, uint8_t own_addr_type, uint8_t role,
+ uint16_t connection_interval, uint16_t connection_latency, uint16_t supervision_timeout);
+
void LeWhiteListClear();
void LeWhiteListAddDevice(Address addr, uint8_t addr_type);
void LeWhiteListRemoveDevice(Address addr, uint8_t addr_type);
bool LeWhiteListContainsDevice(Address addr, uint8_t addr_type);
bool LeWhiteListFull();
+ void LeResolvingListClear();
+ void LeResolvingListAddDevice(Address addr, uint8_t addr_type,
+ std::array<uint8_t, kIrk_size> peerIrk,
+ std::array<uint8_t, kIrk_size> localIrk);
+ void LeResolvingListRemoveDevice(Address addr, uint8_t addr_type);
+ bool LeResolvingListContainsDevice(Address addr, uint8_t addr_type);
+ bool LeResolvingListFull();
+ void LeSetPrivacyMode(uint8_t address_type, Address addr, uint8_t mode);
+
+ bluetooth::hci::ErrorCode SetLeAdvertisingEnable(
+ uint8_t le_advertising_enable) {
+ le_advertising_enable_ = le_advertising_enable;
+ // TODO: Check properties and return errors
+ return bluetooth::hci::ErrorCode::SUCCESS;
+ }
void SetLeScanEnable(uint8_t le_scan_enable) {
le_scan_enable_ = le_scan_enable;
@@ -131,9 +185,9 @@
void SetLeAddressType(uint8_t le_address_type) {
le_address_type_ = le_address_type;
}
- hci::Status SetLeConnect(bool le_connect) {
+ bluetooth::hci::ErrorCode SetLeConnect(bool le_connect) {
le_connect_ = le_connect;
- return hci::Status::SUCCESS;
+ return bluetooth::hci::ErrorCode::SUCCESS;
}
void SetLeConnectionIntervalMin(uint16_t min) {
le_connection_interval_min_ = min;
@@ -175,37 +229,93 @@
void SetInquiryScanEnable(bool enable);
void SetPageScanEnable(bool enable);
- hci::Status ChangeConnectionPacketType(uint16_t handle, uint16_t types);
- hci::Status WriteLinkPolicySettings(uint16_t handle, uint16_t settings);
- hci::Status WriteLinkSupervisionTimeout(uint16_t handle, uint16_t timeout);
+ bluetooth::hci::ErrorCode ChangeConnectionPacketType(uint16_t handle,
+ uint16_t types);
+ bluetooth::hci::ErrorCode ChangeConnectionLinkKey(uint16_t handle);
+ bluetooth::hci::ErrorCode MasterLinkKey(uint8_t key_flag);
+ bluetooth::hci::ErrorCode HoldMode(uint16_t handle,
+ uint16_t hold_mode_max_interval,
+ uint16_t hold_mode_min_interval);
+ bluetooth::hci::ErrorCode SniffMode(uint16_t handle,
+ uint16_t sniff_max_interval,
+ uint16_t sniff_min_interval,
+ uint16_t sniff_attempt,
+ uint16_t sniff_timeout);
+ bluetooth::hci::ErrorCode ExitSniffMode(uint16_t handle);
+ bluetooth::hci::ErrorCode QosSetup(uint16_t handle, uint8_t service_type,
+ uint32_t token_rate,
+ uint32_t peak_bandwidth, uint32_t latency,
+ uint32_t delay_variation);
+ bluetooth::hci::ErrorCode SwitchRole(Address bd_addr, uint8_t role);
+ bluetooth::hci::ErrorCode WriteLinkPolicySettings(uint16_t handle,
+ uint16_t settings);
+ bluetooth::hci::ErrorCode FlowSpecification(
+ uint16_t handle, uint8_t flow_direction, uint8_t service_type,
+ uint32_t token_rate, uint32_t token_bucket_size, uint32_t peak_bandwidth,
+ uint32_t access_latency);
+ bluetooth::hci::ErrorCode WriteLinkSupervisionTimeout(uint16_t handle,
+ uint16_t timeout);
protected:
- void SendLELinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> packet);
- void SendLinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> packet);
- void IncomingAclPacket(packets::LinkLayerPacketView packet);
- void IncomingAclAckPacket(packets::LinkLayerPacketView packet);
- void IncomingCommandPacket(packets::LinkLayerPacketView packet);
- void IncomingCreateConnectionPacket(packets::LinkLayerPacketView packet);
- void IncomingDisconnectPacket(packets::LinkLayerPacketView packet);
- void IncomingEncryptConnection(packets::LinkLayerPacketView packet);
- void IncomingEncryptConnectionResponse(packets::LinkLayerPacketView packet);
- void IncomingInquiryPacket(packets::LinkLayerPacketView packet);
- void IncomingInquiryResponsePacket(packets::LinkLayerPacketView packet);
- void IncomingIoCapabilityRequestPacket(packets::LinkLayerPacketView packet);
- void IncomingIoCapabilityResponsePacket(packets::LinkLayerPacketView packet);
- void IncomingIoCapabilityNegativeResponsePacket(packets::LinkLayerPacketView packet);
- void IncomingLeAdvertisementPacket(packets::LinkLayerPacketView packet);
- void IncomingLeScanPacket(packets::LinkLayerPacketView packet);
- void IncomingLeScanResponsePacket(packets::LinkLayerPacketView packet);
- void IncomingPagePacket(packets::LinkLayerPacketView packet);
- void IncomingPageResponsePacket(packets::LinkLayerPacketView packet);
- void IncomingResponsePacket(packets::LinkLayerPacketView packet);
+ void SendLeLinkLayerPacket(
+ std::unique_ptr<model::packets::LinkLayerPacketBuilder> packet);
+ void SendLinkLayerPacket(
+ std::unique_ptr<model::packets::LinkLayerPacketBuilder> packet);
+ void IncomingAclPacket(model::packets::LinkLayerPacketView packet);
+ void IncomingAclAckPacket(model::packets::LinkLayerPacketView packet);
+ void IncomingCreateConnectionPacket(
+ model::packets::LinkLayerPacketView packet);
+ void IncomingDisconnectPacket(model::packets::LinkLayerPacketView packet);
+ void IncomingEncryptConnection(model::packets::LinkLayerPacketView packet);
+ void IncomingEncryptConnectionResponse(
+ model::packets::LinkLayerPacketView packet);
+ void IncomingInquiryPacket(model::packets::LinkLayerPacketView packet);
+ void IncomingInquiryResponsePacket(
+ model::packets::LinkLayerPacketView packet);
+ void IncomingIoCapabilityRequestPacket(
+ model::packets::LinkLayerPacketView packet);
+ void IncomingIoCapabilityResponsePacket(
+ model::packets::LinkLayerPacketView packet);
+ void IncomingIoCapabilityNegativeResponsePacket(
+ model::packets::LinkLayerPacketView packet);
+ void IncomingLeAdvertisementPacket(
+ model::packets::LinkLayerPacketView packet);
+ void IncomingLeConnectPacket(model::packets::LinkLayerPacketView packet);
+ void IncomingLeConnectCompletePacket(
+ model::packets::LinkLayerPacketView packet);
+ void IncomingLeScanPacket(model::packets::LinkLayerPacketView packet);
+ void IncomingLeScanResponsePacket(model::packets::LinkLayerPacketView packet);
+ void IncomingPagePacket(model::packets::LinkLayerPacketView packet);
+ void IncomingPageRejectPacket(model::packets::LinkLayerPacketView packet);
+ void IncomingPageResponsePacket(model::packets::LinkLayerPacketView packet);
+ void IncomingReadRemoteLmpFeatures(
+ model::packets::LinkLayerPacketView packet);
+ void IncomingReadRemoteLmpFeaturesResponse(
+ model::packets::LinkLayerPacketView packet);
+ void IncomingReadRemoteSupportedFeatures(
+ model::packets::LinkLayerPacketView packet);
+ void IncomingReadRemoteSupportedFeaturesResponse(
+ model::packets::LinkLayerPacketView packet);
+ void IncomingReadRemoteExtendedFeatures(
+ model::packets::LinkLayerPacketView packet);
+ void IncomingReadRemoteExtendedFeaturesResponse(
+ model::packets::LinkLayerPacketView packet);
+ void IncomingReadRemoteVersion(model::packets::LinkLayerPacketView packet);
+ void IncomingReadRemoteVersionResponse(
+ model::packets::LinkLayerPacketView packet);
+ void IncomingReadClockOffset(model::packets::LinkLayerPacketView packet);
+ void IncomingReadClockOffsetResponse(
+ model::packets::LinkLayerPacketView packet);
+ void IncomingRemoteNameRequest(model::packets::LinkLayerPacketView packet);
+ void IncomingRemoteNameRequestResponse(
+ model::packets::LinkLayerPacketView packet);
private:
const DeviceProperties& properties_;
- AclConnectionHandler classic_connections_;
+ AclConnectionHandler connections_;
// Add timestamps?
- std::vector<std::shared_ptr<packets::LinkLayerPacketBuilder>> commands_awaiting_responses_;
+ std::vector<std::shared_ptr<model::packets::LinkLayerPacketBuilder>>
+ commands_awaiting_responses_;
// Timing related state
std::vector<AsyncTaskId> controller_events_;
@@ -219,19 +329,30 @@
std::function<void(AsyncTaskId)> cancel_task_;
// Callbacks to send packets back to the HCI.
- std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_acl_;
- std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_event_;
+ std::function<void(std::shared_ptr<bluetooth::hci::AclPacketBuilder>)>
+ send_acl_;
+ std::function<void(std::shared_ptr<bluetooth::hci::EventPacketBuilder>)>
+ send_event_;
std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_sco_;
+ std::function<void(std::shared_ptr<std::vector<uint8_t>>)> send_iso_;
// Callback to send packets to remote devices.
- std::function<void(std::shared_ptr<packets::LinkLayerPacketBuilder>, Phy::Type phy_type)> send_to_remote_;
+ std::function<void(std::shared_ptr<model::packets::LinkLayerPacketBuilder>,
+ Phy::Type phy_type)>
+ send_to_remote_;
// LE state
std::vector<uint8_t> le_event_mask_;
std::vector<std::tuple<Address, uint8_t>> le_white_list_;
+ std::vector<std::tuple<Address, uint8_t, std::array<uint8_t, kIrk_size>,
+ std::array<uint8_t, kIrk_size>>>
+ le_resolving_list_;
- uint8_t le_scan_enable_;
+ uint8_t le_advertising_enable_{false};
+ std::chrono::steady_clock::time_point last_le_advertisement_;
+
+ uint8_t le_scan_enable_{false};
uint8_t le_scan_type_;
uint16_t le_scan_interval_;
uint16_t le_scan_window_;
@@ -239,7 +360,7 @@
uint8_t le_scan_filter_duplicates_;
uint8_t le_address_type_;
- bool le_connect_;
+ bool le_connect_{false};
uint16_t le_connection_interval_min_;
uint16_t le_connection_interval_max_;
uint16_t le_connection_latency_;
@@ -255,7 +376,7 @@
SecurityManager security_manager_{10};
std::chrono::steady_clock::time_point last_inquiry_;
- Inquiry::InquiryType inquiry_mode_;
+ model::packets::InquiryType inquiry_mode_;
Inquiry::InquiryState inquiry_state_;
uint64_t inquiry_lap_;
uint8_t inquiry_max_responses_;
diff --git a/vendor_libs/test_vendor_lib/model/controller/security_manager.cc b/vendor_libs/test_vendor_lib/model/controller/security_manager.cc
index 6ab1351..38b9e64 100644
--- a/vendor_libs/test_vendor_lib/model/controller/security_manager.cc
+++ b/vendor_libs/test_vendor_lib/model/controller/security_manager.cc
@@ -14,11 +14,9 @@
* limitations under the License.
*/
-#define LOG_TAG "security_manager"
-
#include "security_manager.h"
-#include "base/logging.h"
+#include "os/log.h"
using std::vector;
@@ -46,7 +44,8 @@
return key_store_.count(addr.ToString());
}
-uint16_t SecurityManager::WriteKey(const Address& addr, const std::vector<uint8_t>& key) {
+uint16_t SecurityManager::WriteKey(const Address& addr,
+ const std::array<uint8_t, 16>& key) {
if (key_store_.size() >= max_keys_) {
return 0;
}
@@ -54,8 +53,9 @@
return 1;
}
-const std::vector<uint8_t>& SecurityManager::GetKey(const Address& addr) const {
- CHECK(ReadKey(addr)) << "No such key";
+const std::array<uint8_t, 16>& SecurityManager::GetKey(
+ const Address& addr) const {
+ ASSERT_LOG(ReadKey(addr), "No such key");
return key_store_.at(addr.ToString());
}
@@ -83,7 +83,7 @@
void SecurityManager::SetPeerIoCapability(const Address& addr, uint8_t io_capability, uint8_t oob_present_flag,
uint8_t authentication_requirements) {
- CHECK_EQ(addr, peer_address_);
+ ASSERT(addr == peer_address_);
peer_capabilities_valid_ = true;
if (io_capability <= static_cast<uint8_t>(IoCapabilityType::NO_INPUT_NO_OUTPUT)) {
peer_io_capability_ = static_cast<IoCapabilityType>(io_capability);
@@ -102,12 +102,12 @@
void SecurityManager::SetLocalIoCapability(const Address& peer, uint8_t io_capability, uint8_t oob_present_flag,
uint8_t authentication_requirements) {
- CHECK_EQ(peer, peer_address_);
- CHECK(io_capability <= static_cast<uint8_t>(IoCapabilityType::NO_INPUT_NO_OUTPUT))
- << "io_capability = " << io_capability;
- CHECK(oob_present_flag <= 1) << "oob_present_flag = " << oob_present_flag;
- CHECK(authentication_requirements <= static_cast<uint8_t>(AuthenticationType::GENERAL_BONDING_MITM))
- << "authentication_requirements = " << authentication_requirements;
+ ASSERT(peer == peer_address_);
+ ASSERT_LOG(io_capability <= static_cast<uint8_t>(IoCapabilityType::NO_INPUT_NO_OUTPUT), "io_capability = %d",
+ static_cast<int>(io_capability));
+ ASSERT_LOG(oob_present_flag <= 1, "oob_present_flag = %hhx ", oob_present_flag);
+ ASSERT_LOG(authentication_requirements <= static_cast<uint8_t>(AuthenticationType::GENERAL_BONDING_MITM),
+ "authentication_requirements = %d", static_cast<int>(authentication_requirements));
host_io_capability_ = static_cast<IoCapabilityType>(io_capability);
host_oob_present_flag_ = (oob_present_flag == 1);
host_authentication_requirements_ = static_cast<AuthenticationType>(authentication_requirements);
@@ -132,7 +132,53 @@
if (!(peer_requires_mitm || host_requires_mitm)) {
return PairingType::AUTO_CONFIRMATION;
}
- return PairingType::INVALID;
+ LOG_INFO("%s: host does%s require peer does%s require MITM",
+ peer_address_.ToString().c_str(), host_requires_mitm ? "" : "n't",
+ peer_requires_mitm ? "" : "n't");
+ switch (peer_io_capability_) {
+ case IoCapabilityType::DISPLAY_ONLY:
+ switch (host_io_capability_) {
+ case IoCapabilityType::DISPLAY_ONLY:
+ case IoCapabilityType::DISPLAY_YES_NO:
+ return PairingType::AUTO_CONFIRMATION;
+ case IoCapabilityType::KEYBOARD_ONLY:
+ return PairingType::INPUT_PIN;
+ case IoCapabilityType::NO_INPUT_NO_OUTPUT:
+ return PairingType::AUTO_CONFIRMATION;
+ default:
+ return PairingType::INVALID;
+ }
+ case IoCapabilityType::DISPLAY_YES_NO:
+ switch (host_io_capability_) {
+ case IoCapabilityType::DISPLAY_ONLY:
+ return PairingType::AUTO_CONFIRMATION;
+ case IoCapabilityType::DISPLAY_YES_NO:
+ return PairingType::DISPLAY_AND_CONFIRM;
+ case IoCapabilityType::KEYBOARD_ONLY:
+ return PairingType::DISPLAY_PIN;
+ case IoCapabilityType::NO_INPUT_NO_OUTPUT:
+ return PairingType::AUTO_CONFIRMATION;
+ default:
+ return PairingType::INVALID;
+ }
+ case IoCapabilityType::KEYBOARD_ONLY:
+ switch (host_io_capability_) {
+ case IoCapabilityType::DISPLAY_ONLY:
+ return PairingType::DISPLAY_PIN;
+ case IoCapabilityType::DISPLAY_YES_NO:
+ return PairingType::DISPLAY_PIN;
+ case IoCapabilityType::KEYBOARD_ONLY:
+ return PairingType::INPUT_PIN;
+ case IoCapabilityType::NO_INPUT_NO_OUTPUT:
+ return PairingType::AUTO_CONFIRMATION;
+ default:
+ return PairingType::INVALID;
+ }
+ case IoCapabilityType::NO_INPUT_NO_OUTPUT:
+ return PairingType::AUTO_CONFIRMATION;
+ default:
+ return PairingType::INVALID;
+ }
}
} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/controller/security_manager.h b/vendor_libs/test_vendor_lib/model/controller/security_manager.h
index 94284cb..e77f1d1 100644
--- a/vendor_libs/test_vendor_lib/model/controller/security_manager.h
+++ b/vendor_libs/test_vendor_lib/model/controller/security_manager.h
@@ -16,15 +16,17 @@
#pragma once
+#include <array>
#include <cstdint>
#include <string>
#include <unordered_map>
-#include <vector>
-#include "types/address.h"
+#include "hci/address.h"
namespace test_vendor_lib {
+using ::bluetooth::hci::Address;
+
enum class PairingType : uint8_t {
AUTO_CONFIRMATION,
CONFIRM_Y_N,
@@ -62,12 +64,10 @@
uint16_t DeleteKey(const Address& addr);
uint16_t ReadAllKeys() const;
uint16_t ReadKey(const Address& addr) const;
- uint16_t WriteKey(const Address& addr, const std::vector<uint8_t>& key);
- uint16_t ReadCapacity() const {
- return max_keys_;
- };
+ uint16_t WriteKey(const Address& addr, const std::array<uint8_t, 16>& key);
+ uint16_t ReadCapacity() const { return max_keys_; };
- const std::vector<uint8_t>& GetKey(const Address& addr) const;
+ const std::array<uint8_t, 16>& GetKey(const Address& addr) const;
void AuthenticationRequest(const Address& addr, uint16_t handle);
void AuthenticationRequestFinished();
@@ -87,16 +87,16 @@
private:
uint16_t max_keys_;
- std::unordered_map<std::string, std::vector<uint8_t>> key_store_;
+ std::unordered_map<std::string, std::array<uint8_t, 16>> key_store_;
bool peer_capabilities_valid_{false};
IoCapabilityType peer_io_capability_;
- bool peer_oob_present_flag_;
+ bool peer_oob_present_flag_{false};
AuthenticationType peer_authentication_requirements_;
bool host_capabilities_valid_{false};
IoCapabilityType host_io_capability_;
- bool host_oob_present_flag_;
+ bool host_oob_present_flag_{false};
AuthenticationType host_authentication_requirements_;
bool authenticating_{false};
diff --git a/vendor_libs/test_vendor_lib/model/devices/beacon.cc b/vendor_libs/test_vendor_lib/model/devices/beacon.cc
index 10ebf5c..96f6099 100644
--- a/vendor_libs/test_vendor_lib/model/devices/beacon.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/beacon.cc
@@ -14,31 +14,27 @@
* limitations under the License.
*/
-#define LOG_TAG "beacon"
-
#include "beacon.h"
-#include "le_advertisement.h"
#include "model/setup/device_boutique.h"
-#include "osi/include/log.h"
using std::vector;
namespace test_vendor_lib {
-bool Beacon::registered_ = DeviceBoutique::Register(LOG_TAG, &Beacon::Create);
+bool Beacon::registered_ = DeviceBoutique::Register("beacon", &Beacon::Create);
Beacon::Beacon() {
advertising_interval_ms_ = std::chrono::milliseconds(1280);
- properties_.SetLeAdvertisementType(BTM_BLE_NON_CONNECT_EVT);
+ properties_.SetLeAdvertisementType(0x03 /* NON_CONNECT */);
properties_.SetLeAdvertisement({0x0F, // Length
- BTM_BLE_AD_TYPE_NAME_CMPL, 'g', 'D', 'e', 'v', 'i', 'c', 'e', '-', 'b', 'e', 'a', 'c',
+ 0x09 /* TYPE_NAME_CMPL */, 'g', 'D', 'e', 'v', 'i', 'c', 'e', '-', 'b', 'e', 'a', 'c',
'o', 'n',
0x02, // Length
- BTM_BLE_AD_TYPE_FLAG, BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG});
+ 0x01 /* TYPE_FLAG */, 0x4 /* BREDR_NOT_SPT */ | 0x2 /* GEN_DISC_FLAG */});
properties_.SetLeScanResponse({0x05, // Length
- BTM_BLE_AD_TYPE_NAME_SHORT, 'b', 'e', 'a', 'c'});
+ 0x08 /* TYPE_NAME_SHORT */, 'b', 'e', 'a', 'c'});
}
std::string Beacon::GetTypeString() const {
@@ -63,29 +59,35 @@
}
void Beacon::TimerTick() {
- if (IsAdvertisementAvailable(std::chrono::milliseconds(5000))) {
- std::unique_ptr<packets::LeAdvertisementBuilder> ad = packets::LeAdvertisementBuilder::Create(
- LeAdvertisement::AddressType::PUBLIC,
- static_cast<LeAdvertisement::AdvertisementType>(properties_.GetLeAdvertisementType()),
+ if (IsAdvertisementAvailable()) {
+ last_advertisement_ = std::chrono::steady_clock::now();
+ auto ad = model::packets::LeAdvertisementBuilder::Create(
+ properties_.GetLeAddress(), Address::kEmpty,
+ model::packets::AddressType::PUBLIC,
+ static_cast<model::packets::AdvertisementType>(
+ properties_.GetLeAdvertisementType()),
properties_.GetLeAdvertisement());
- std::shared_ptr<packets::LinkLayerPacketBuilder> to_send =
- packets::LinkLayerPacketBuilder::WrapLeAdvertisement(std::move(ad), properties_.GetLeAddress());
- std::vector<std::shared_ptr<PhyLayer>> le_phys = phy_layers_[Phy::Type::LOW_ENERGY];
- for (std::shared_ptr<PhyLayer> phy : le_phys) {
+ std::shared_ptr<model::packets::LinkLayerPacketBuilder> to_send =
+ std::move(ad);
+
+ for (auto phy : phy_layers_[Phy::Type::LOW_ENERGY]) {
phy->Send(to_send);
}
}
}
-void Beacon::IncomingPacket(packets::LinkLayerPacketView packet) {
- if (packet.GetDestinationAddress() == properties_.GetLeAddress() && packet.GetType() == Link::PacketType::LE_SCAN) {
- std::unique_ptr<packets::LeAdvertisementBuilder> scan_response = packets::LeAdvertisementBuilder::Create(
- LeAdvertisement::AddressType::PUBLIC, LeAdvertisement::AdvertisementType::SCAN_RESPONSE,
+void Beacon::IncomingPacket(model::packets::LinkLayerPacketView packet) {
+ if (packet.GetDestinationAddress() == properties_.GetLeAddress() &&
+ packet.GetType() == model::packets::PacketType::LE_SCAN) {
+ auto scan_response = model::packets::LeScanResponseBuilder::Create(
+ properties_.GetLeAddress(), packet.GetSourceAddress(),
+ model::packets::AddressType::PUBLIC,
+ model::packets::AdvertisementType::SCAN_RESPONSE,
properties_.GetLeScanResponse());
- std::shared_ptr<packets::LinkLayerPacketBuilder> to_send = packets::LinkLayerPacketBuilder::WrapLeScanResponse(
- std::move(scan_response), properties_.GetLeAddress(), packet.GetSourceAddress());
- std::vector<std::shared_ptr<PhyLayer>> le_phys = phy_layers_[Phy::Type::LOW_ENERGY];
- for (auto phy : le_phys) {
+ std::shared_ptr<model::packets::LinkLayerPacketBuilder> to_send =
+ std::move(scan_response);
+
+ for (auto phy : phy_layers_[Phy::Type::LOW_ENERGY]) {
phy->Send(to_send);
}
}
diff --git a/vendor_libs/test_vendor_lib/model/devices/beacon.h b/vendor_libs/test_vendor_lib/model/devices/beacon.h
index faac5cc..87bb228 100644
--- a/vendor_libs/test_vendor_lib/model/devices/beacon.h
+++ b/vendor_libs/test_vendor_lib/model/devices/beacon.h
@@ -20,7 +20,6 @@
#include <vector>
#include "device.h"
-#include "stack/include/btm_ble_api.h"
namespace test_vendor_lib {
@@ -43,7 +42,8 @@
// Set the address and advertising interval from string args.
virtual void Initialize(const std::vector<std::string>& args) override;
- virtual void IncomingPacket(packets::LinkLayerPacketView packet) override;
+ virtual void IncomingPacket(
+ model::packets::LinkLayerPacketView packet) override;
virtual void TimerTick() override;
diff --git a/vendor_libs/test_vendor_lib/model/devices/beacon_swarm.cc b/vendor_libs/test_vendor_lib/model/devices/beacon_swarm.cc
index a065c36..c9f17f1 100644
--- a/vendor_libs/test_vendor_lib/model/devices/beacon_swarm.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/beacon_swarm.cc
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "beacon_swarm"
-
#include "beacon_swarm.h"
#include "model/setup/device_boutique.h"
@@ -23,14 +21,14 @@
using std::vector;
namespace test_vendor_lib {
-bool BeaconSwarm::registered_ = DeviceBoutique::Register(LOG_TAG, &BeaconSwarm::Create);
+bool BeaconSwarm::registered_ = DeviceBoutique::Register("beacon_swarm", &BeaconSwarm::Create);
BeaconSwarm::BeaconSwarm() {
advertising_interval_ms_ = std::chrono::milliseconds(1280);
- properties_.SetLeAdvertisementType(BTM_BLE_NON_CONNECT_EVT);
+ properties_.SetLeAdvertisementType(0x03 /* NON_CONNECT */);
properties_.SetLeAdvertisement({
0x15, // Length
- BTM_BLE_AD_TYPE_NAME_CMPL,
+ 0x09 /* TYPE_NAME_CMPL */,
'g',
'D',
'e',
@@ -52,12 +50,12 @@
'r',
'm',
0x02, // Length
- BTM_BLE_AD_TYPE_FLAG,
- BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG,
+ 0x01 /* TYPE_FLAG */,
+ 0x4 /* BREDR_NOT_SPT */ | 0x2 /* GEN_DISC_FLAG */,
});
properties_.SetLeScanResponse({0x06, // Length
- BTM_BLE_AD_TYPE_NAME_SHORT, 'c', 'b', 'e', 'a', 'c'});
+ 0x08 /* TYPE_NAME_SHORT */, 'c', 'b', 'e', 'a', 'c'});
}
void BeaconSwarm::Initialize(const vector<std::string>& args) {
diff --git a/vendor_libs/test_vendor_lib/model/devices/broken_adv.cc b/vendor_libs/test_vendor_lib/model/devices/broken_adv.cc
index c7d6822..32c5ebb 100644
--- a/vendor_libs/test_vendor_lib/model/devices/broken_adv.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/broken_adv.cc
@@ -14,54 +14,36 @@
* limitations under the License.
*/
-#define LOG_TAG "broken_adv"
-
#include "broken_adv.h"
#include "model/setup/device_boutique.h"
-#include "osi/include/log.h"
using std::vector;
namespace test_vendor_lib {
-bool BrokenAdv::registered_ = DeviceBoutique::Register(LOG_TAG, &BrokenAdv::Create);
+bool BrokenAdv::registered_ = DeviceBoutique::Register("broken_adv", &BrokenAdv::Create);
BrokenAdv::BrokenAdv() {
advertising_interval_ms_ = std::chrono::milliseconds(1280);
- properties_.SetLeAdvertisementType(BTM_BLE_NON_CONNECT_EVT);
+ properties_.SetLeAdvertisementType(0x03 /* NON_CONNECT */);
constant_adv_data_ = {
- 0x02, // Length
- BTM_BLE_AD_TYPE_FLAG,
- BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG,
- 0x13, // Length
- BTM_BLE_AD_TYPE_NAME_CMPL,
- 'g',
- 'D',
- 'e',
- 'v',
- 'i',
- 'c',
- 'e',
- '-',
- 'b',
- 'r',
- 'o',
- 'k',
- 'e',
- 'n',
- '_',
- 'a',
- 'd',
- 'v',
+ 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
- BTM_BLE_AD_TYPE_NAME_SHORT, 'b', 'r', 'o', 'k', 'e', 'n', 'n', 'e', 's', 's'});
+ 0x08, // TYPE_NAME_SHORT
+ 'b', 'r', 'o', 'k', 'e', 'n', 'n', 'e', 's', 's'});
properties_.SetExtendedInquiryData({0x07, // Length
- BT_EIR_COMPLETE_LOCAL_NAME_TYPE, 'B', 'R', '0', 'K', '3', 'N'});
+ 0x09, // TYPE_NAME_COMPLETE
+ 'B', 'R', '0', 'K', '3', 'N'});
properties_.SetPageScanRepetitionMode(0);
page_scan_delay_ms_ = std::chrono::milliseconds(600);
}
@@ -106,7 +88,7 @@
switch ((randomness & 0xf000000) >> 24) {
case (0):
- return BTM_EIR_MANUFACTURER_SPECIFIC_TYPE;
+ return 0xff; // TYPE_MANUFACTURER_SPECIFIC
case (1):
return (randomness & 0xff);
default:
diff --git a/vendor_libs/test_vendor_lib/model/devices/car_kit.cc b/vendor_libs/test_vendor_lib/model/devices/car_kit.cc
index 5f7fa4a..65603f1 100644
--- a/vendor_libs/test_vendor_lib/model/devices/car_kit.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/car_kit.cc
@@ -14,19 +14,16 @@
* limitations under the License.
*/
-#define LOG_TAG "car_kit"
-
#include "car_kit.h"
-#include "osi/include/log.h"
-
#include "model/setup/device_boutique.h"
+#include "os/log.h"
using std::vector;
namespace test_vendor_lib {
-bool CarKit::registered_ = DeviceBoutique::Register(LOG_TAG, &CarKit::Create);
+bool CarKit::registered_ = DeviceBoutique::Register("car_kit", &CarKit::Create);
CarKit::CarKit() : Device(kCarKitPropertiesFile) {
advertising_interval_ms_ = std::chrono::milliseconds(0);
@@ -34,17 +31,20 @@
page_scan_delay_ms_ = std::chrono::milliseconds(600);
// Stub in packet handling for now
- link_layer_controller_.RegisterAclChannel([](std::shared_ptr<std::vector<uint8_t>>) {});
- link_layer_controller_.RegisterEventChannel([](std::shared_ptr<std::vector<uint8_t>>) {});
+ link_layer_controller_.RegisterAclChannel(
+ [](std::shared_ptr<bluetooth::hci::AclPacketBuilder>) {});
+ link_layer_controller_.RegisterEventChannel(
+ [](std::shared_ptr<bluetooth::hci::EventPacketBuilder>) {});
link_layer_controller_.RegisterScoChannel([](std::shared_ptr<std::vector<uint8_t>>) {});
link_layer_controller_.RegisterRemoteChannel(
- [this](std::shared_ptr<packets::LinkLayerPacketBuilder> packet, Phy::Type phy_type) {
+ [this](std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet,
+ Phy::Type phy_type) {
CarKit::SendLinkLayerPacket(packet, phy_type);
});
properties_.SetPageScanRepetitionMode(0);
properties_.SetClassOfDevice(0x600420);
- properties_.SetSupportedFeatures(0x8779ff9bfe8defff);
+ properties_.SetExtendedFeatures(0x8779ff9bfe8defff, 0);
properties_.SetExtendedInquiryData({
16, // length
9, // Type: Device Name
@@ -82,7 +82,7 @@
Address addr;
if (Address::FromString(args[1], addr)) properties_.SetAddress(addr);
- LOG_INFO(LOG_TAG, "%s SetAddress %s", ToString().c_str(), addr.ToString().c_str());
+ LOG_INFO("%s SetAddress %s", ToString().c_str(), addr.ToString().c_str());
if (args.size() < 3) return;
@@ -93,8 +93,8 @@
link_layer_controller_.TimerTick();
}
-void CarKit::IncomingPacket(packets::LinkLayerPacketView packet) {
- LOG_WARN(LOG_TAG, "Incoming Packet");
+void CarKit::IncomingPacket(model::packets::LinkLayerPacketView packet) {
+ LOG_WARN("Incoming Packet");
link_layer_controller_.IncomingPacket(packet);
}
diff --git a/vendor_libs/test_vendor_lib/model/devices/car_kit.h b/vendor_libs/test_vendor_lib/model/devices/car_kit.h
index 94057ad..f59a2ad 100644
--- a/vendor_libs/test_vendor_lib/model/devices/car_kit.h
+++ b/vendor_libs/test_vendor_lib/model/devices/car_kit.h
@@ -20,6 +20,7 @@
#include <vector>
#include "device.h"
+#include "hci/hci_packets.h"
#include "model/controller/link_layer_controller.h"
namespace {
@@ -45,7 +46,8 @@
return "car_kit";
}
- virtual void IncomingPacket(packets::LinkLayerPacketView packet) override;
+ virtual void IncomingPacket(
+ model::packets::LinkLayerPacketView packet) override;
virtual void TimerTick() override;
diff --git a/vendor_libs/test_vendor_lib/model/devices/classic.cc b/vendor_libs/test_vendor_lib/model/devices/classic.cc
index a8f8a99..e8df43a 100644
--- a/vendor_libs/test_vendor_lib/model/devices/classic.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/classic.cc
@@ -14,28 +14,25 @@
* limitations under the License.
*/
-#define LOG_TAG "classic"
-
#include "classic.h"
#include "model/setup/device_boutique.h"
-#include "osi/include/log.h"
using std::vector;
namespace test_vendor_lib {
-bool Classic::registered_ = DeviceBoutique::Register(LOG_TAG, &Classic::Create);
+bool Classic::registered_ = DeviceBoutique::Register("classic", &Classic::Create);
Classic::Classic() {
advertising_interval_ms_ = std::chrono::milliseconds(0);
properties_.SetClassOfDevice(0x30201);
- properties_.SetExtendedInquiryData({0x10, // Length
- BT_EIR_COMPLETE_LOCAL_NAME_TYPE, // Type
+ properties_.SetExtendedInquiryData({0x10, // Length
+ 0x09, // TYPE_NAME_CMPL
'g', 'D', 'e', 'v', 'i', 'c', 'e', '-', 'c', 'l', 'a', 's', 's', 'i', 'c',
'\0'}); // End of data
properties_.SetPageScanRepetitionMode(0);
- properties_.SetSupportedFeatures(0x87593F9bFE8FFEFF);
+ properties_.SetExtendedFeatures(0x87593F9bFE8FFEFF, 0);
page_scan_delay_ms_ = std::chrono::milliseconds(600);
}
diff --git a/vendor_libs/test_vendor_lib/model/devices/device.cc b/vendor_libs/test_vendor_lib/model/devices/device.cc
index 52a37c1..9fdcd5e 100644
--- a/vendor_libs/test_vendor_lib/model/devices/device.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/device.cc
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "device"
-
#include <vector>
#include "device.h"
@@ -34,35 +32,46 @@
phy_layers_[phy->GetType()].push_back(phy);
}
-void Device::UnregisterPhyLayer(std::shared_ptr<PhyLayer> phy) {
+void Device::UnregisterPhyLayers() {
for (auto phy_pair : phy_layers_) {
auto phy_list = std::get<1>(phy_pair);
- for (size_t i = 0; i < phy_list.size(); i++) {
- if (phy == phy_list[i]) {
- phy_list.erase(phy_list.begin() + i);
- }
+ for (auto phy : phy_list) {
+ phy->Unregister();
}
}
}
-bool Device::IsAdvertisementAvailable(std::chrono::milliseconds scan_time) const {
- if (advertising_interval_ms_ == std::chrono::milliseconds(0)) return false;
-
- std::chrono::steady_clock::time_point now = std::chrono::steady_clock::now();
-
- std::chrono::steady_clock::time_point last_interval =
- ((now - time_stamp_) / advertising_interval_ms_) * advertising_interval_ms_ + time_stamp_;
-
- std::chrono::steady_clock::time_point next_interval = last_interval + advertising_interval_ms_;
-
- return ((now + scan_time) >= next_interval);
+void Device::UnregisterPhyLayer(Phy::Type phy_type, uint32_t factory_id) {
+ for (const auto phy_layer : phy_layers_[phy_type]) {
+ if (phy_layer->IsFactoryId(factory_id)) {
+ phy_layer->Unregister();
+ phy_layers_[phy_type].remove(phy_layer);
+ }
+ }
}
-void Device::SendLinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> to_send, Phy::Type phy_type) {
- auto phy_list = phy_layers_[phy_type];
- for (auto phy : phy_list) {
+bool Device::IsAdvertisementAvailable() const {
+ return (advertising_interval_ms_ > std::chrono::milliseconds(0)) &&
+ (std::chrono::steady_clock::now() >= last_advertisement_ + advertising_interval_ms_);
+}
+
+void Device::SendLinkLayerPacket(
+ std::shared_ptr<model::packets::LinkLayerPacketBuilder> to_send,
+ Phy::Type phy_type) {
+ for (auto phy : phy_layers_[phy_type]) {
phy->Send(to_send);
}
}
+void Device::SendLinkLayerPacket(model::packets::LinkLayerPacketView to_send,
+ Phy::Type phy_type) {
+ for (auto phy : phy_layers_[phy_type]) {
+ phy->Send(to_send);
+ }
+}
+
+void Device::SetAddress(Address) {
+ LOG_INFO("%s does not implement %s", GetTypeString().c_str(), __func__);
+}
+
} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/device.h b/vendor_libs/test_vendor_lib/model/devices/device.h
index 18842cd..b985888 100644
--- a/vendor_libs/test_vendor_lib/model/devices/device.h
+++ b/vendor_libs/test_vendor_lib/model/devices/device.h
@@ -18,26 +18,27 @@
#include <chrono>
#include <cstdint>
+#include <list>
#include <map>
#include <string>
#include <vector>
+#include "hci/address.h"
#include "model/devices/device_properties.h"
#include "model/setup/phy_layer.h"
-#include "packets/link_layer/link_layer_packet_builder.h"
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "types/address.h"
-#include "stack/include/btm_ble_api.h"
+#include "packets/link_layer_packets.h"
namespace test_vendor_lib {
+using ::bluetooth::hci::Address;
+
// Represent a Bluetooth Device
// - Provide Get*() and Set*() functions for device attributes.
class Device {
public:
Device(const std::string properties_filename = "")
- : time_stamp_(std::chrono::steady_clock::now()), properties_(properties_filename) {}
+ : last_advertisement_(std::chrono::steady_clock::now()), properties_(properties_filename) {}
virtual ~Device() = default;
// Initialize the device based on the values of |args|.
@@ -57,30 +58,38 @@
return false;
}
+ // Set the device's Bluetooth address.
+ virtual void SetAddress(Address address);
+
// Set the advertisement interval in milliseconds.
void SetAdvertisementInterval(std::chrono::milliseconds ms) {
advertising_interval_ms_ = ms;
}
- // Returns true if the host could see an advertisement in the next
- // |scan_time| milliseconds.
- virtual bool IsAdvertisementAvailable(std::chrono::milliseconds scan_time) const;
+ // Returns true if the host could see an advertisement about now.
+ virtual bool IsAdvertisementAvailable() const;
// Let the device know that time has passed.
virtual void TimerTick() {}
void RegisterPhyLayer(std::shared_ptr<PhyLayer> phy);
- void UnregisterPhyLayer(std::shared_ptr<PhyLayer> phy);
+ void UnregisterPhyLayers();
- virtual void IncomingPacket(packets::LinkLayerPacketView){};
+ void UnregisterPhyLayer(Phy::Type phy_type, uint32_t factory_id);
- virtual void SendLinkLayerPacket(std::shared_ptr<packets::LinkLayerPacketBuilder> packet, Phy::Type phy_type);
+ virtual void IncomingPacket(model::packets::LinkLayerPacketView){};
+
+ virtual void SendLinkLayerPacket(
+ std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet,
+ Phy::Type phy_type);
+ virtual void SendLinkLayerPacket(model::packets::LinkLayerPacketView packet,
+ Phy::Type phy_type);
protected:
- std::map<Phy::Type, std::vector<std::shared_ptr<PhyLayer>>> phy_layers_;
+ std::map<Phy::Type, std::list<std::shared_ptr<PhyLayer>>> phy_layers_;
- std::chrono::steady_clock::time_point time_stamp_;
+ std::chrono::steady_clock::time_point last_advertisement_;
// The time between page scans.
std::chrono::milliseconds page_scan_delay_ms_;
diff --git a/vendor_libs/test_vendor_lib/model/devices/device_properties.cc b/vendor_libs/test_vendor_lib/model/devices/device_properties.cc
index 164160a..8309268 100644
--- a/vendor_libs/test_vendor_lib/model/devices/device_properties.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/device_properties.cc
@@ -14,19 +14,15 @@
* limitations under the License.
*/
-#define LOG_TAG "device_properties"
-
#include "device_properties.h"
#include <memory>
-#include <base/logging.h>
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/values.h"
-#include "hci.h"
-#include "osi/include/log.h"
+#include "os/log.h"
#include "osi/include/osi.h"
using std::vector;
@@ -48,20 +44,32 @@
namespace test_vendor_lib {
DeviceProperties::DeviceProperties(const std::string& file_name)
- : acl_data_packet_size_(1024), sco_data_packet_size_(255), num_acl_data_packets_(10), num_sco_data_packets_(10),
- version_(static_cast<uint8_t>(hci::Version::V4_1)), revision_(0),
- lmp_pal_version_(static_cast<uint8_t>(hci::Version::V4_1)), manufacturer_name_(0), lmp_pal_subversion_(0),
- le_data_packet_length_(27), num_le_data_packets_(15), le_white_list_size_(15) {
+ : acl_data_packet_size_(1024),
+ sco_data_packet_size_(255),
+ num_acl_data_packets_(10),
+ num_sco_data_packets_(10),
+ version_(static_cast<uint8_t>(bluetooth::hci::HciVersion::V_4_1)),
+ revision_(0),
+ lmp_pal_version_(static_cast<uint8_t>(bluetooth::hci::LmpVersion::V_4_1)),
+ manufacturer_name_(0),
+ lmp_pal_subversion_(0),
+ le_data_packet_length_(27),
+ num_le_data_packets_(15),
+ le_white_list_size_(15),
+ le_resolving_list_size_(15) {
std::string properties_raw;
- CHECK(Address::FromString("BB:BB:BB:BB:BB:AD", address_));
- CHECK(Address::FromString("BB:BB:BB:BB:AD:1E", le_address_));
+ ASSERT(Address::FromString("BB:BB:BB:BB:BB:AD", address_));
+ ASSERT(Address::FromString("BB:BB:BB:BB:AD:1E", le_address_));
name_ = {'D', 'e', 'f', 'a', 'u', 'l', 't'};
supported_codecs_ = {0}; // Only SBC is supported.
vendor_specific_codecs_ = {};
- for (int i = 0; i < 64; i++) supported_commands_.push_back(0xff);
+ for (int i = 0; i < 35; i++) supported_commands_.push_back(0xff);
+ // Mark HCI_LE_Transmitter_Test[v2] and newer commands as unsupported
+ // TODO: Implement a better mapping.
+ for (int i = 35; i < 64; i++) supported_commands_.push_back(0x00);
le_supported_features_ = 0x1f;
le_supported_states_ = 0x3ffffffffff;
@@ -70,15 +78,14 @@
if (file_name.size() == 0) {
return;
}
- LOG_INFO(LOG_TAG, "Reading controller properties from %s.", file_name.c_str());
+ LOG_INFO("Reading controller properties from %s.", file_name.c_str());
if (!base::ReadFileToString(base::FilePath(file_name), &properties_raw)) {
- LOG_ERROR(LOG_TAG, "Error reading controller properties from file.");
+ LOG_ERROR("Error reading controller properties from file.");
return;
}
std::unique_ptr<base::Value> properties_value_ptr = base::JSONReader::Read(properties_raw);
- if (properties_value_ptr.get() == nullptr)
- LOG_INFO(LOG_TAG, "Error controller properties may consist of ill-formed JSON.");
+ if (properties_value_ptr.get() == nullptr) LOG_INFO("Error controller properties may consist of ill-formed JSON.");
// Get the underlying base::Value object, which is of type
// base::Value::TYPE_DICTIONARY, and read it into member variables.
@@ -86,7 +93,7 @@
base::JSONValueConverter<DeviceProperties> converter;
if (!converter.Convert(properties_dictionary, this))
- LOG_INFO(LOG_TAG, "Error converting JSON properties into Properties object.");
+ LOG_INFO("Error converting JSON properties into Properties object.");
}
// static
@@ -98,6 +105,7 @@
converter->RegisterCustomField<uint16_t>(field_name, &DeviceProperties::field, &ParseUint16t);
REGISTER_UINT16_T("AclDataPacketSize", acl_data_packet_size_);
REGISTER_UINT8_T("ScoDataPacketSize", sco_data_packet_size_);
+ REGISTER_UINT8_T("EncryptionKeySize", encryption_key_size_);
REGISTER_UINT16_T("NumAclDataPackets", num_acl_data_packets_);
REGISTER_UINT16_T("NumScoDataPackets", num_sco_data_packets_);
REGISTER_UINT8_T("Version", version_);
diff --git a/vendor_libs/test_vendor_lib/model/devices/device_properties.h b/vendor_libs/test_vendor_lib/model/devices/device_properties.h
index 6960553..960e5d0 100644
--- a/vendor_libs/test_vendor_lib/model/devices/device_properties.h
+++ b/vendor_libs/test_vendor_lib/model/devices/device_properties.h
@@ -16,16 +16,21 @@
#pragma once
+#include <array>
#include <cstdint>
#include <string>
#include <vector>
#include "base/json/json_value_converter.h"
-#include "types/address.h"
-#include "types/class_of_device.h"
+#include "hci/address.h"
+#include "hci/hci_packets.h"
+#include "os/log.h"
namespace test_vendor_lib {
+using ::bluetooth::hci::Address;
+using ::bluetooth::hci::ClassOfDevice;
+
class DeviceProperties {
public:
explicit DeviceProperties(const std::string& file_name = "");
@@ -45,8 +50,9 @@
return extended_features_[0];
}
- void SetSupportedFeatures(uint64_t features) {
- extended_features_[0] = features;
+ void SetExtendedFeatures(uint64_t features, uint8_t page_number) {
+ ASSERT(page_number < extended_features_.size());
+ extended_features_[page_number] = features;
}
// Specification Version 4.2, Volume 2, Part E, Section 7.4.4
@@ -55,7 +61,7 @@
}
uint64_t GetExtendedFeatures(uint8_t page_number) const {
- CHECK(page_number < extended_features_.size());
+ ASSERT(page_number < extended_features_.size());
return extended_features_[page_number];
}
@@ -68,6 +74,8 @@
return sco_data_packet_size_;
}
+ uint8_t GetEncryptionKeySize() const { return encryption_key_size_; }
+
uint16_t GetTotalNumAclDataPackets() const {
return num_acl_data_packets_;
}
@@ -138,12 +146,13 @@
}
void SetName(const std::vector<uint8_t>& name) {
- name_ = name;
+ name_.fill(0);
+ for (size_t i = 0; i < 248 && i < name.size(); i++) {
+ name_[i] = name[i];
+ }
}
- const std::vector<uint8_t>& GetName() const {
- return name_;
- }
+ const std::array<uint8_t, 248>& GetName() const { return name_; }
void SetExtendedInquiryData(const std::vector<uint8_t>& eid) {
extended_inquiry_data_ = eid;
@@ -190,6 +199,47 @@
return le_advertisement_type_;
}
+ uint16_t GetLeAdvertisingIntervalMin() const {
+ return le_advertising_interval_min_;
+ }
+
+ uint16_t GetLeAdvertisingIntervalMax() const {
+ return le_advertising_interval_max_;
+ }
+
+ uint8_t GetLeAdvertisingOwnAddressType() const {
+ return le_advertising_own_address_type_;
+ }
+
+ uint8_t GetLeAdvertisingPeerAddressType() const {
+ return le_advertising_peer_address_type_;
+ }
+
+ Address GetLeAdvertisingPeerAddress() const {
+ return le_advertising_peer_address_;
+ }
+
+ uint8_t GetLeAdvertisingChannelMap() const {
+ return le_advertising_channel_map_;
+ }
+
+ uint8_t GetLeAdvertisingFilterPolicy() const {
+ return le_advertising_filter_policy_;
+ }
+
+ void SetLeAdvertisingParameters(uint16_t interval_min, uint16_t interval_max, uint8_t ad_type,
+ uint8_t own_address_type, uint8_t peer_address_type, Address peer_address,
+ uint8_t channel_map, uint8_t filter_policy) {
+ le_advertisement_type_ = ad_type;
+ le_advertising_interval_min_ = interval_min;
+ le_advertising_interval_max_ = interval_max;
+ le_advertising_own_address_type_ = own_address_type;
+ le_advertising_peer_address_type_ = peer_address_type;
+ le_advertising_peer_address_ = peer_address;
+ le_advertising_channel_map_ = channel_map;
+ le_advertising_filter_policy_ = filter_policy;
+ }
+
void SetLeAdvertisementType(uint8_t ad_type) {
le_advertisement_type_ = ad_type;
}
@@ -238,6 +288,9 @@
return le_supported_states_;
}
+ // Specification Version 4.2, Volume 2, Part E, Section 7.8.41
+ uint8_t GetLeResolvingListSize() const { return le_resolving_list_size_; }
+
// Vendor-specific commands
const std::vector<uint8_t>& GetLeVendorCap() const {
return le_vendor_cap_;
@@ -261,23 +314,33 @@
std::vector<uint8_t> supported_codecs_;
std::vector<uint32_t> vendor_specific_codecs_;
std::vector<uint8_t> supported_commands_;
- std::vector<uint64_t> extended_features_{{0x875b3fd8fe8ffeff, 0x07}};
+ std::vector<uint64_t> extended_features_{{0x875b3fd8fe8ffeff, 0x0f}};
ClassOfDevice class_of_device_{{0, 0, 0}};
std::vector<uint8_t> extended_inquiry_data_;
- std::vector<uint8_t> name_;
+ std::array<uint8_t, 248> name_;
Address address_;
uint8_t page_scan_repetition_mode_;
uint16_t clock_offset_;
+ uint8_t encryption_key_size_{10};
// Low Energy
uint16_t le_data_packet_length_;
uint8_t num_le_data_packets_;
uint8_t le_white_list_size_;
+ uint8_t le_resolving_list_size_;
uint64_t le_supported_features_{0x075b3fd8fe8ffeff};
uint64_t le_supported_states_;
std::vector<uint8_t> le_vendor_cap_;
Address le_address_;
uint8_t le_address_type_;
+
+ uint16_t le_advertising_interval_min_;
+ uint16_t le_advertising_interval_max_;
+ uint8_t le_advertising_own_address_type_;
+ uint8_t le_advertising_peer_address_type_;
+ Address le_advertising_peer_address_;
+ uint8_t le_advertising_channel_map_;
+ uint8_t le_advertising_filter_policy_;
uint8_t le_advertisement_type_;
std::vector<uint8_t> le_advertisement_;
std::vector<uint8_t> le_scan_response_;
diff --git a/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.cc b/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.cc
index 49e8727..3591fbb 100644
--- a/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.cc
@@ -16,15 +16,14 @@
#include "h4_packetizer.h"
-#define LOG_TAG "h4_packetizer"
-
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
-#include <log/log.h>
#include <sys/uio.h>
#include <unistd.h>
+#include "os/log.h"
+
namespace test_vendor_lib {
namespace hci {
constexpr size_t H4Packetizer::COMMAND_PREAMBLE_SIZE;
@@ -53,8 +52,9 @@
}
H4Packetizer::H4Packetizer(int fd, PacketReadCallback command_cb, PacketReadCallback event_cb,
- PacketReadCallback acl_cb, PacketReadCallback sco_cb)
- : uart_fd_(fd), command_cb_(command_cb), event_cb_(event_cb), acl_cb_(acl_cb), sco_cb_(sco_cb) {}
+ PacketReadCallback acl_cb, PacketReadCallback sco_cb, ClientDisconnectCallback disconnect_cb)
+ : uart_fd_(fd), command_cb_(command_cb), event_cb_(event_cb), acl_cb_(acl_cb), sco_cb_(sco_cb),
+ disconnect_cb_(disconnect_cb) {}
size_t H4Packetizer::Send(uint8_t type, const uint8_t* data, size_t length) {
struct iovec iov[] = {{&type, sizeof(type)}, {const_cast<uint8_t*>(data), length}};
@@ -64,16 +64,15 @@
} while (-1 == ret && EAGAIN == errno);
if (ret == -1) {
- ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
+ LOG_ERROR("%s error writing to UART (%s)", __func__, strerror(errno));
} else if (ret < static_cast<ssize_t>(length + 1)) {
- ALOGE("%s: %d / %d bytes written - something went wrong...", __func__, static_cast<int>(ret),
- static_cast<int>(length + 1));
+ LOG_ERROR("%s: %d / %d bytes written - something went wrong...", __func__, static_cast<int>(ret),
+ static_cast<int>(length + 1));
}
return ret;
}
void H4Packetizer::OnPacketReady() {
- ALOGE("%s: before switch", __func__);
switch (hci_packet_type_) {
case hci::PacketType::COMMAND:
command_cb_(packet_);
@@ -98,20 +97,19 @@
if (hci_packet_type_ == hci::PacketType::UNKNOWN) {
uint8_t buffer[1] = {0};
ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, 1));
- if (bytes_read != 1) {
- if (bytes_read == 0) {
- ALOGI("%s: Nothing ready, will retry!", __func__);
+ if (bytes_read == 0) {
+ LOG_INFO("%s: remote disconnected!", __func__);
+ disconnect_cb_();
+ return;
+ } else if (bytes_read < 0) {
+ if (errno == EAGAIN) {
+ // No data, try again later.
return;
- } else if (bytes_read < 0) {
- if (errno == EAGAIN) {
- // No data, try again later.
- return;
- } else {
- LOG_ALWAYS_FATAL("%s: Read packet type error: %s", __func__, strerror(errno));
- }
} else {
- LOG_ALWAYS_FATAL("%s: More bytes read than expected (%u)!", __func__, static_cast<unsigned int>(bytes_read));
+ LOG_ALWAYS_FATAL("%s: Read packet type error: %s", __func__, strerror(errno));
}
+ } else if (bytes_read > 1) {
+ LOG_ALWAYS_FATAL("%s: More bytes read than expected (%u)!", __func__, static_cast<unsigned int>(bytes_read));
}
hci_packet_type_ = static_cast<hci::PacketType>(buffer[0]);
if (hci_packet_type_ != hci::PacketType::ACL && hci_packet_type_ != hci::PacketType::SCO &&
@@ -132,7 +130,7 @@
size_t preamble_bytes = preamble_size[static_cast<size_t>(hci_packet_type_)];
ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, preamble_ + bytes_read_, preamble_bytes - bytes_read_));
if (bytes_read == 0) {
- ALOGE("%s: Will try again to read the header!", __func__);
+ LOG_ERROR("%s: Will try again to read the header!", __func__);
return;
}
if (bytes_read < 0) {
@@ -147,8 +145,6 @@
size_t packet_length = HciGetPacketLengthForType(hci_packet_type_, preamble_);
packet_.resize(preamble_bytes + packet_length);
memcpy(packet_.data(), preamble_, preamble_bytes);
- ALOGI("%s: Read a preamble of size %d length %d %0x %0x %0x", __func__, static_cast<int>(bytes_read_),
- static_cast<int>(packet_length), preamble_[0], preamble_[1], preamble_[2]);
bytes_remaining_ = packet_length;
if (bytes_remaining_ == 0) {
OnPacketReady();
@@ -167,7 +163,7 @@
ssize_t bytes_read =
TEMP_FAILURE_RETRY(read(fd, packet_.data() + preamble_bytes + bytes_read_, bytes_remaining_));
if (bytes_read == 0) {
- ALOGI("%s: Will try again to read the payload!", __func__);
+ LOG_INFO("%s: Will try again to read the payload!", __func__);
return;
}
if (bytes_read < 0) {
diff --git a/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.h b/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.h
index f81cf77..c8b7917 100644
--- a/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.h
+++ b/vendor_libs/test_vendor_lib/model/devices/h4_packetizer.h
@@ -26,11 +26,12 @@
namespace hci {
using HciPacketReadyCallback = std::function<void(void)>;
+using ClientDisconnectCallback = std::function<void()>;
class H4Packetizer : public HciProtocol {
public:
H4Packetizer(int fd, PacketReadCallback command_cb, PacketReadCallback event_cb, PacketReadCallback acl_cb,
- PacketReadCallback sco_cb);
+ PacketReadCallback sco_cb, ClientDisconnectCallback disconnect_cb);
size_t Send(uint8_t type, const uint8_t* data, size_t length);
@@ -46,6 +47,8 @@
PacketReadCallback acl_cb_;
PacketReadCallback sco_cb_;
+ ClientDisconnectCallback disconnect_cb_;
+
hci::PacketType hci_packet_type_{hci::PacketType::UNKNOWN};
// 2 bytes for opcode, 1 byte for parameter length (Volume 2, Part E, 5.4.1)
diff --git a/vendor_libs/test_vendor_lib/model/devices/h4_protocol.cc b/vendor_libs/test_vendor_lib/model/devices/h4_protocol.cc
index c4704ea..7ba432d 100644
--- a/vendor_libs/test_vendor_lib/model/devices/h4_protocol.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/h4_protocol.cc
@@ -16,14 +16,13 @@
#include "h4_protocol.h"
-#define LOG_TAG "hci-h4_protocol"
-
#include <errno.h>
#include <fcntl.h>
-#include <log/log.h>
#include <sys/uio.h>
#include <unistd.h>
+#include "os/log.h"
+
namespace test_vendor_lib {
namespace hci {
@@ -31,7 +30,7 @@
PacketReadCallback sco_cb)
: uart_fd_(fd), command_cb_(command_cb), event_cb_(event_cb), acl_cb_(acl_cb), sco_cb_(sco_cb),
hci_packetizer_([this]() {
- ALOGI("in lambda");
+ LOG_INFO("in lambda");
this->OnPacketReady();
}) {}
@@ -43,16 +42,16 @@
} while (-1 == ret && EAGAIN == errno);
if (ret == -1) {
- ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
+ LOG_ERROR("%s error writing to UART (%s)", __func__, strerror(errno));
} else if (ret < static_cast<ssize_t>(length + 1)) {
- ALOGE("%s: %d / %d bytes written - something went wrong...", __func__, static_cast<int>(ret),
- static_cast<int>(length + 1));
+ LOG_ERROR("%s: %d / %d bytes written - something went wrong...", __func__, static_cast<int>(ret),
+ static_cast<int>(length + 1));
}
return ret;
}
void H4Protocol::OnPacketReady() {
- ALOGE("%s: before switch", __func__);
+ LOG_ERROR("%s: before switch", __func__);
switch (hci_packet_type_) {
case hci::PacketType::COMMAND:
command_cb_(hci_packetizer_.GetPacket());
@@ -79,7 +78,7 @@
ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, 1));
if (bytes_read != 1) {
if (bytes_read == 0) {
- ALOGI("%s: Nothing ready, will retry!", __func__);
+ LOG_INFO("%s: Nothing ready, will retry!", __func__);
return;
} else if (bytes_read < 0) {
if (errno == EAGAIN) {
diff --git a/vendor_libs/test_vendor_lib/model/devices/hci_packetizer.cc b/vendor_libs/test_vendor_lib/model/devices/hci_packetizer.cc
index cca7780..e0c4e4a 100644
--- a/vendor_libs/test_vendor_lib/model/devices/hci_packetizer.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/hci_packetizer.cc
@@ -16,14 +16,13 @@
#include "hci_packetizer.h"
-#define LOG_TAG "hci_packetizer"
-
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
-#include <log/log.h>
#include <unistd.h>
+#include "os/log.h"
+
namespace test_vendor_lib {
namespace hci {
constexpr size_t HciPacketizer::COMMAND_PREAMBLE_SIZE;
@@ -69,7 +68,7 @@
ssize_t bytes_read = TEMP_FAILURE_RETRY(
read(fd, preamble_ + bytes_read_, preamble_size[static_cast<uint8_t>(packet_type)] - bytes_read_));
if (bytes_read == 0) {
- ALOGE("%s: Will try again to read the header!", __func__);
+ LOG_ERROR("%s: Will try again to read the header!", __func__);
return;
}
if (bytes_read < 0) {
@@ -77,15 +76,15 @@
if (errno == EAGAIN) {
return;
}
- LOG_ALWAYS_FATAL("%s: Read header error: %s", __func__, strerror(errno));
+ LOG_ALWAYS_FATAL("Read header error: %s", strerror(errno));
}
bytes_read_ += bytes_read;
if (bytes_read_ == preamble_size[static_cast<uint8_t>(packet_type)]) {
size_t packet_length = HciGetPacketLengthForType(packet_type, preamble_);
packet_.resize(preamble_size[static_cast<uint8_t>(packet_type)] + packet_length);
memcpy(packet_.data(), preamble_, preamble_size[static_cast<uint8_t>(packet_type)]);
- ALOGI("%s: Read a preamble of size %d length %d %0x %0x %0x", __func__, static_cast<int>(bytes_read_),
- static_cast<int>(packet_length), preamble_[0], preamble_[1], preamble_[2]);
+ LOG_INFO("%s: Read a preamble of size %d length %d %0x %0x %0x", __func__, static_cast<int>(bytes_read_),
+ static_cast<int>(packet_length), preamble_[0], preamble_[1], preamble_[2]);
bytes_remaining_ = packet_length;
if (bytes_remaining_ == 0) {
packet_ready_cb_();
@@ -103,7 +102,7 @@
ssize_t bytes_read = TEMP_FAILURE_RETRY(
read(fd, packet_.data() + preamble_size[static_cast<uint8_t>(packet_type)] + bytes_read_, bytes_remaining_));
if (bytes_read == 0) {
- ALOGI("%s: Will try again to read the payload!", __func__);
+ LOG_INFO("Will try again to read the payload!");
return;
}
if (bytes_read < 0) {
@@ -111,7 +110,7 @@
if (errno == EAGAIN) {
return;
}
- LOG_ALWAYS_FATAL("%s: Read payload error: %s", __func__, strerror(errno));
+ LOG_ALWAYS_FATAL("Read payload error: %s", strerror(errno));
}
bytes_remaining_ -= bytes_read;
bytes_read_ += bytes_read;
diff --git a/vendor_libs/test_vendor_lib/model/devices/hci_protocol.cc b/vendor_libs/test_vendor_lib/model/devices/hci_protocol.cc
index e01bfa5..d2ef535 100644
--- a/vendor_libs/test_vendor_lib/model/devices/hci_protocol.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/hci_protocol.cc
@@ -16,13 +16,13 @@
#include "hci_protocol.h"
-#define LOG_TAG "hci-hci_protocol"
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
-#include <log/log.h>
#include <unistd.h>
+#include "os/log.h"
+
namespace test_vendor_lib {
namespace hci {
@@ -33,12 +33,12 @@
if (ret == -1) {
if (errno == EAGAIN) continue;
- ALOGE("%s error writing to UART (%s)", __func__, strerror(errno));
+ LOG_ERROR("%s error writing to UART (%s)", __func__, strerror(errno));
break;
} else if (ret == 0) {
// Nothing written :(
- ALOGE("%s zero bytes written - something went wrong...", __func__);
+ LOG_ERROR("%s zero bytes written - something went wrong...", __func__);
break;
}
diff --git a/vendor_libs/test_vendor_lib/model/devices/hci_socket_device.cc b/vendor_libs/test_vendor_lib/model/devices/hci_socket_device.cc
index e146fcc..6865714 100644
--- a/vendor_libs/test_vendor_lib/model/devices/hci_socket_device.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/hci_socket_device.cc
@@ -14,24 +14,21 @@
* limitations under the License.
*/
-#define LOG_TAG "hci_socket_device"
-
#include "hci_socket_device.h"
#include <fcntl.h>
#include <netinet/in.h>
#include <sys/socket.h>
-#include "osi/include/log.h"
-
#include "model/setup/device_boutique.h"
+#include "os/log.h"
using std::vector;
namespace test_vendor_lib {
HciSocketDevice::HciSocketDevice(int file_descriptor) : socket_file_descriptor_(file_descriptor) {
- advertising_interval_ms_ = std::chrono::milliseconds(0);
+ advertising_interval_ms_ = std::chrono::milliseconds(1000);
page_scan_delay_ms_ = std::chrono::milliseconds(600);
@@ -77,57 +74,54 @@
h4_ = hci::H4Packetizer(
socket_file_descriptor_,
[this](const std::vector<uint8_t>& raw_command) {
- LOG_INFO(LOG_TAG, "Rx Command");
std::shared_ptr<std::vector<uint8_t>> packet_copy = std::make_shared<std::vector<uint8_t>>(raw_command);
HandleCommand(packet_copy);
},
- [](const std::vector<uint8_t>&) { CHECK(false) << "Unexpected Event in HciSocketDevice!"; },
+ [](const std::vector<uint8_t>&) { LOG_ALWAYS_FATAL("Unexpected Event in HciSocketDevice!"); },
[this](const std::vector<uint8_t>& raw_acl) {
- LOG_INFO(LOG_TAG, "Rx ACL");
std::shared_ptr<std::vector<uint8_t>> packet_copy = std::make_shared<std::vector<uint8_t>>(raw_acl);
HandleAcl(packet_copy);
},
[this](const std::vector<uint8_t>& raw_sco) {
- LOG_INFO(LOG_TAG, "Rx SCO");
std::shared_ptr<std::vector<uint8_t>> packet_copy = std::make_shared<std::vector<uint8_t>>(raw_sco);
HandleSco(packet_copy);
+ },
+ [this]() {
+ LOG_INFO("HCI socket device disconnected");
+ close_callback_();
});
RegisterEventChannel([this](std::shared_ptr<std::vector<uint8_t>> packet) {
- LOG_INFO(LOG_TAG, "Tx Event");
SendHci(hci::PacketType::EVENT, packet);
});
- RegisterAclChannel([this](std::shared_ptr<std::vector<uint8_t>> packet) {
- LOG_INFO(LOG_TAG, "Tx ACL");
- SendHci(hci::PacketType::ACL, packet);
- });
- RegisterScoChannel([this](std::shared_ptr<std::vector<uint8_t>> packet) {
- LOG_INFO(LOG_TAG, "Tx SCO");
- SendHci(hci::PacketType::SCO, packet);
- });
+ RegisterAclChannel([this](std::shared_ptr<std::vector<uint8_t>> packet) { SendHci(hci::PacketType::ACL, packet); });
+ RegisterScoChannel([this](std::shared_ptr<std::vector<uint8_t>> packet) { SendHci(hci::PacketType::SCO, packet); });
}
void HciSocketDevice::TimerTick() {
- LOG_INFO(LOG_TAG, "TimerTick fd = %d", socket_file_descriptor_);
h4_.OnDataReady(socket_file_descriptor_);
DualModeController::TimerTick();
}
void HciSocketDevice::SendHci(hci::PacketType packet_type, const std::shared_ptr<std::vector<uint8_t>> packet) {
if (socket_file_descriptor_ == -1) {
- LOG_INFO(LOG_TAG, "socket_file_descriptor == -1");
+ LOG_INFO("socket_file_descriptor == -1");
return;
}
uint8_t type = static_cast<uint8_t>(packet_type);
int bytes_written;
bytes_written = write(socket_file_descriptor_, &type, sizeof(type));
if (bytes_written != sizeof(type)) {
- LOG_INFO(LOG_TAG, "bytes_written %d != sizeof(type)", bytes_written);
+ LOG_WARN("bytes_written %d != sizeof(type)", bytes_written);
}
bytes_written = write(socket_file_descriptor_, packet->data(), packet->size());
if (static_cast<size_t>(bytes_written) != packet->size()) {
- LOG_INFO(LOG_TAG, "bytes_written %d != packet->size", bytes_written);
+ LOG_WARN("bytes_written %d != packet->size", bytes_written);
}
}
+void HciSocketDevice::RegisterCloseCallback(std::function<void()> close_callback) {
+ close_callback_ = close_callback;
+}
+
} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/hci_socket_device.h b/vendor_libs/test_vendor_lib/model/devices/hci_socket_device.h
index 11eddae..0a3bb3b 100644
--- a/vendor_libs/test_vendor_lib/model/devices/hci_socket_device.h
+++ b/vendor_libs/test_vendor_lib/model/devices/hci_socket_device.h
@@ -45,10 +45,18 @@
void SendHci(hci::PacketType packet_type, const std::shared_ptr<std::vector<uint8_t>> packet);
+ void RegisterCloseCallback(std::function<void()>);
+
private:
int socket_file_descriptor_{-1};
- hci::H4Packetizer h4_{socket_file_descriptor_, [](const std::vector<uint8_t>&) {}, [](const std::vector<uint8_t>&) {},
- [](const std::vector<uint8_t>&) {}, [](const std::vector<uint8_t>&) {}};
+ hci::H4Packetizer h4_{socket_file_descriptor_,
+ [](const std::vector<uint8_t>&) {},
+ [](const std::vector<uint8_t>&) {},
+ [](const std::vector<uint8_t>&) {},
+ [](const std::vector<uint8_t>&) {},
+ [] {}};
+
+ std::function<void()> close_callback_;
};
} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/keyboard.cc b/vendor_libs/test_vendor_lib/model/devices/keyboard.cc
index 2cfc992..1244d3e 100644
--- a/vendor_libs/test_vendor_lib/model/devices/keyboard.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/keyboard.cc
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "keyboard"
-
#include "keyboard.h"
#include "model/setup/device_boutique.h"
@@ -23,12 +21,12 @@
using std::vector;
namespace test_vendor_lib {
-bool Keyboard::registered_ = DeviceBoutique::Register(LOG_TAG, &Keyboard::Create);
+bool Keyboard::registered_ = DeviceBoutique::Register("keyboard", &Keyboard::Create);
Keyboard::Keyboard() {
- properties_.SetLeAdvertisementType(BTM_BLE_CONNECT_EVT);
+ properties_.SetLeAdvertisementType(0x00 /* CONNECTABLE */);
properties_.SetLeAdvertisement({0x11, // Length
- BTM_BLE_AD_TYPE_NAME_CMPL,
+ 0x09 /* TYPE_NAME_CMPL */,
'g',
'D',
'e',
@@ -54,11 +52,11 @@
0x12,
0x18,
0x02, // Length
- BTM_BLE_AD_TYPE_FLAG,
- BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG});
+ 0x01 /* TYPE_FLAGS */,
+ 0x04 /* BREDR_NOT_SPT */ | 0x02 /* GEN_DISC_FLAG */});
properties_.SetLeScanResponse({0x04, // Length
- BTM_BLE_AD_TYPE_NAME_SHORT, 'k', 'e', 'y'});
+ 0x08 /* TYPE_NAME_SHORT */, 'k', 'e', 'y'});
}
std::string Keyboard::GetTypeString() const {
@@ -82,7 +80,7 @@
}
}
-void Keyboard::IncomingPacket(packets::LinkLayerPacketView packet) {
+void Keyboard::IncomingPacket(model::packets::LinkLayerPacketView packet) {
if (!connected_) {
Beacon::IncomingPacket(packet);
}
diff --git a/vendor_libs/test_vendor_lib/model/devices/keyboard.h b/vendor_libs/test_vendor_lib/model/devices/keyboard.h
index 871fa52..cf00dfe 100644
--- a/vendor_libs/test_vendor_lib/model/devices/keyboard.h
+++ b/vendor_libs/test_vendor_lib/model/devices/keyboard.h
@@ -40,7 +40,8 @@
// Initialize the device based on the values of |args|.
virtual void Initialize(const std::vector<std::string>& args) override;
- virtual void IncomingPacket(packets::LinkLayerPacketView packet) override;
+ virtual void IncomingPacket(
+ model::packets::LinkLayerPacketView packet) override;
virtual void TimerTick() override;
diff --git a/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.cc b/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.cc
index 9ccfd61..ddff51b 100644
--- a/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.cc
@@ -14,17 +14,13 @@
* limitations under the License.
*/
-#define LOG_TAG "link_layer_socket_device"
-
#include "link_layer_socket_device.h"
#include <unistd.h>
-#include "osi/include/log.h"
-#include "packets/link_layer/link_layer_packet_builder.h"
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-#include "packets/view.h"
+#include "packet/packet_view.h"
+#include "packet/raw_builder.h"
+#include "packet/view.h"
using std::vector;
@@ -35,16 +31,18 @@
void LinkLayerSocketDevice::TimerTick() {
if (bytes_left_ == 0) {
- received_ = std::make_shared<std::vector<uint8_t>>(Link::kSizeBytes);
- size_t bytes_received = socket_.TryReceive(Link::kSizeBytes, received_->data());
+ auto packet_size = std::make_shared<std::vector<uint8_t>>(kSizeBytes);
+
+ size_t bytes_received = socket_.TryReceive(kSizeBytes, packet_size->data());
if (bytes_received == 0) {
return;
}
- CHECK(bytes_received == Link::kSizeBytes) << "bytes_received == " << bytes_received;
- packets::PacketView<true> size({packets::View(received_, 0, Link::kSizeBytes)});
+ ASSERT_LOG(bytes_received == kSizeBytes, "bytes_received == %d", static_cast<int>(bytes_received));
+ bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> size(
+ {bluetooth::packet::View(packet_size, 0, kSizeBytes)});
bytes_left_ = size.begin().extract<uint32_t>();
- received_->resize(Link::kSizeBytes + bytes_left_);
- offset_ = Link::kSizeBytes;
+ received_ = std::make_shared<std::vector<uint8_t>>(bytes_left_);
+ offset_ = 0;
}
size_t bytes_received = socket_.TryReceive(bytes_left_, received_->data() + offset_);
if (bytes_received == 0) {
@@ -53,14 +51,28 @@
bytes_left_ -= bytes_received;
offset_ += bytes_received;
if (bytes_left_ == 0) {
- SendLinkLayerPacket(packets::LinkLayerPacketBuilder::ReWrap(received_), phy_type_);
+ bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian> packet_view(
+ received_);
+ auto packet = model::packets::LinkLayerPacketView::Create(packet_view);
+ ASSERT(packet.IsValid());
+ SendLinkLayerPacket(packet, phy_type_);
offset_ = 0;
received_.reset();
}
}
-void LinkLayerSocketDevice::IncomingPacket(packets::LinkLayerPacketView packet) {
- socket_.TrySend(packet);
+void LinkLayerSocketDevice::IncomingPacket(
+ model::packets::LinkLayerPacketView packet) {
+ auto size_packet = bluetooth::packet::RawBuilder();
+ size_packet.AddOctets4(packet.size());
+ std::vector<uint8_t> size_bytes;
+ bluetooth::packet::BitInserter bit_inserter(size_bytes);
+ size_packet.Serialize(bit_inserter);
+
+ if (socket_.TrySend(size_bytes) == kSizeBytes) {
+ std::vector<uint8_t> payload_bytes{packet.begin(), packet.end()};
+ socket_.TrySend(payload_bytes);
+ }
}
} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.h b/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.h
index d3bbb2e..564233c 100644
--- a/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.h
+++ b/vendor_libs/test_vendor_lib/model/devices/link_layer_socket_device.h
@@ -20,9 +20,8 @@
#include <vector>
#include "device.h"
-#include "include/link.h"
#include "include/phy.h"
-#include "packets/link_layer/link_layer_packet_view.h"
+#include "packets/link_layer_packets.h"
#include "polled_socket.h"
namespace test_vendor_lib {
@@ -43,17 +42,20 @@
virtual void Initialize(const std::vector<std::string>&) override {}
- virtual void IncomingPacket(packets::LinkLayerPacketView packet) override;
+ virtual void IncomingPacket(
+ model::packets::LinkLayerPacketView packet) override;
virtual void TimerTick() override;
+ static constexpr size_t kSizeBytes = sizeof(uint32_t);
+
private:
net::PolledSocket socket_;
Phy::Type phy_type_;
size_t bytes_left_{0};
size_t offset_;
std::shared_ptr<std::vector<uint8_t>> received_;
- std::vector<packets::LinkLayerPacketView> packet_queue_;
+ std::vector<model::packets::LinkLayerPacketView> packet_queue_;
};
} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/loopback.cc b/vendor_libs/test_vendor_lib/model/devices/loopback.cc
index 4d9078e..df0c762 100644
--- a/vendor_libs/test_vendor_lib/model/devices/loopback.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/loopback.cc
@@ -14,47 +14,33 @@
* limitations under the License.
*/
-#define LOG_TAG "loopback"
-
#include "loopback.h"
#include "le_advertisement.h"
#include "model/setup/device_boutique.h"
-#include "osi/include/log.h"
+#include "os/log.h"
using std::vector;
namespace test_vendor_lib {
-bool Loopback::registered_ = DeviceBoutique::Register(LOG_TAG, &Loopback::Create);
+bool Loopback::registered_ = DeviceBoutique::Register("loopback", &Loopback::Create);
Loopback::Loopback() {
advertising_interval_ms_ = std::chrono::milliseconds(1280);
- properties_.SetLeAdvertisementType(BTM_BLE_NON_CONNECT_EVT);
- properties_.SetLeAdvertisement({0x11, // Length
- BTM_BLE_AD_TYPE_NAME_CMPL,
- 'g',
- 'D',
- 'e',
- 'v',
- 'i',
- 'c',
- 'e',
- '-',
- 'l',
- 'o',
- 'o',
- 'p',
- 'b',
- 'a',
- 'c',
- 'k',
- 0x02, // Length
- BTM_BLE_AD_TYPE_FLAG,
- BTM_BLE_BREDR_NOT_SPT | BTM_BLE_GEN_DISC_FLAG});
+ properties_.SetLeAdvertisementType(0x03); // NON_CONNECT
+ properties_.SetLeAdvertisement({
+ 0x11, // Length
+ 0x09, // NAME_CMPL
+ 'g', 'D', 'e', 'v', 'i', 'c', 'e', '-', 'l', 'o', 'o', 'p', 'b', 'a', 'c', 'k',
+ 0x02, // Length
+ 0x01, // TYPE_FLAG
+ 0x04 | 0x02, // BREDR_NOT_SPT | GEN_DISC
+ });
properties_.SetLeScanResponse({0x05, // Length
- BTM_BLE_AD_TYPE_NAME_SHORT, 'l', 'o', 'o', 'p'});
+ 0x08, // NAME_SHORT
+ 'l', 'o', 'o', 'p'});
}
std::string Loopback::GetTypeString() const {
@@ -80,18 +66,22 @@
void Loopback::TimerTick() {}
-void Loopback::IncomingPacket(packets::LinkLayerPacketView packet) {
- LOG_INFO(LOG_TAG, "Got a packet of type %d", static_cast<int>(packet.GetType()));
- if (packet.GetDestinationAddress() == properties_.GetLeAddress() && packet.GetType() == Link::PacketType::LE_SCAN) {
- LOG_INFO(LOG_TAG, "Got a scan");
- std::unique_ptr<packets::LeAdvertisementBuilder> scan_response = packets::LeAdvertisementBuilder::Create(
- LeAdvertisement::AddressType::PUBLIC, LeAdvertisement::AdvertisementType::SCAN_RESPONSE,
+void Loopback::IncomingPacket(model::packets::LinkLayerPacketView packet) {
+ LOG_INFO("Got a packet of type %d", static_cast<int>(packet.GetType()));
+ if (packet.GetDestinationAddress() == properties_.GetLeAddress() &&
+ packet.GetType() == model::packets::PacketType::LE_SCAN) {
+ LOG_INFO("Got a scan");
+
+ auto scan_response = model::packets::LeScanResponseBuilder::Create(
+ properties_.GetLeAddress(), packet.GetSourceAddress(),
+ model::packets::AddressType::PUBLIC,
+ model::packets::AdvertisementType::SCAN_RESPONSE,
properties_.GetLeScanResponse());
- std::shared_ptr<packets::LinkLayerPacketBuilder> to_send = packets::LinkLayerPacketBuilder::WrapLeScanResponse(
- std::move(scan_response), properties_.GetLeAddress(), packet.GetSourceAddress());
- std::vector<std::shared_ptr<PhyLayer>> le_phys = phy_layers_[Phy::Type::LOW_ENERGY];
- for (auto phy : le_phys) {
- LOG_INFO(LOG_TAG, "Sending a Scan Response on a Phy");
+ std::shared_ptr<model::packets::LinkLayerPacketBuilder> to_send =
+ std::move(scan_response);
+
+ for (auto phy : phy_layers_[Phy::Type::LOW_ENERGY]) {
+ LOG_INFO("Sending a Scan Response on a Phy");
phy->Send(to_send);
}
}
diff --git a/vendor_libs/test_vendor_lib/model/devices/loopback.h b/vendor_libs/test_vendor_lib/model/devices/loopback.h
index 31dd1cd..dd5c069 100644
--- a/vendor_libs/test_vendor_lib/model/devices/loopback.h
+++ b/vendor_libs/test_vendor_lib/model/devices/loopback.h
@@ -42,7 +42,8 @@
// Set the address and advertising interval from string args.
virtual void Initialize(const std::vector<std::string>& args) override;
- virtual void IncomingPacket(packets::LinkLayerPacketView packet) override;
+ virtual void IncomingPacket(
+ model::packets::LinkLayerPacketView packet) override;
virtual void TimerTick() override;
diff --git a/vendor_libs/test_vendor_lib/model/devices/polled_socket.cc b/vendor_libs/test_vendor_lib/model/devices/polled_socket.cc
index 5719132..6fea766 100644
--- a/vendor_libs/test_vendor_lib/model/devices/polled_socket.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/polled_socket.cc
@@ -14,11 +14,8 @@
* limitations under the License.
*/
-#define LOG_TAG "polled_socket"
-
#include "polled_socket.h"
-#include <base/logging.h>
#include <fcntl.h>
#include <netdb.h>
#include <netinet/in.h>
@@ -26,7 +23,7 @@
#include <sys/types.h>
#include <sys/uio.h>
-#include "osi/include/log.h"
+#include "os/log.h"
namespace test_vendor_lib {
namespace net {
@@ -48,19 +45,13 @@
file_descriptor_ = -1;
}
-size_t PolledSocket::TrySend(packets::PacketView<true> packet) {
+size_t PolledSocket::TrySend(const std::vector<uint8_t>& packet) {
if (file_descriptor_ == -1) {
return 0;
}
- // Could skip this copy if the packet is guaranteed to be contiguous.
- std::vector<uint8_t> copy;
- copy.reserve(packet.size());
- for (const auto&& c : packet) {
- copy.push_back(c);
- }
- int ret = write(file_descriptor_, copy.data(), copy.size());
+ int ret = write(file_descriptor_, packet.data(), packet.size());
if (ret == -1) {
- ALOGW("%s error %s", __func__, strerror(errno));
+ LOG_WARN("%s error %s", __func__, strerror(errno));
return 0;
} else {
return static_cast<size_t>(ret);
@@ -100,7 +91,7 @@
if (errno == EAGAIN) {
return 0;
} else {
- ALOGW("%s error %s", __func__, strerror(errno));
+ LOG_WARN("%s error %s", __func__, strerror(errno));
CleanUp();
return 0;
}
diff --git a/vendor_libs/test_vendor_lib/model/devices/polled_socket.h b/vendor_libs/test_vendor_lib/model/devices/polled_socket.h
index b697f56..a196fd6 100644
--- a/vendor_libs/test_vendor_lib/model/devices/polled_socket.h
+++ b/vendor_libs/test_vendor_lib/model/devices/polled_socket.h
@@ -26,8 +26,6 @@
#include <sys/socket.h>
#include <unistd.h>
-#include "packets/packet_view.h"
-
namespace test_vendor_lib {
namespace net {
@@ -41,7 +39,7 @@
PolledSocket(PolledSocket&& p);
virtual ~PolledSocket();
- size_t TrySend(packets::PacketView<true> packet);
+ size_t TrySend(const std::vector<uint8_t>& packet);
// size_t TrySendVector(const std::vector<const std::vector<uint8_t>&>& data);
size_t TryReceive(size_t num_bytes, uint8_t* data);
diff --git a/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.cc b/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.cc
index 787e2f7..db87028 100644
--- a/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.cc
@@ -14,25 +14,20 @@
* limitations under the License.
*/
-#define LOG_TAG "remote_loopback_device"
-
#include "remote_loopback_device.h"
#include "model/setup/device_boutique.h"
-
-#include "osi/include/log.h"
-#include "packets/link_layer/link_layer_packet_builder.h"
-#include "packets/link_layer/link_layer_packet_view.h"
+#include "os/log.h"
using std::vector;
namespace test_vendor_lib {
-using packets::LinkLayerPacketBuilder;
-using packets::LinkLayerPacketView;
-using packets::PageResponseBuilder;
+using model::packets::LinkLayerPacketBuilder;
+using model::packets::LinkLayerPacketView;
+using model::packets::PageResponseBuilder;
-bool RemoteLoopbackDevice::registered_ = DeviceBoutique::Register(LOG_TAG, &RemoteLoopbackDevice::Create);
+bool RemoteLoopbackDevice::registered_ = DeviceBoutique::Register("remote_loopback", &RemoteLoopbackDevice::Create);
RemoteLoopbackDevice::RemoteLoopbackDevice() {}
@@ -47,27 +42,23 @@
if (Address::FromString(args[1], addr)) properties_.SetAddress(addr);
}
-void RemoteLoopbackDevice::IncomingPacket(LinkLayerPacketView packet) {
+void RemoteLoopbackDevice::IncomingPacket(
+ model::packets::LinkLayerPacketView packet) {
// TODO: Check sender?
// TODO: Handle other packet types
Phy::Type phy_type = Phy::Type::BR_EDR;
- Link::PacketType type = packet.GetType();
+ model::packets::PacketType type = packet.GetType();
switch (type) {
- case Link::PacketType::PAGE:
- SendLinkLayerPacket(LinkLayerPacketBuilder::WrapPageResponse(
- PageResponseBuilder::Create(true), packet.GetSourceAddress(), packet.GetSourceAddress()),
- Phy::Type::BR_EDR);
+ case model::packets::PacketType::PAGE:
+ SendLinkLayerPacket(
+ PageResponseBuilder::Create(packet.GetSourceAddress(),
+ packet.GetSourceAddress(), true),
+ Phy::Type::BR_EDR);
break;
default: {
- ALOGW("Resend = %d", static_cast<int>(packet.size()));
- std::shared_ptr<std::vector<uint8_t>> extracted_packet = std::make_shared<std::vector<uint8_t>>();
- extracted_packet->reserve(packet.size());
- for (const auto byte : packet) {
- extracted_packet->push_back(byte);
- }
-
- SendLinkLayerPacket(LinkLayerPacketBuilder::ReWrap(extracted_packet), phy_type);
+ LOG_WARN("Resend = %d", static_cast<int>(packet.size()));
+ SendLinkLayerPacket(packet, phy_type);
}
}
}
diff --git a/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.h b/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.h
index 5513677..98c9a83 100644
--- a/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.h
+++ b/vendor_libs/test_vendor_lib/model/devices/remote_loopback_device.h
@@ -20,7 +20,6 @@
#include <vector>
#include "device.h"
-#include "packets/link_layer/link_layer_packet_view.h"
namespace test_vendor_lib {
@@ -41,7 +40,8 @@
virtual void Initialize(const std::vector<std::string>& args) override;
- virtual void IncomingPacket(packets::LinkLayerPacketView packet) override;
+ virtual void IncomingPacket(
+ model::packets::LinkLayerPacketView packet) override;
private:
static bool registered_;
diff --git a/vendor_libs/test_vendor_lib/model/devices/server_port_factory.cc b/vendor_libs/test_vendor_lib/model/devices/server_port_factory.cc
index 72008a6..b0b2165 100644
--- a/vendor_libs/test_vendor_lib/model/devices/server_port_factory.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/server_port_factory.cc
@@ -14,13 +14,9 @@
* limitations under the License.
*/
-#define LOG_TAG "server_port_factory"
-
#include "server_port_factory.h"
-#include <base/logging.h>
-
-#include "osi/include/log.h"
+#include "os/log.h"
#include "osi/include/osi.h"
#include <netinet/in.h>
@@ -43,23 +39,23 @@
OSI_NO_INTR(listen_fd_ = socket(AF_INET, SOCK_STREAM, 0));
if (listen_fd_ < 0) {
- LOG_INFO(LOG_TAG, "Error creating socket for test channel.");
+ LOG_INFO("Error creating socket for test channel.");
return -1;
}
- LOG_INFO(LOG_TAG, "port: %d", port);
+ LOG_INFO("port: %d", port);
listen_address.sin_family = AF_INET;
listen_address.sin_port = htons(port);
listen_address.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(listen_fd_, reinterpret_cast<sockaddr*>(&listen_address), sockaddr_in_size) < 0) {
- LOG_INFO(LOG_TAG, "Error binding test channel listener socket to address.");
+ LOG_INFO("Error binding test channel listener socket to address.");
close(listen_fd_);
return -1;
}
if (listen(listen_fd_, 1) < 0) {
- LOG_INFO(LOG_TAG, "Error listening for test channel.");
+ LOG_INFO("Error listening for test channel.");
close(listen_fd_);
return -1;
}
@@ -71,7 +67,7 @@
return;
}
if (close(listen_fd_)) {
- LOG_ERROR(LOG_TAG, "Error closing listen_fd_.");
+ LOG_ERROR("Error closing listen_fd_.");
}
listen_fd_ = -1;
}
@@ -84,16 +80,16 @@
OSI_NO_INTR(accept_fd = accept(listen_fd_, reinterpret_cast<sockaddr*>(&test_channel_address), &sockaddr_in_size));
if (accept_fd < 0) {
- LOG_INFO(LOG_TAG, "Error accepting test channel connection errno=%d (%s).", errno, strerror(errno));
+ LOG_INFO("Error accepting test channel connection errno=%d (%s).", errno, strerror(errno));
if (errno != EAGAIN && errno != EWOULDBLOCK) {
- LOG_ERROR(LOG_TAG, "Closing listen_fd_ (won't try again).");
+ LOG_ERROR("Closing listen_fd_ (won't try again).");
close(listen_fd_);
return -1;
}
}
- LOG_INFO(LOG_TAG, "accept_fd = %d.", accept_fd);
+ LOG_INFO("accept_fd = %d.", accept_fd);
return accept_fd;
}
@@ -107,7 +103,7 @@
std::string command_name(command_name_raw.begin(), command_name_raw.end());
if (command_name == "CLOSE_TEST_CHANNEL" || command_name == "") {
- LOG_INFO(LOG_TAG, "Test channel closed");
+ LOG_INFO("Test channel closed");
unwatch();
close(fd);
return;
@@ -137,9 +133,9 @@
char size_buf[4] = {static_cast<uint8_t>(size & 0xff), static_cast<uint8_t>((size >> 8) & 0xff),
static_cast<uint8_t>((size >> 16) & 0xff), static_cast<uint8_t>((size >> 24) & 0xff)};
int written = write(fd, size_buf, 4);
- CHECK(written == 4) << "What happened? written = " << written << "errno =" << errno;
+ ASSERT_LOG(written == 4, "What happened? written = %d errno = %d", written, errno);
written = write(fd, response.c_str(), size);
- CHECK(written == static_cast<int>(size)) << "What happened? written = " << written << "errno =" << errno;
+ ASSERT_LOG(written == static_cast<int>(size), "What happened? written = %d errno = %d", written, errno);
}
void ServerPortFactory::RegisterCommandHandler(
diff --git a/vendor_libs/test_vendor_lib/model/devices/sniffer.cc b/vendor_libs/test_vendor_lib/model/devices/sniffer.cc
index 903ecac..efdca87 100644
--- a/vendor_libs/test_vendor_lib/model/devices/sniffer.cc
+++ b/vendor_libs/test_vendor_lib/model/devices/sniffer.cc
@@ -14,19 +14,16 @@
* limitations under the License.
*/
-#define LOG_TAG "sniffer"
-
#include "sniffer.h"
-#include "osi/include/log.h"
-
#include "model/setup/device_boutique.h"
+#include "os/log.h"
using std::vector;
namespace test_vendor_lib {
-bool Sniffer::registered_ = DeviceBoutique::Register(LOG_TAG, &Sniffer::Create);
+bool Sniffer::registered_ = DeviceBoutique::Register("sniffer", &Sniffer::Create);
Sniffer::Sniffer() {}
@@ -42,7 +39,7 @@
void Sniffer::TimerTick() {}
-void Sniffer::IncomingPacket(packets::LinkLayerPacketView packet) {
+void Sniffer::IncomingPacket(model::packets::LinkLayerPacketView packet) {
Address source = packet.GetSourceAddress();
Address dest = packet.GetDestinationAddress();
bool match_source = device_to_sniff_ == source;
@@ -50,8 +47,10 @@
if (!match_source && !match_dest) {
return;
}
- LOG_INFO(LOG_TAG, "%s %s -> %s (Type %d)", (match_source ? (match_dest ? "<->" : "<--") : "-->"),
- source.ToString().c_str(), dest.ToString().c_str(), static_cast<int>(packet.GetType()));
+ LOG_INFO("%s %s -> %s (Type %s)",
+ (match_source ? (match_dest ? "<->" : "<--") : "-->"),
+ source.ToString().c_str(), dest.ToString().c_str(),
+ model::packets::PacketTypeText(packet.GetType()).c_str());
}
} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/devices/sniffer.h b/vendor_libs/test_vendor_lib/model/devices/sniffer.h
index 3e0cfef..a5c7277 100644
--- a/vendor_libs/test_vendor_lib/model/devices/sniffer.h
+++ b/vendor_libs/test_vendor_lib/model/devices/sniffer.h
@@ -20,11 +20,13 @@
#include <vector>
#include "device.h"
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "types/address.h"
+#include "hci/address.h"
+#include "packets/link_layer_packets.h"
namespace test_vendor_lib {
+using ::bluetooth::hci::Address;
+
class Sniffer : public Device {
public:
Sniffer();
@@ -42,7 +44,8 @@
return "sniffer";
}
- virtual void IncomingPacket(packets::LinkLayerPacketView packet) override;
+ virtual void IncomingPacket(
+ model::packets::LinkLayerPacketView packet) override;
virtual void TimerTick() override;
diff --git a/vendor_libs/test_vendor_lib/model/setup/async_manager.cc b/vendor_libs/test_vendor_lib/model/setup/async_manager.cc
index fb9b1ad..092271d 100644
--- a/vendor_libs/test_vendor_lib/model/setup/async_manager.cc
+++ b/vendor_libs/test_vendor_lib/model/setup/async_manager.cc
@@ -14,19 +14,17 @@
* limitations under the License.
*/
-#define LOG_TAG "async_manager"
-
#include "async_manager.h"
-#include "osi/include/log.h"
-
#include <algorithm>
#include <atomic>
#include <condition_variable>
#include <mutex>
#include <thread>
#include <vector>
+
#include "fcntl.h"
+#include "os/log.h"
#include "sys/select.h"
#include "unistd.h"
@@ -105,7 +103,7 @@
// start the thread if not started yet
int started = tryStartThread();
if (started != 0) {
- LOG_ERROR(LOG_TAG, "%s: Unable to start thread", __func__);
+ LOG_ERROR("%s: Unable to start thread", __func__);
return started;
}
@@ -134,7 +132,7 @@
if (std::this_thread::get_id() != thread_.get_id()) {
thread_.join();
} else {
- LOG_WARN(LOG_TAG, "%s: Starting thread stop from inside the reading thread itself", __func__);
+ LOG_WARN("%s: Starting thread stop from inside the reading thread itself", __func__);
}
{
@@ -158,10 +156,10 @@
// set up the communication channel
int pipe_fds[2];
if (pipe2(pipe_fds, O_NONBLOCK)) {
- LOG_ERROR(LOG_TAG,
- "%s:Unable to establish a communication channel to the reading "
- "thread",
- __func__);
+ LOG_ERROR(
+ "%s:Unable to establish a communication channel to the reading "
+ "thread",
+ __func__);
return -1;
}
notification_listen_fd_ = pipe_fds[0];
@@ -169,7 +167,7 @@
thread_ = std::thread([this]() { ThreadRoutine(); });
if (!thread_.joinable()) {
- LOG_ERROR(LOG_TAG, "%s: Unable to start reading thread", __func__);
+ LOG_ERROR("%s: Unable to start reading thread", __func__);
return -1;
}
return 0;
@@ -178,7 +176,7 @@
int notifyThread() {
char buffer = '0';
if (TEMP_FAILURE_RETRY(write(notification_write_fd_, &buffer, 1)) < 0) {
- LOG_ERROR(LOG_TAG, "%s: Unable to send message to reading thread", __func__);
+ LOG_ERROR("%s: Unable to send message to reading thread", __func__);
return -1;
}
return 0;
@@ -239,10 +237,10 @@
// wait until there is data available to read on some FD
int retval = select(nfds + 1, &read_fds, NULL, NULL, NULL);
if (retval <= 0) { // there was some error or a timeout
- LOG_ERROR(LOG_TAG,
- "%s: There was an error while waiting for data on the file "
- "descriptors: %s",
- __func__, strerror(errno));
+ LOG_ERROR(
+ "%s: There was an error while waiting for data on the file "
+ "descriptors: %s",
+ __func__, strerror(errno));
continue;
}
@@ -310,7 +308,7 @@
if (std::this_thread::get_id() != thread_.get_id()) {
thread_.join();
} else {
- LOG_WARN(LOG_TAG, "%s: Starting thread stop from inside the task thread itself", __func__);
+ LOG_WARN("%s: Starting thread stop from inside the task thread itself", __func__);
}
return 0;
}
@@ -371,7 +369,7 @@
// start thread if necessary
int started = tryStartThread();
if (started != 0) {
- LOG_ERROR(LOG_TAG, "%s: Unable to start thread", __func__);
+ LOG_ERROR("%s: Unable to start thread", __func__);
return kInvalidTaskId;
}
// notify the thread so that it knows of the new task
@@ -395,7 +393,7 @@
running_ = true;
thread_ = std::thread([this]() { ThreadRoutine(); });
if (!thread_.joinable()) {
- LOG_ERROR(LOG_TAG, "%s: Unable to start task thread", __func__);
+ LOG_ERROR("%s: Unable to start task thread", __func__);
return -1;
}
return 0;
diff --git a/vendor_libs/test_vendor_lib/model/setup/device_boutique.cc b/vendor_libs/test_vendor_lib/model/setup/device_boutique.cc
index 18de1b1..de3b1cc 100644
--- a/vendor_libs/test_vendor_lib/model/setup/device_boutique.cc
+++ b/vendor_libs/test_vendor_lib/model/setup/device_boutique.cc
@@ -14,12 +14,9 @@
* limitations under the License.
*/
-#define LOG_TAG "device_boutique"
-
#include "device_boutique.h"
-#include "base/logging.h"
-#include "osi/include/log.h"
+#include "os/log.h"
using std::vector;
@@ -33,16 +30,16 @@
// Register a constructor for a device type.
bool DeviceBoutique::Register(const std::string& device_type,
const std::function<std::shared_ptr<Device>()> device_constructor) {
- LOG_INFO(LOG_TAG, "Registering %s", device_type.c_str());
+ LOG_INFO("Registering %s", device_type.c_str());
GetMap()[device_type] = device_constructor;
return true;
}
std::shared_ptr<Device> DeviceBoutique::Create(const vector<std::string>& args) {
- CHECK(!args.empty());
+ ASSERT(!args.empty());
if (GetMap().find(args[0]) == GetMap().end()) {
- LOG_WARN(LOG_TAG, "No constructor registered for %s", args[0].c_str());
+ LOG_WARN("No constructor registered for %s", args[0].c_str());
return std::shared_ptr<Device>(nullptr);
}
diff --git a/vendor_libs/test_vendor_lib/model/setup/phy_layer.h b/vendor_libs/test_vendor_lib/model/setup/phy_layer.h
index 84e4cba..7f0fa33 100644
--- a/vendor_libs/test_vendor_lib/model/setup/phy_layer.h
+++ b/vendor_libs/test_vendor_lib/model/setup/phy_layer.h
@@ -17,22 +17,33 @@
#pragma once
#include "include/phy.h"
-#include "packets/link_layer/link_layer_packet_builder.h"
-#include "packets/link_layer/link_layer_packet_view.h"
+#include "packets/link_layer_packets.h"
namespace test_vendor_lib {
class PhyLayer {
public:
- PhyLayer(Phy::Type phy_type, uint32_t id, const std::function<void(packets::LinkLayerPacketView)>& device_receive)
- : phy_type_(phy_type), id_(id), transmit_to_device_(device_receive) {}
+ PhyLayer(Phy::Type phy_type, uint32_t id,
+ const std::function<void(model::packets::LinkLayerPacketView)>&
+ device_receive,
+ uint32_t device_id)
+ : phy_type_(phy_type),
+ id_(id),
+ device_id_(device_id),
+ transmit_to_device_(device_receive) {}
- virtual void Send(const std::shared_ptr<packets::LinkLayerPacketBuilder> packet) = 0;
+ virtual void Send(
+ const std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet) = 0;
+ virtual void Send(model::packets::LinkLayerPacketView packet) = 0;
- virtual void Receive(packets::LinkLayerPacketView packet) = 0;
+ virtual void Receive(model::packets::LinkLayerPacketView packet) = 0;
virtual void TimerTick() = 0;
+ virtual bool IsFactoryId(uint32_t factory_id) = 0;
+
+ virtual void Unregister() = 0;
+
Phy::Type GetType() {
return phy_type_;
}
@@ -41,14 +52,18 @@
return id_;
}
+ uint32_t GetDeviceId() { return device_id_; }
+
virtual ~PhyLayer() = default;
private:
Phy::Type phy_type_;
uint32_t id_;
+ uint32_t device_id_;
protected:
- const std::function<void(packets::LinkLayerPacketView)> transmit_to_device_;
+ const std::function<void(model::packets::LinkLayerPacketView)>
+ transmit_to_device_;
};
} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.cc b/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.cc
index 182416a..b963ce0 100644
--- a/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.cc
+++ b/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.cc
@@ -14,26 +14,29 @@
* limitations under the License.
*/
-#define LOG_TAG "phy_layer_factory"
-
#include "phy_layer_factory.h"
-
-#include "base/logging.h"
-
-#include "osi/include/log.h"
+#include <sstream>
namespace test_vendor_lib {
-PhyLayerFactory::PhyLayerFactory(Phy::Type phy_type) : phy_type_(phy_type) {}
+PhyLayerFactory::PhyLayerFactory(Phy::Type phy_type, uint32_t factory_id)
+ : phy_type_(phy_type), factory_id_(factory_id) {}
Phy::Type PhyLayerFactory::GetType() {
return phy_type_;
}
+uint32_t PhyLayerFactory::GetFactoryId() {
+ return factory_id_;
+}
+
std::shared_ptr<PhyLayer> PhyLayerFactory::GetPhyLayer(
- const std::function<void(packets::LinkLayerPacketView)>& device_receive) {
- std::shared_ptr<PhyLayer> new_phy =
- std::make_shared<PhyLayerImpl>(phy_type_, next_id_++, device_receive, std::shared_ptr<PhyLayerFactory>(this));
+ const std::function<void(model::packets::LinkLayerPacketView)>&
+ device_receive,
+ uint32_t device_id) {
+ std::shared_ptr<PhyLayer> new_phy = std::make_shared<PhyLayerImpl>(
+ phy_type_, next_id_++, device_receive, device_id,
+ std::shared_ptr<PhyLayerFactory>(this));
phy_layers_.push_back(new_phy);
return new_phy;
}
@@ -48,56 +51,87 @@
}
}
-void PhyLayerFactory::Send(const std::shared_ptr<packets::LinkLayerPacketBuilder> packet, uint32_t id) {
+void PhyLayerFactory::Send(
+ const std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet,
+ uint32_t id) {
// Convert from a Builder to a View
- std::shared_ptr<std::vector<uint8_t>> serialized_packet =
- std::shared_ptr<std::vector<uint8_t>>(new std::vector<uint8_t>());
- std::back_insert_iterator<std::vector<uint8_t>> itr(*serialized_packet);
- serialized_packet->reserve(packet->size());
- packet->Serialize(itr);
- packets::LinkLayerPacketView packet_view = packets::LinkLayerPacketView::Create(serialized_packet);
+ auto bytes = std::make_shared<std::vector<uint8_t>>();
+ bluetooth::packet::BitInserter i(*bytes);
+ bytes->reserve(packet->size());
+ packet->Serialize(i);
+ auto packet_view =
+ bluetooth::packet::PacketView<bluetooth::packet::kLittleEndian>(bytes);
+ auto link_layer_packet_view =
+ model::packets::LinkLayerPacketView::Create(packet_view);
+ ASSERT(link_layer_packet_view.IsValid());
- for (const auto phy : phy_layers_) {
+ Send(link_layer_packet_view, id);
+}
+
+void PhyLayerFactory::Send(model::packets::LinkLayerPacketView packet,
+ uint32_t id) {
+ for (const auto& phy : phy_layers_) {
if (id != phy->GetId()) {
- phy->Receive(packet_view);
+ phy->Receive(packet);
}
}
}
void PhyLayerFactory::TimerTick() {
- for (auto phy : phy_layers_) {
+ for (auto& phy : phy_layers_) {
phy->TimerTick();
}
}
std::string PhyLayerFactory::ToString() const {
+ std::stringstream factory;
switch (phy_type_) {
case Phy::Type::LOW_ENERGY:
- return "LOW_ENERGY";
+ factory << "LOW_ENERGY: ";
break;
case Phy::Type::BR_EDR:
- return "BR_EDR";
+ factory << "BR_EDR: ";
break;
default:
- return "Unknown";
+ factory << "Unknown: ";
}
+ for (auto& phy : phy_layers_) {
+ factory << phy->GetDeviceId();
+ factory << ",";
+ }
+
+ return factory.str();
}
-PhyLayerImpl::PhyLayerImpl(Phy::Type phy_type, uint32_t id,
- const std::function<void(packets::LinkLayerPacketView)>& device_receive,
- const std::shared_ptr<PhyLayerFactory>& factory)
- : PhyLayer(phy_type, id, device_receive), factory_(factory) {}
+PhyLayerImpl::PhyLayerImpl(
+ Phy::Type phy_type, uint32_t id,
+ const std::function<void(model::packets::LinkLayerPacketView)>&
+ device_receive,
+ uint32_t device_id, const std::shared_ptr<PhyLayerFactory> factory)
+ : PhyLayer(phy_type, id, device_receive, device_id), factory_(factory) {}
PhyLayerImpl::~PhyLayerImpl() {
- factory_->UnregisterPhyLayer(GetId());
- PhyLayer::~PhyLayer();
+ Unregister();
}
-void PhyLayerImpl::Send(const std::shared_ptr<packets::LinkLayerPacketBuilder> packet) {
+void PhyLayerImpl::Send(
+ const std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet) {
factory_->Send(packet, GetId());
}
-void PhyLayerImpl::Receive(packets::LinkLayerPacketView packet) {
+void PhyLayerImpl::Send(model::packets::LinkLayerPacketView packet) {
+ factory_->Send(packet, GetId());
+}
+
+void PhyLayerImpl::Unregister() {
+ factory_->UnregisterPhyLayer(GetId());
+}
+
+bool PhyLayerImpl::IsFactoryId(uint32_t id) {
+ return factory_->GetFactoryId() == id;
+}
+
+void PhyLayerImpl::Receive(model::packets::LinkLayerPacketView packet) {
transmit_to_device_(packet);
}
diff --git a/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.h b/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.h
index 018ff78..7d46733 100644
--- a/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.h
+++ b/vendor_libs/test_vendor_lib/model/setup/phy_layer_factory.h
@@ -20,8 +20,7 @@
#include <vector>
#include "include/phy.h"
-#include "packets/link_layer/link_layer_packet_builder.h"
-#include "packets/link_layer/link_layer_packet_view.h"
+#include "packets/link_layer_packets.h"
#include "phy_layer.h"
namespace test_vendor_lib {
@@ -30,13 +29,18 @@
friend class PhyLayerImpl;
public:
- PhyLayerFactory(Phy::Type phy_type);
+ PhyLayerFactory(Phy::Type phy_type, uint32_t factory_id);
virtual ~PhyLayerFactory() = default;
Phy::Type GetType();
- std::shared_ptr<PhyLayer> GetPhyLayer(const std::function<void(packets::LinkLayerPacketView)>& device_receive);
+ uint32_t GetFactoryId();
+
+ std::shared_ptr<PhyLayer> GetPhyLayer(
+ const std::function<void(model::packets::LinkLayerPacketView)>&
+ device_receive,
+ uint32_t device_id);
void UnregisterPhyLayer(uint32_t id);
@@ -45,23 +49,37 @@
virtual std::string ToString() const;
protected:
- virtual void Send(const std::shared_ptr<packets::LinkLayerPacketBuilder> packet, uint32_t id);
+ virtual void Send(
+ const std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet,
+ uint32_t id);
+ virtual void Send(model::packets::LinkLayerPacketView packet, uint32_t id);
private:
Phy::Type phy_type_;
std::vector<std::shared_ptr<PhyLayer>> phy_layers_;
uint32_t next_id_{1};
+ const uint32_t factory_id_;
};
class PhyLayerImpl : public PhyLayer {
public:
- PhyLayerImpl(Phy::Type phy_type, uint32_t id, const std::function<void(packets::LinkLayerPacketView)>& device_receive,
- const std::shared_ptr<PhyLayerFactory>& factory);
+ PhyLayerImpl(Phy::Type phy_type, uint32_t id,
+ const std::function<void(model::packets::LinkLayerPacketView)>&
+ device_receive,
+ uint32_t device_id,
+ const std::shared_ptr<PhyLayerFactory> factory);
virtual ~PhyLayerImpl() override;
- virtual void Send(const std::shared_ptr<packets::LinkLayerPacketBuilder> packet) override;
- virtual void Receive(packets::LinkLayerPacketView packet) override;
- virtual void TimerTick() override;
+ virtual void Send(
+ const std::shared_ptr<model::packets::LinkLayerPacketBuilder> packet)
+ override;
+ void Send(model::packets::LinkLayerPacketView packet) override;
+ void Receive(model::packets::LinkLayerPacketView packet) override;
+ void Unregister() override;
+ bool IsFactoryId(uint32_t factory_id) override;
+ void TimerTick() override;
+
+ uint32_t device_id_;
private:
std::shared_ptr<PhyLayerFactory> factory_;
diff --git a/vendor_libs/test_vendor_lib/model/setup/test_channel_transport.cc b/vendor_libs/test_vendor_lib/model/setup/test_channel_transport.cc
index d291896..d42bc72 100644
--- a/vendor_libs/test_vendor_lib/model/setup/test_channel_transport.cc
+++ b/vendor_libs/test_vendor_lib/model/setup/test_channel_transport.cc
@@ -14,17 +14,16 @@
* limitations under the License.
*/
-#define LOG_TAG "test_channel_transport"
-
#include "test_channel_transport.h"
-#include <base/logging.h>
-
-#include "osi/include/log.h"
+#include "os/log.h"
#include "osi/include/osi.h"
+#include <errno.h>
+#include <fcntl.h>
#include <netinet/in.h>
#include <sys/socket.h>
+#include <unistd.h>
using std::vector;
@@ -37,23 +36,28 @@
OSI_NO_INTR(listen_fd_ = socket(AF_INET, SOCK_STREAM, 0));
if (listen_fd_ < 0) {
- LOG_INFO(LOG_TAG, "Error creating socket for test channel.");
+ LOG_INFO("Error creating socket for test channel.");
return -1;
}
- LOG_INFO(LOG_TAG, "port: %d", port);
+ int enable = 1;
+ if (setsockopt(listen_fd_, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) {
+ LOG_ERROR("setsockopt(SO_REUSEADDR) failed: %s", strerror(errno));
+ }
+
+ LOG_INFO("port: %d", port);
listen_address.sin_family = AF_INET;
listen_address.sin_port = htons(port);
listen_address.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(listen_fd_, reinterpret_cast<sockaddr*>(&listen_address), sockaddr_in_size) < 0) {
- LOG_INFO(LOG_TAG, "Error binding test channel listener socket to address.");
+ LOG_INFO("Error binding test channel listener socket to address: %s", strerror(errno));
close(listen_fd_);
return -1;
}
if (listen(listen_fd_, 1) < 0) {
- LOG_INFO(LOG_TAG, "Error listening for test channel.");
+ LOG_INFO("Error listening for test channel: %s", strerror(errno));
close(listen_fd_);
return -1;
}
@@ -65,7 +69,7 @@
return;
}
if (close(listen_fd_)) {
- LOG_ERROR(LOG_TAG, "Error closing listen_fd_.");
+ LOG_ERROR("Error closing listen_fd_.");
}
listen_fd_ = -1;
}
@@ -76,16 +80,16 @@
OSI_NO_INTR(accept_fd = accept(listen_fd_, NULL, NULL));
if (accept_fd < 0) {
- LOG_INFO(LOG_TAG, "Error accepting test channel connection errno=%d (%s).", errno, strerror(errno));
+ LOG_INFO("Error accepting test channel connection errno=%d (%s).", errno, strerror(errno));
if (errno != EAGAIN && errno != EWOULDBLOCK) {
- LOG_ERROR(LOG_TAG, "Closing listen_fd_ (won't try again).");
+ LOG_ERROR("Closing listen_fd_ (won't try again).");
close(listen_fd_);
return -1;
}
}
- LOG_INFO(LOG_TAG, "accept_fd = %d.", accept_fd);
+ LOG_INFO("accept_fd = %d.", accept_fd);
return accept_fd;
}
@@ -94,18 +98,18 @@
uint8_t command_name_size = 0;
int bytes_read = read(fd, &command_name_size, 1);
if (bytes_read != 1) {
- LOG_INFO(LOG_TAG, "Unexpected (command_name_size) bytes_read: %d != %d", bytes_read, 1);
+ LOG_INFO("Unexpected (command_name_size) bytes_read: %d != %d", bytes_read, 1);
}
vector<uint8_t> command_name_raw;
command_name_raw.resize(command_name_size);
bytes_read = read(fd, &command_name_raw[0], command_name_size);
if (bytes_read != command_name_size) {
- LOG_INFO(LOG_TAG, "Unexpected (command_name) bytes_read: %d != %d", bytes_read, command_name_size);
+ LOG_INFO("Unexpected (command_name) bytes_read: %d != %d", bytes_read, command_name_size);
}
std::string command_name(command_name_raw.begin(), command_name_raw.end());
if (command_name == "CLOSE_TEST_CHANNEL" || command_name == "") {
- LOG_INFO(LOG_TAG, "Test channel closed");
+ LOG_INFO("Test channel closed");
unwatch();
close(fd);
return;
@@ -114,20 +118,20 @@
uint8_t num_args = 0;
bytes_read = read(fd, &num_args, 1);
if (bytes_read != 1) {
- LOG_INFO(LOG_TAG, "Unexpected (num_args) bytes_read: %d != %d", bytes_read, 1);
+ LOG_INFO("Unexpected (num_args) bytes_read: %d != %d", bytes_read, 1);
}
vector<std::string> args;
for (uint8_t i = 0; i < num_args; ++i) {
uint8_t arg_size = 0;
bytes_read = read(fd, &arg_size, 1);
if (bytes_read != 1) {
- LOG_INFO(LOG_TAG, "Unexpected (arg_size) bytes_read: %d != %d", bytes_read, 1);
+ LOG_INFO("Unexpected (arg_size) bytes_read: %d != %d", bytes_read, 1);
}
vector<uint8_t> arg;
arg.resize(arg_size);
bytes_read = read(fd, &arg[0], arg_size);
if (bytes_read != arg_size) {
- LOG_INFO(LOG_TAG, "Unexpected (arg) bytes_read: %d != %d", bytes_read, arg_size);
+ LOG_INFO("Unexpected (arg) bytes_read: %d != %d", bytes_read, arg_size);
}
args.push_back(std::string(arg.begin(), arg.end()));
}
@@ -144,9 +148,9 @@
uint8_t size_buf[4] = {static_cast<uint8_t>(size & 0xff), static_cast<uint8_t>((size >> 8) & 0xff),
static_cast<uint8_t>((size >> 16) & 0xff), static_cast<uint8_t>((size >> 24) & 0xff)};
int written = write(fd, size_buf, 4);
- CHECK(written == 4) << "What happened? written = " << written << "errno =" << errno;
+ ASSERT_LOG(written == 4, "What happened? written = %d errno = %d", written, errno);
written = write(fd, response.c_str(), size);
- CHECK(written == static_cast<int>(size)) << "What happened? written = " << written << "errno =" << errno;
+ ASSERT_LOG(written == static_cast<int>(size), "What happened? written = %d errno = %d", written, errno);
}
void TestChannelTransport::RegisterCommandHandler(
diff --git a/vendor_libs/test_vendor_lib/model/setup/test_command_handler.cc b/vendor_libs/test_vendor_lib/model/setup/test_command_handler.cc
index ad8689d..a2b8b2e 100644
--- a/vendor_libs/test_vendor_lib/model/setup/test_command_handler.cc
+++ b/vendor_libs/test_vendor_lib/model/setup/test_command_handler.cc
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "test_command_handler"
-
#include "test_command_handler.h"
#include "device_boutique.h"
#include "phy.h"
@@ -24,12 +22,11 @@
#include <stdlib.h>
-#include <base/logging.h>
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/values.h"
-#include "osi/include/log.h"
+#include "os/log.h"
#include "osi/include/osi.h"
using std::vector;
@@ -47,6 +44,7 @@
SET_HANDLER("add_device_to_phy", AddDeviceToPhy);
SET_HANDLER("del_device_from_phy", DelDeviceFromPhy);
SET_HANDLER("list", List);
+ SET_HANDLER("set_device_address", SetDeviceAddress);
SET_HANDLER("set_timer_period", SetTimerPeriod);
SET_HANDLER("start_timer", StartTimer);
SET_HANDLER("stop_timer", StopTimer);
@@ -59,29 +57,29 @@
AddPhy({"BR_EDR"});
// Add the controller to the Phys
- AddDeviceToPhy({"0", "0"});
- AddDeviceToPhy({"0", "1"});
+ AddDeviceToPhy({"1", "1"});
+ AddDeviceToPhy({"1", "2"});
// Add default test devices and add the devices to the phys
// Add({"beacon", "be:ac:10:00:00:01", "1000"});
- // AddDeviceToPhy({"1", "0"});
+ // AddDeviceToPhy({"2", "1"});
// Add({"keyboard", "cc:1c:eb:0a:12:d1", "500"});
- // AddDeviceToPhy({"2", "0"});
-
- // Add({"classic", "c1:a5:51:c0:00:01", "22"});
// AddDeviceToPhy({"3", "1"});
+ // Add({"classic", "c1:a5:51:c0:00:01", "22"});
+ // AddDeviceToPhy({"4", "2"});
+
// Add({"car_kit", "ca:12:1c:17:00:01", "238"});
- // AddDeviceToPhy({"4", "1"});
+ // AddDeviceToPhy({"5", "2"});
// Add({"sniffer", "ca:12:1c:17:00:01"});
- // AddDeviceToPhy({"5", "1"});
+ // AddDeviceToPhy({"6", "2"});
// Add({"sniffer", "3c:5a:b4:04:05:06"});
- // AddDeviceToPhy({"1", "1"});
+ // AddDeviceToPhy({"7", "2"});
// Add({"remote_loopback_device", "10:0d:00:ba:c1:06"});
- // AddDeviceToPhy({"2", "1"});
+ // AddDeviceToPhy({"8", "2"});
List({});
SetTimerPeriod({"10"});
@@ -113,11 +111,11 @@
if (new_dev == NULL) {
response_string_ = "TestCommandHandler 'add' " + args[0] + " failed!";
send_response_(response_string_);
- LOG_WARN(LOG_TAG, "%s", response_string_.c_str());
+ LOG_WARN("%s", response_string_.c_str());
return;
}
- LOG_INFO(LOG_TAG, "Add %s", new_dev->ToString().c_str());
+ LOG_INFO("Add %s", new_dev->ToString().c_str());
size_t dev_index = model_.Add(new_dev);
response_string_ = std::to_string(dev_index) + std::string(":") + new_dev->ToString();
send_response_(response_string_);
@@ -160,11 +158,9 @@
void TestCommandHandler::AddPhy(const vector<std::string>& args) {
if (args[0] == "LOW_ENERGY") {
- std::shared_ptr<PhyLayerFactory> new_phy = std::make_shared<PhyLayerFactory>(Phy::Type::LOW_ENERGY);
- model_.AddPhy(new_phy);
+ model_.AddPhy(Phy::Type::LOW_ENERGY);
} else if (args[0] == "BR_EDR") {
- std::shared_ptr<PhyLayerFactory> new_phy = std::make_shared<PhyLayerFactory>(Phy::Type::BR_EDR);
- model_.AddPhy(new_phy);
+ model_.AddPhy(Phy::Type::BR_EDR);
} else {
response_string_ = "TestCommandHandler 'add_phy' with unrecognized type " + args[0];
send_response_(response_string_);
@@ -211,15 +207,31 @@
void TestCommandHandler::List(const vector<std::string>& args) {
if (args.size() > 0) {
- LOG_INFO(LOG_TAG, "Unused args: arg[0] = %s", args[0].c_str());
+ LOG_INFO("Unused args: arg[0] = %s", args[0].c_str());
return;
}
send_response_(model_.List());
}
+void TestCommandHandler::SetDeviceAddress(const vector<std::string>& args) {
+ if (args.size() != 2) {
+ response_string_ = "TestCommandHandler 'set_device_address' takes two arguments";
+ send_response_(response_string_);
+ return;
+ }
+ size_t device_id = std::stoi(args[0]);
+ Address device_address;
+ Address::FromString(args[1], device_address);
+ model_.SetDeviceAddress(device_id, device_address);
+ response_string_ = "set_device_address " + args[0];
+ response_string_ += " ";
+ response_string_ += args[1];
+ send_response_(response_string_);
+}
+
void TestCommandHandler::SetTimerPeriod(const vector<std::string>& args) {
if (args.size() != 1) {
- LOG_INFO(LOG_TAG, "SetTimerPeriod takes 1 argument");
+ LOG_INFO("SetTimerPeriod takes 1 argument");
}
size_t period = std::stoi(args[0]);
model_.SetTimerPeriod(std::chrono::milliseconds(period));
@@ -227,14 +239,14 @@
void TestCommandHandler::StartTimer(const vector<std::string>& args) {
if (args.size() > 0) {
- LOG_INFO(LOG_TAG, "Unused args: arg[0] = %s", args[0].c_str());
+ LOG_INFO("Unused args: arg[0] = %s", args[0].c_str());
}
model_.StartTimer();
}
void TestCommandHandler::StopTimer(const vector<std::string>& args) {
if (args.size() > 0) {
- LOG_INFO(LOG_TAG, "Unused args: arg[0] = %s", args[0].c_str());
+ LOG_INFO("Unused args: arg[0] = %s", args[0].c_str());
}
model_.StopTimer();
}
diff --git a/vendor_libs/test_vendor_lib/model/setup/test_command_handler.h b/vendor_libs/test_vendor_lib/model/setup/test_command_handler.h
index 409966a..4c62d84 100644
--- a/vendor_libs/test_vendor_lib/model/setup/test_command_handler.h
+++ b/vendor_libs/test_vendor_lib/model/setup/test_command_handler.h
@@ -69,6 +69,9 @@
// List the devices that the test knows about
void List(const std::vector<std::string>& args);
+ // Change the device's MAC address
+ void SetDeviceAddress(const std::vector<std::string>& args);
+
// Timer management functions
void SetTimerPeriod(const std::vector<std::string>& args);
diff --git a/vendor_libs/test_vendor_lib/model/setup/test_model.cc b/vendor_libs/test_vendor_lib/model/setup/test_model.cc
index 3572761..688b7dc 100644
--- a/vendor_libs/test_vendor_lib/model/setup/test_model.cc
+++ b/vendor_libs/test_vendor_lib/model/setup/test_model.cc
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "test_model"
-
#include "test_model.h"
// TODO: Remove when registration works
@@ -30,13 +28,14 @@
#include <memory>
#include <stdlib.h>
+#include <iomanip>
+#include <iostream>
-#include <base/logging.h>
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
#include "base/values.h"
-#include "osi/include/log.h"
+#include "os/log.h"
#include "osi/include/osi.h"
#include "device_boutique.h"
@@ -78,73 +77,87 @@
}
void TestModel::StartTimer() {
- LOG_INFO(LOG_TAG, "StartTimer()");
+ LOG_INFO("StartTimer()");
timer_tick_task_ =
schedule_periodic_task_(std::chrono::milliseconds(0), timer_period_, [this]() { TestModel::TimerTick(); });
}
void TestModel::StopTimer() {
- LOG_INFO(LOG_TAG, "StopTimer()");
+ LOG_INFO("StopTimer()");
cancel_task_(timer_tick_task_);
timer_tick_task_ = kInvalidTaskId;
}
size_t TestModel::Add(std::shared_ptr<Device> new_dev) {
- devices_.push_back(new_dev);
- return devices_.size() - 1;
+ devices_counter_++;
+ devices_[devices_counter_] = new_dev;
+ return devices_counter_;
}
void TestModel::Del(size_t dev_index) {
- if (dev_index >= devices_.size()) {
- LOG_WARN(LOG_TAG, "del: index out of range!");
+ auto device = devices_.find(dev_index);
+ if (device == devices_.end()) {
+ LOG_WARN("Del: can't find device!");
return;
}
- devices_.erase(devices_.begin() + dev_index);
+ devices_.erase(dev_index);
}
-size_t TestModel::AddPhy(std::shared_ptr<PhyLayerFactory> new_phy) {
- phys_.push_back(new_phy);
- return phys_.size() - 1;
+size_t TestModel::AddPhy(Phy::Type phy_type) {
+ phys_counter_++;
+ std::shared_ptr<PhyLayerFactory> new_phy = std::make_shared<PhyLayerFactory>(phy_type, phys_counter_);
+ phys_[phys_counter_] = new_phy;
+ return phys_counter_;
}
void TestModel::DelPhy(size_t phy_index) {
- if (phy_index >= phys_.size()) {
- LOG_WARN(LOG_TAG, "del_phy: index %d out of range: ", static_cast<int>(phy_index));
+ auto phy = phys_.find(phy_index);
+ if (phy == phys_.end()) {
+ LOG_WARN("DelPhy: can't find device!");
return;
}
+ phys_.erase(phy_index);
}
void TestModel::AddDeviceToPhy(size_t dev_index, size_t phy_index) {
- if (dev_index >= devices_.size()) {
- LOG_WARN(LOG_TAG, "add_device_to_phy: device out of range: ");
+ auto device = devices_.find(dev_index);
+ if (device == devices_.end()) {
+ LOG_WARN("%s: can't find device!", __func__);
return;
}
- if (phy_index >= phys_.size()) {
- LOG_WARN(LOG_TAG, "add_device_to_phy: phy out of range: ");
+ auto phy = phys_.find(phy_index);
+ if (phy == phys_.end()) {
+ LOG_WARN("%s: can't find phy!", __func__);
return;
}
- std::shared_ptr<Device> dev = devices_[dev_index];
- dev->RegisterPhyLayer(
- phys_[phy_index]->GetPhyLayer([dev](packets::LinkLayerPacketView packet) { dev->IncomingPacket(packet); }));
+ auto dev = device->second;
+ dev->RegisterPhyLayer(phy->second->GetPhyLayer(
+ [dev](model::packets::LinkLayerPacketView packet) {
+ dev->IncomingPacket(packet);
+ },
+ device->first));
}
void TestModel::DelDeviceFromPhy(size_t dev_index, size_t phy_index) {
- if (dev_index >= devices_.size()) {
- LOG_WARN(LOG_TAG, "del_device_from_phy: device out of range: ");
+ auto device = devices_.find(dev_index);
+ if (device == devices_.end()) {
+ LOG_WARN("%s: can't find device!", __func__);
return;
}
- if (phy_index >= phys_.size()) {
- LOG_WARN(LOG_TAG, "del_device_from_phy: phy out of range: ");
+ auto phy = phys_.find(phy_index);
+ if (phy == phys_.end()) {
+ LOG_WARN("%s: can't find phy!", __func__);
return;
}
+ device->second->UnregisterPhyLayer(phy->second->GetType(), phy->second->GetFactoryId());
}
void TestModel::AddLinkLayerConnection(int socket_fd, Phy::Type phy_type) {
std::shared_ptr<Device> dev = LinkLayerSocketDevice::Create(socket_fd, phy_type);
int index = Add(dev);
- for (size_t phy_index = 0; phy_index < phys_.size(); phy_index++) {
- if (phy_type == phys_[phy_index]->GetType()) {
- AddDeviceToPhy(index, phy_index);
+ for (auto& phy : phys_) {
+ if (phy_type == phy.second->GetType()) {
+ AddDeviceToPhy(index, phy.first);
}
}
}
@@ -163,40 +176,64 @@
}
void TestModel::IncomingHciConnection(int socket_fd) {
- std::shared_ptr<HciSocketDevice> dev = HciSocketDevice::Create(socket_fd);
- // TODO: Auto-increment addresses?
- static int hci_devs = 0;
- int index = Add(std::static_pointer_cast<Device>(dev));
- std::string addr = "da:4c:10:de:17:0"; // Da HCI dev
- CHECK(hci_devs < 10) << "Why do you need more than 9?";
- addr += '0' + hci_devs++;
+ auto dev = HciSocketDevice::Create(socket_fd);
+ size_t index = Add(std::static_pointer_cast<Device>(dev));
+ std::string addr = "da:4c:10:de:17:"; // Da HCI dev
+ std::stringstream stream;
+ stream << std::setfill('0') << std::setw(2) << std::hex << (index % 256);
+ addr += stream.str();
+
dev->Initialize({"IgnoredTypeName", addr});
- // TODO: Add device to all phys? For now, just the first two.
- for (size_t phy = 0; phy < 2 && phy < phys_.size(); phy++) {
- AddDeviceToPhy(index, phy);
+ LOG_INFO("initialized %s", addr.c_str());
+ for (auto& phy : phys_) {
+ AddDeviceToPhy(index, phy.first);
}
dev->RegisterTaskScheduler(schedule_task_);
dev->RegisterTaskCancel(cancel_task_);
+ dev->RegisterCloseCallback([this, socket_fd, index] { OnHciConnectionClosed(socket_fd, index); });
+}
+
+void TestModel::OnHciConnectionClosed(int socket_fd, size_t index) {
+ auto device = devices_.find(index);
+ if (device == devices_.end()) {
+ LOG_WARN("OnHciConnectionClosed: can't find device!");
+ return;
+ }
+ int close_result = close(socket_fd);
+ ASSERT_LOG(close_result == 0, "can't close: %s", strerror(errno));
+ device->second->UnregisterPhyLayers();
+ devices_.erase(index);
+}
+
+void TestModel::SetDeviceAddress(size_t index, Address address) {
+ auto device = devices_.find(index);
+ if (device == devices_.end()) {
+ LOG_WARN("SetDeviceAddress can't find device!");
+ return;
+ }
+ device->second->SetAddress(address);
}
const std::string& TestModel::List() {
list_string_ = "";
list_string_ += " Devices: \r\n";
- for (size_t dev = 0; dev < devices_.size(); dev++) {
- list_string_ += " " + std::to_string(dev) + ":";
- list_string_ += devices_[dev]->ToString() + " \r\n";
+ for (auto& dev : devices_) {
+ list_string_ += " " + std::to_string(dev.first) + ":";
+ list_string_ += dev.second->ToString() + " \r\n";
}
list_string_ += " Phys: \r\n";
- for (size_t phy = 0; phy < phys_.size(); phy++) {
- list_string_ += " " + std::to_string(phy) + ":";
- list_string_ += phys_[phy]->ToString() + " \r\n";
+ for (auto& phy : phys_) {
+ list_string_ += " " + std::to_string(phy.first) + ":";
+ list_string_ += phy.second->ToString() + " \r\n";
}
return list_string_;
}
void TestModel::TimerTick() {
- for (size_t dev = 0; dev < devices_.size(); dev++) {
- devices_[dev]->TimerTick();
+ for (auto dev = devices_.begin(); dev != devices_.end();) {
+ auto tmp = dev;
+ dev++;
+ tmp->second->TimerTick();
}
}
diff --git a/vendor_libs/test_vendor_lib/model/setup/test_model.h b/vendor_libs/test_vendor_lib/model/setup/test_model.h
index c799f3f..d651f50 100644
--- a/vendor_libs/test_vendor_lib/model/setup/test_model.h
+++ b/vendor_libs/test_vendor_lib/model/setup/test_model.h
@@ -47,7 +47,7 @@
void Del(size_t device_index);
// Add phy, return its index
- size_t AddPhy(std::shared_ptr<PhyLayerFactory> phy);
+ size_t AddPhy(Phy::Type phy_type);
// Remove phy by index
void DelPhy(size_t phy_index);
@@ -63,9 +63,15 @@
void IncomingLinkLayerConnection(int socket_fd);
void IncomingHciConnection(int socket_fd);
+ // Handle closed remote connections
+ void OnHciConnectionClosed(int socket_fd, size_t index);
+
// Connect to a remote device
void AddRemote(const std::string& server, int port, Phy::Type phy_type);
+ // Set the device's Bluetooth address
+ void SetDeviceAddress(size_t device_index, Address device_address);
+
// Let devices know about the passage of time
void TimerTick();
void StartTimer();
@@ -79,8 +85,10 @@
void Reset();
private:
- std::vector<std::shared_ptr<PhyLayerFactory>> phys_;
- std::vector<std::shared_ptr<Device>> devices_;
+ std::map<size_t, std::shared_ptr<PhyLayerFactory>> phys_;
+ size_t phys_counter_ = 0;
+ std::map<size_t, std::shared_ptr<Device>> devices_;
+ size_t devices_counter_ = 0;
std::string list_string_;
// Callbacks to schedule tasks.
diff --git a/vendor_libs/test_vendor_lib/packets/Android.bp b/vendor_libs/test_vendor_lib/packets/Android.bp
deleted file mode 100644
index 8a73a64..0000000
--- a/vendor_libs/test_vendor_lib/packets/Android.bp
+++ /dev/null
@@ -1,83 +0,0 @@
-// packet library for libbt-rootcanal
-// ========================================================
-cc_library_static {
- name: "libbt-rootcanal-packets",
- defaults: [
- "libchrome_support_defaults",
- "clang_file_coverage",
- ],
- host_supported: true,
- proprietary: true,
- srcs: [
- "iterator.cc",
- "counted_builder.cc",
- "packet_view.cc",
- "raw_builder.cc",
- "view.cc",
- "hci/acl_packet_builder.cc",
- "hci/acl_packet_view.cc",
- "hci/command_packet_builder.cc",
- "hci/command_packet_view.cc",
- "hci/event_packet_builder.cc",
- "hci/event_payload_builder.cc",
- "hci/hci_packet_builder.cc",
- "hci/le_meta_event_builder.cc",
- "hci/sco_packet_builder.cc",
- "hci/sco_packet_view.cc",
- "link_layer/link_layer_packet_builder.cc",
- "link_layer/link_layer_packet_view.cc",
- ],
- cflags: [
- "-fvisibility=hidden",
- ],
- local_include_dirs: [
- ".",
- ],
- export_include_dirs: ["."],
- include_dirs: [
- "system/bt/vendor_libs/test_vendor_lib/include",
- "system/bt/vendor_libs/test_vendor_lib/",
- "system/bt/",
- ],
- shared_libs: [
- "libbase",
- "liblog",
- ],
-}
-
-// Unit tests for the host
-// ========================================================
-cc_test_host {
- name: "rootcanal-packets_test_host",
- defaults: [
- "libchrome_support_defaults",
- "clang_file_coverage",
- "clang_coverage_bin",
- ],
- srcs: [
- "test/link_layer_packet_builder_test.cc",
- "test/packet_builder_test.cc",
- "test/packet_view_test.cc",
- "hci/test/acl_builder_test.cc",
- "hci/test/event_builder_test.cc",
- ],
- header_libs: [
- "libbluetooth_headers",
- ],
- local_include_dirs: [
- ".",
- ],
- include_dirs: [
- "system/bt",
- "system/bt/hci/include",
- "system/bt/vendor_libs/test_vendor_lib",
- "system/bt/vendor_libs/test_vendor_lib/include",
- ],
- shared_libs: [
- "liblog",
- ],
- static_libs: [
- "libbt-rootcanal-types",
- "libbt-rootcanal-packets",
- ],
-}
diff --git a/vendor_libs/test_vendor_lib/packets/base_packet_builder.h b/vendor_libs/test_vendor_lib/packets/base_packet_builder.h
deleted file mode 100644
index 92ae3a9..0000000
--- a/vendor_libs/test_vendor_lib/packets/base_packet_builder.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <forward_list>
-#include <iterator>
-#include <memory>
-#include <vector>
-
-namespace test_vendor_lib {
-namespace packets {
-
-// A little-endian PacketBuilder might contain a big-endian PacketBuilder,
-// so BasePacketBuilder provides a common base class.
-class BasePacketBuilder {
- public:
- virtual ~BasePacketBuilder() = default;
-
- virtual size_t size() const = 0;
-
- // Write to the vector with the given iterator.
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const = 0;
-
- protected:
- BasePacketBuilder() = default;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/counted_builder.cc b/vendor_libs/test_vendor_lib/packets/counted_builder.cc
deleted file mode 100644
index 10d3ceb..0000000
--- a/vendor_libs/test_vendor_lib/packets/counted_builder.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2018 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 "counted_builder.h"
-
-using std::vector;
-
-namespace test_vendor_lib {
-namespace packets {
-
-size_t CountedBuilder::size() const {
- size_t payload_size = sizeof(uint8_t);
- for (size_t i = 0; i < sub_builders_.size(); i++) {
- payload_size += sub_builders_[i]->size();
- }
- return payload_size;
-}
-
-void CountedBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const {
- insert(static_cast<uint8_t>(sub_builders_.size()), it);
- for (size_t i = 0; i < sub_builders_.size(); i++) {
- sub_builders_[i]->Serialize(it);
- }
-}
-
-void CountedBuilder::Add(std::unique_ptr<BasePacketBuilder> builder) {
- sub_builders_.push_back(std::move(builder));
-}
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/counted_builder.h b/vendor_libs/test_vendor_lib/packets/counted_builder.h
deleted file mode 100644
index fed88c5..0000000
--- a/vendor_libs/test_vendor_lib/packets/counted_builder.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <forward_list>
-#include <memory>
-#include <vector>
-
-#include "packets/base_packet_builder.h"
-#include "packets/packet_builder.h"
-#include "packets/raw_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class CountedBuilder : public RawBuilder {
- public:
- CountedBuilder() = default;
- virtual ~CountedBuilder() = default;
-
- virtual size_t size() const override;
-
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override;
-
- void Add(std::unique_ptr<BasePacketBuilder> builder);
-
- private:
- std::vector<std::unique_ptr<BasePacketBuilder>> sub_builders_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/acl_packet_builder.cc b/vendor_libs/test_vendor_lib/packets/hci/acl_packet_builder.cc
deleted file mode 100644
index 00b0ba8..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/acl_packet_builder.cc
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2018 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 "packets/hci/acl_packet_builder.h"
-
-#include <base/logging.h>
-
-using std::vector;
-using test_vendor_lib::acl::BroadcastFlagsType;
-using test_vendor_lib::acl::PacketBoundaryFlagsType;
-
-namespace test_vendor_lib {
-namespace packets {
-
-AclPacketBuilder::AclPacketBuilder(uint16_t handle, PacketBoundaryFlagsType packet_boundary_flags,
- BroadcastFlagsType broadcast_flags, std::unique_ptr<BasePacketBuilder> payload)
- : handle_(handle), packet_boundary_flags_(packet_boundary_flags), broadcast_flags_(broadcast_flags),
- payload_(std::move(payload)) {}
-
-std::unique_ptr<AclPacketBuilder> AclPacketBuilder::Create(uint16_t handle,
- PacketBoundaryFlagsType packet_boundary_flags,
- BroadcastFlagsType broadcast_flags,
- std::unique_ptr<BasePacketBuilder> payload) {
- return std::unique_ptr<AclPacketBuilder>(
- new AclPacketBuilder(handle, packet_boundary_flags, broadcast_flags, std::move(payload)));
-}
-
-size_t AclPacketBuilder::size() const {
- return 2 * sizeof(uint16_t) + payload_->size();
-}
-
-void AclPacketBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const {
- insert(static_cast<uint16_t>((handle_ & 0xfff) | (static_cast<uint16_t>(packet_boundary_flags_) << 12) |
- (static_cast<uint16_t>(broadcast_flags_) << 14)),
- it);
- uint16_t payload_size = payload_->size();
-
- CHECK(static_cast<size_t>(payload_size) == payload_->size())
- << "Payload too large for an ACL packet: " << payload_->size();
- insert(payload_size, it);
- payload_->Serialize(it);
-}
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/acl_packet_builder.h b/vendor_libs/test_vendor_lib/packets/hci/acl_packet_builder.h
deleted file mode 100644
index cd2a607..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/acl_packet_builder.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <base/logging.h>
-#include <cstdint>
-#include <memory>
-#include <vector>
-
-#include "include/acl.h"
-#include "packets/hci/hci_packet_builder.h"
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// ACL data packets are specified in the Bluetooth Core Specification Version
-// 4.2, Volume 2, Part E, Section 5.4.2
-class AclPacketBuilder : public HciPacketBuilder {
- public:
- virtual ~AclPacketBuilder() override = default;
-
- static std::unique_ptr<AclPacketBuilder> Create(uint16_t handle, acl::PacketBoundaryFlagsType packet_boundary_flags,
- acl::BroadcastFlagsType broadcast_flags,
- std::unique_ptr<BasePacketBuilder> payload);
-
- virtual size_t size() const override;
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const;
-
- private:
- AclPacketBuilder(uint16_t handle, acl::PacketBoundaryFlagsType packet_boundary_flags,
- acl::BroadcastFlagsType broadcast_flags, std::unique_ptr<BasePacketBuilder> payload);
- AclPacketBuilder() = delete;
- uint16_t handle_;
- acl::PacketBoundaryFlagsType packet_boundary_flags_;
- acl::BroadcastFlagsType broadcast_flags_;
- std::unique_ptr<BasePacketBuilder> payload_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/acl_packet_view.cc b/vendor_libs/test_vendor_lib/packets/hci/acl_packet_view.cc
deleted file mode 100644
index bfec835e..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/acl_packet_view.cc
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2018 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 "packets/hci/acl_packet_view.h"
-
-#include <base/logging.h>
-
-using std::vector;
-using test_vendor_lib::acl::BroadcastFlagsType;
-using test_vendor_lib::acl::PacketBoundaryFlagsType;
-
-namespace test_vendor_lib {
-namespace packets {
-
-AclPacketView::AclPacketView(std::shared_ptr<std::vector<uint8_t>> packet) : PacketView<true>(packet) {}
-
-AclPacketView::AclPacketView(PacketView<true> packet_view) : PacketView<true>(packet_view) {}
-
-AclPacketView AclPacketView::Create(std::shared_ptr<std::vector<uint8_t>> packet) {
- return AclPacketView(packet);
-}
-
-AclPacketView AclPacketView::Create(PacketView<true> packet_view) {
- return AclPacketView(packet_view);
-}
-
-uint16_t AclPacketView::GetHandle() const {
- return begin().extract<uint16_t>() & 0xfff;
-}
-
-PacketBoundaryFlagsType AclPacketView::GetPacketBoundaryFlags() const {
- return static_cast<PacketBoundaryFlagsType>(((begin() + 1).extract<uint8_t>() & 0x30) >> 4);
-}
-
-BroadcastFlagsType AclPacketView::GetBroadcastFlags() const {
- return static_cast<BroadcastFlagsType>(((begin() + 1).extract<uint8_t>() & 0xc0) >> 6);
-}
-
-PacketView<true> AclPacketView::GetPayload() const {
- uint16_t payload_size = (begin() + sizeof(uint16_t)).extract<uint16_t>();
- CHECK(static_cast<uint16_t>(size() - 2 * sizeof(uint16_t)) == payload_size)
- << "Malformed ACL packet payload_size " << payload_size << " + 4 != " << size();
- return SubViewLittleEndian(2 * sizeof(uint16_t), size());
-}
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/acl_packet_view.h b/vendor_libs/test_vendor_lib/packets/hci/acl_packet_view.h
deleted file mode 100644
index 1e69cda..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/acl_packet_view.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <memory>
-#include <vector>
-
-#include "include/acl.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// ACL data packets are specified in the Bluetooth Core Specification Version
-// 4.2, Volume 2, Part E, Section 5.4.2
-class AclPacketView : public PacketView<true> {
- public:
- virtual ~AclPacketView() override = default;
-
- static AclPacketView Create(std::shared_ptr<std::vector<uint8_t>> packet);
- static AclPacketView Create(PacketView<true> packet_view);
-
- uint16_t GetHandle() const;
- acl::PacketBoundaryFlagsType GetPacketBoundaryFlags() const;
- acl::BroadcastFlagsType GetBroadcastFlags() const;
- PacketView<true> GetPayload() const;
-
- private:
- AclPacketView(std::shared_ptr<std::vector<uint8_t>> packet);
- AclPacketView(PacketView<true> packet_view);
- AclPacketView() = delete;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/command_packet_builder.cc b/vendor_libs/test_vendor_lib/packets/hci/command_packet_builder.cc
deleted file mode 100644
index 7074309..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/command_packet_builder.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2018 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 "packets/hci/command_packet_builder.h"
-
-#include <base/logging.h>
-
-using std::vector;
-using test_vendor_lib::hci::OpCode;
-
-namespace test_vendor_lib {
-namespace packets {
-
-CommandPacketBuilder::CommandPacketBuilder(OpCode opcode, std::unique_ptr<BasePacketBuilder> payload)
- : opcode_(opcode), payload_(std::move(payload)) {}
-
-size_t CommandPacketBuilder::size() const {
- return sizeof(uint16_t) + sizeof(uint8_t) + payload_->size();
-}
-
-void CommandPacketBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const {
- insert(static_cast<uint16_t>(opcode_), it);
- uint8_t payload_size = static_cast<uint8_t>(payload_->size());
-
- CHECK(static_cast<size_t>(payload_size) == payload_->size())
- << "Payload too large for a command packet: " << payload_->size();
- insert(payload_size, it);
- payload_->Serialize(it);
-}
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/command_packet_builder.h b/vendor_libs/test_vendor_lib/packets/hci/command_packet_builder.h
deleted file mode 100644
index d8e86a0..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/command_packet_builder.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <base/logging.h>
-#include <cstdint>
-#include <memory>
-#include <vector>
-
-#include "include/hci.h"
-#include "packets/hci/hci_packet_builder.h"
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// ACL data packets are specified in the Bluetooth Core Specification Version
-// 4.2, Volume 2, Part E, Section 5.4.2
-class CommandPacketBuilder : public HciPacketBuilder {
- public:
- virtual ~CommandPacketBuilder() override = default;
-
- static std::unique_ptr<CommandPacketBuilder> Create(hci::OpCode opcode, std::unique_ptr<BasePacketBuilder> payload);
-
- virtual size_t size() const override;
-
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const;
-
- private:
- CommandPacketBuilder(hci::OpCode opcode, std::unique_ptr<BasePacketBuilder> payload);
- CommandPacketBuilder() = delete;
- hci::OpCode opcode_;
- std::unique_ptr<BasePacketBuilder> payload_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/command_packet_view.cc b/vendor_libs/test_vendor_lib/packets/hci/command_packet_view.cc
deleted file mode 100644
index f0876c1..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/command_packet_view.cc
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2018 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 "packets/hci/command_packet_view.h"
-
-#include <base/logging.h>
-
-using std::vector;
-
-namespace test_vendor_lib {
-namespace packets {
-
-CommandPacketView::CommandPacketView(std::shared_ptr<std::vector<uint8_t>> packet) : PacketView<true>(packet) {}
-
-CommandPacketView CommandPacketView::Create(std::shared_ptr<std::vector<uint8_t>> packet) {
- return CommandPacketView(packet);
-}
-
-uint16_t CommandPacketView::GetOpcode() const {
- return begin().extract<uint16_t>();
-}
-
-PacketView<true> CommandPacketView::GetPayload() const {
- uint8_t payload_size = (begin() + sizeof(uint16_t)).extract<uint8_t>();
- CHECK(static_cast<uint8_t>(size() - sizeof(uint16_t) - sizeof(uint8_t)) == payload_size)
- << "Malformed Command packet payload_size " << payload_size << " + 2 != " << size();
- return SubViewLittleEndian(sizeof(uint16_t) + sizeof(uint8_t), size());
-}
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/command_packet_view.h b/vendor_libs/test_vendor_lib/packets/hci/command_packet_view.h
deleted file mode 100644
index 6355c1e..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/command_packet_view.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <memory>
-#include <vector>
-
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// Command packets are specified in the Bluetooth Core Specification Version
-// 4.2, Volume 2, Part E, Section 5.4.1
-class CommandPacketView : public PacketView<true> {
- public:
- virtual ~CommandPacketView() override = default;
-
- static CommandPacketView Create(std::shared_ptr<std::vector<uint8_t>> packet);
-
- uint16_t GetOpcode() const;
-
- PacketView<true> GetPayload() const;
-
- private:
- CommandPacketView(std::shared_ptr<std::vector<uint8_t>> packet);
- CommandPacketView() = delete;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/event_packet_builder.cc b/vendor_libs/test_vendor_lib/packets/hci/event_packet_builder.cc
deleted file mode 100644
index 010decd..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/event_packet_builder.cc
+++ /dev/null
@@ -1,810 +0,0 @@
-/*
- * Copyright 2018 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 "packets/hci/event_packet_builder.h"
-
-#include <base/logging.h>
-#include "hci.h"
-#include "packets/hci/le_meta_event_builder.h"
-
-using std::vector;
-using test_vendor_lib::hci::EventCode;
-using test_vendor_lib::hci::OpCode;
-using test_vendor_lib::hci::Status;
-
-namespace test_vendor_lib {
-namespace packets {
-
-EventPacketBuilder::EventPacketBuilder(EventCode event_code)
- : event_code_(event_code), payload_(std::make_unique<RawBuilder>()) {}
-
-EventPacketBuilder::EventPacketBuilder(EventCode event_code, std::unique_ptr<RawBuilder> payload)
- : event_code_(event_code), payload_(std::move(payload)) {}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.1
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateInquiryCompleteEvent(hci::Status status) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::INQUIRY_COMPLETE));
- CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.14
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteEvent(
- hci::OpCode command_opcode, const vector<uint8_t>& event_return_parameters) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::COMMAND_COMPLETE));
-
- CHECK(evt_ptr->AddPayloadOctets1(1)); // num_hci_command_packets
- CHECK(evt_ptr->AddPayloadOctets2(static_cast<uint16_t>(command_opcode)));
- CHECK(evt_ptr->AddPayloadOctets(event_return_parameters));
-
- return evt_ptr;
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(hci::OpCode command_opcode,
- hci::Status status) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::COMMAND_COMPLETE));
-
- CHECK(evt_ptr->AddPayloadOctets1(1)); // num_hci_command_packets
- CHECK(evt_ptr->AddPayloadOctets2(static_cast<uint16_t>(command_opcode)));
- CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
-
- return evt_ptr;
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteStatusAndAddressEvent(
- hci::OpCode command_opcode, hci::Status status, const Address& address) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::COMMAND_COMPLETE));
-
- CHECK(evt_ptr->AddPayloadOctets1(1)); // num_hci_command_packets
- CHECK(evt_ptr->AddPayloadOctets2(static_cast<uint16_t>(command_opcode)));
- CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
- CHECK(evt_ptr->AddPayloadAddress(address));
-
- return evt_ptr;
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteUnknownOpCodeEvent(
- uint16_t command_opcode) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::COMMAND_COMPLETE));
-
- CHECK(evt_ptr->AddPayloadOctets1(1)); // num_hci_command_packets
- CHECK(evt_ptr->AddPayloadOctets2(static_cast<uint16_t>(command_opcode)));
- CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(Status::UNKNOWN_COMMAND)));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.15
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandStatusEvent(hci::Status status,
- hci::OpCode command_opcode) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::COMMAND_STATUS));
-
- CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
- CHECK(evt_ptr->AddPayloadOctets1(1)); // num_hci_command_packets
- CHECK(evt_ptr->AddPayloadOctets2(static_cast<uint16_t>(command_opcode)));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.19
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateNumberOfCompletedPacketsEvent(
- uint16_t handle, uint16_t num_completed_packets) {
- std::unique_ptr<RawBuilder> payload = std::make_unique<CountedBuilder>();
- std::unique_ptr<EventPacketBuilder> evt_ptr = std::unique_ptr<EventPacketBuilder>(
- new EventPacketBuilder(EventCode::NUMBER_OF_COMPLETED_PACKETS, std::move(payload)));
-
- evt_ptr->AddCompletedPackets(handle, num_completed_packets);
-
- return evt_ptr;
-}
-
-void EventPacketBuilder::AddCompletedPackets(uint16_t handle, uint16_t num_completed_packets) {
- CHECK(event_code_ == EventCode::NUMBER_OF_COMPLETED_PACKETS);
-
- std::unique_ptr<RawBuilder> handle_pair = std::make_unique<RawBuilder>();
- CHECK(handle_pair->AddOctets2(handle));
- CHECK(handle_pair->AddOctets2(num_completed_packets));
- AddBuilder(std::move(handle_pair));
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.10
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteDeleteStoredLinkKey(
- hci::Status status, uint16_t num_keys_deleted) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::DELETE_STORED_LINK_KEY, status);
-
- CHECK(evt_ptr->AddPayloadOctets2(num_keys_deleted));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.12
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadLocalName(
- hci::Status status, const std::vector<uint8_t>& local_name) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_LOCAL_NAME, status);
-
- size_t len = local_name.size();
- if (len > 247) {
- len = 247;
- }
- CHECK(evt_ptr->AddPayloadOctets(len, local_name));
- CHECK(evt_ptr->AddPayloadOctets1(0)); // Null terminated
- for (size_t i = 0; i < 248 - len - 1; i++) CHECK(evt_ptr->AddPayloadOctets1(0xFF));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.23
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadAuthenticationEnable(
- hci::Status status, uint8_t enable) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_LOCAL_NAME, status);
- CHECK(evt_ptr->AddPayloadOctets1(enable));
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.1
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadLocalVersionInformation(
- hci::Status status, uint8_t hci_version, uint16_t hci_revision, uint8_t lmp_pal_version, uint16_t manufacturer_name,
- uint16_t lmp_pal_subversion) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_LOCAL_VERSION_INFORMATION, status);
-
- CHECK(evt_ptr->AddPayloadOctets1(hci_version));
- CHECK(evt_ptr->AddPayloadOctets2(hci_revision));
- CHECK(evt_ptr->AddPayloadOctets1(lmp_pal_version));
- CHECK(evt_ptr->AddPayloadOctets2(manufacturer_name));
- CHECK(evt_ptr->AddPayloadOctets2(lmp_pal_subversion));
-
- return evt_ptr;
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateReadRemoteVersionInformationEvent(
- hci::Status status, uint16_t connection_handle, uint8_t lmp_pal_version, uint16_t manufacturer_name,
- uint16_t lmp_pal_subversion) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::READ_REMOTE_VERSION_INFORMATION_COMPLETE));
-
- CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
- CHECK(evt_ptr->AddPayloadOctets2(connection_handle));
- CHECK(evt_ptr->AddPayloadOctets1(lmp_pal_version));
- CHECK(evt_ptr->AddPayloadOctets2(manufacturer_name));
- CHECK(evt_ptr->AddPayloadOctets2(lmp_pal_subversion));
-
- return evt_ptr;
-}
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.2
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadLocalSupportedCommands(
- hci::Status status, const vector<uint8_t>& supported_commands) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_LOCAL_SUPPORTED_COMMANDS, status);
-
- CHECK(evt_ptr->AddPayloadOctets(64, supported_commands));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.4
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadLocalExtendedFeatures(
- hci::Status status, uint8_t page_number, uint8_t maximum_page_number, uint64_t extended_lmp_features) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_LOCAL_EXTENDED_FEATURES, status);
-
- CHECK(evt_ptr->AddPayloadOctets1(page_number));
- CHECK(evt_ptr->AddPayloadOctets1(maximum_page_number));
- CHECK(evt_ptr->AddPayloadOctets8(extended_lmp_features));
-
- return evt_ptr;
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateReadRemoteExtendedFeaturesEvent(
- hci::Status status, uint16_t handle, uint8_t page_number, uint8_t maximum_page_number,
- uint64_t extended_lmp_features) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::READ_REMOTE_EXTENDED_FEATURES_COMPLETE));
-
- CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
- CHECK(evt_ptr->AddPayloadOctets2(handle));
- CHECK(evt_ptr->AddPayloadOctets1(page_number));
- CHECK(evt_ptr->AddPayloadOctets1(maximum_page_number));
- CHECK(evt_ptr->AddPayloadOctets8(extended_lmp_features));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.5
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadBufferSize(
- hci::Status status, uint16_t hc_acl_data_packet_length, uint8_t hc_synchronous_data_packet_length,
- uint16_t hc_total_num_acl_data_packets, uint16_t hc_total_synchronous_data_packets) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_BUFFER_SIZE, status);
-
- CHECK(evt_ptr->AddPayloadOctets2(hc_acl_data_packet_length));
- CHECK(evt_ptr->AddPayloadOctets1(hc_synchronous_data_packet_length));
- CHECK(evt_ptr->AddPayloadOctets2(hc_total_num_acl_data_packets));
- CHECK(evt_ptr->AddPayloadOctets2(hc_total_synchronous_data_packets));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.6
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadBdAddr(hci::Status status,
- const Address& address) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_BD_ADDR, status);
-
- CHECK(evt_ptr->AddPayloadAddress(address));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.8
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadLocalSupportedCodecs(
- hci::Status status, const vector<uint8_t>& supported_codecs, const vector<uint32_t>& vendor_specific_codecs) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_LOCAL_SUPPORTED_CODECS, status);
-
- CHECK(evt_ptr->AddPayloadOctets1(supported_codecs.size()));
- CHECK(evt_ptr->AddPayloadOctets(supported_codecs));
- CHECK(evt_ptr->AddPayloadOctets1(vendor_specific_codecs.size()));
- for (size_t i = 0; i < vendor_specific_codecs.size(); i++)
- CHECK(evt_ptr->AddPayloadOctets4(vendor_specific_codecs[i]));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.6.1
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteReadLoopbackMode(hci::Status status,
- hci::LoopbackMode mode) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::READ_LOOPBACK_MODE, status);
- CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(mode)));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.2
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateInquiryResultEvent() {
- std::unique_ptr<RawBuilder> payload = std::unique_ptr<RawBuilder>(new CountedBuilder());
- std::unique_ptr<EventPacketBuilder> evt_ptr(new EventPacketBuilder(EventCode::INQUIRY_RESULT, std::move(payload)));
-
- return evt_ptr;
-}
-
-bool EventPacketBuilder::AddInquiryResult(const Address& address, uint8_t page_scan_repetition_mode,
- ClassOfDevice class_of_device, uint16_t clock_offset) {
- CHECK(event_code_ == EventCode::INQUIRY_RESULT);
-
- if (!CanAddPayloadOctets(14)) return false;
-
- std::unique_ptr<RawBuilder> result = std::make_unique<RawBuilder>();
-
- CHECK(result->AddAddress(address));
- CHECK(result->AddOctets1(page_scan_repetition_mode));
- CHECK(result->AddOctets2(0)); // Reserved
- CHECK(result->AddOctets1(class_of_device.cod[0]));
- CHECK(result->AddOctets1(class_of_device.cod[1]));
- CHECK(result->AddOctets1(class_of_device.cod[2]));
- CHECK(!(clock_offset & 0x8000));
- CHECK(result->AddOctets2(clock_offset));
- AddBuilder(std::move(result));
- return true;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.3
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateConnectionCompleteEvent(
- hci::Status status, uint16_t handle, const Address& address, hci::LinkType link_type, bool encryption_enabled) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::CONNECTION_COMPLETE));
-
- CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
- CHECK((handle & 0xf000) == 0); // Handles are 12-bit values.
- CHECK(evt_ptr->AddPayloadOctets2(handle));
- CHECK(evt_ptr->AddPayloadAddress(address));
- CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(link_type)));
- CHECK(evt_ptr->AddPayloadOctets1(encryption_enabled ? 1 : 0));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.4
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateConnectionRequestEvent(const Address& address,
- ClassOfDevice class_of_device,
- hci::LinkType link_type) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::CONNECTION_REQUEST));
-
- CHECK(evt_ptr->AddPayloadAddress(address));
- CHECK(evt_ptr->AddPayloadOctets1(class_of_device.cod[0]));
- CHECK(evt_ptr->AddPayloadOctets1(class_of_device.cod[1]));
- CHECK(evt_ptr->AddPayloadOctets1(class_of_device.cod[2]));
- CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(link_type)));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.5
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateDisconnectionCompleteEvent(hci::Status status,
- uint16_t handle,
- uint8_t reason) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::DISCONNECTION_COMPLETE));
-
- CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
- CHECK((handle & 0xf000) == 0); // Handles are 12-bit values.
- CHECK(evt_ptr->AddPayloadOctets2(handle));
- CHECK(evt_ptr->AddPayloadOctets1(reason));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.6
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateAuthenticationCompleteEvent(hci::Status status,
- uint16_t handle) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::AUTHENTICATION_COMPLETE));
- CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
- CHECK((handle & 0xf000) == 0); // Handles are 12-bit values.
- CHECK(evt_ptr->AddPayloadOctets2(handle));
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.7
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateRemoteNameRequestCompleteEvent(
- hci::Status status, const Address& address, const std::string& remote_name) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::REMOTE_NAME_REQUEST_COMPLETE));
-
- CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
- CHECK(evt_ptr->AddPayloadAddress(address));
- for (size_t i = 0; i < remote_name.length(); i++) CHECK(evt_ptr->AddPayloadOctets1(remote_name[i]));
- CHECK(evt_ptr->AddPayloadOctets1(0)); // Null terminated
- for (size_t i = 0; i < 248 - remote_name.length() - 1; i++) CHECK(evt_ptr->AddPayloadOctets1(0xFF));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.23
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLinkKeyRequestEvent(const Address& remote) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LINK_KEY_REQUEST));
- CHECK(evt_ptr->AddPayloadAddress(remote));
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.24
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLinkKeyNotificationEvent(const Address& remote,
- const std::vector<uint8_t>& key,
- uint8_t key_type) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LINK_KEY_NOTIFICATION));
- CHECK(evt_ptr->AddPayloadAddress(remote));
- CHECK(key.size() == 16);
- CHECK(evt_ptr->AddPayloadOctets(key));
- CHECK(evt_ptr->AddPayloadOctets1(key_type));
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.25
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLoopbackCommandEvent(hci::OpCode opcode,
- PacketView<true> payload) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LOOPBACK_COMMAND));
- CHECK(evt_ptr->AddPayloadOctets2(static_cast<uint16_t>(opcode)));
- for (const auto& payload_byte : payload) // Fill the packet.
- evt_ptr->AddPayloadOctets1(payload_byte);
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.28
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateReadClockOffsetEvent(hci::Status status, uint16_t handle,
- uint16_t offset) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::READ_CLOCK_OFFSET_COMPLETE));
- CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
- CHECK(evt_ptr->AddPayloadOctets2(handle));
- CHECK(evt_ptr->AddPayloadOctets2(offset));
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.29
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateConnectionPacketTypeChangedEvent(hci::Status status,
- uint16_t handle,
- uint16_t packet_type) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::CONNECTION_PACKET_TYPE_CHANGE));
- CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
- CHECK(evt_ptr->AddPayloadOctets2(handle));
- CHECK(evt_ptr->AddPayloadOctets2(packet_type));
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.37
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateSniffSubratingEvent(const hci::Status status,
- uint16_t handle) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::SNIFF_SUBRATING, status);
-
- CHECK(evt_ptr->AddPayloadOctets2(handle));
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.38
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateExtendedInquiryResultEvent(
- const Address& address, uint8_t page_scan_repetition_mode, ClassOfDevice class_of_device, uint16_t clock_offset,
- uint8_t rssi, const vector<uint8_t>& extended_inquiry_response) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::EXTENDED_INQUIRY_RESULT));
-
- CHECK(evt_ptr->AddPayloadOctets1(1)); // Always contains a single response
-
- CHECK(evt_ptr->AddPayloadAddress(address));
- CHECK(evt_ptr->AddPayloadOctets1(page_scan_repetition_mode));
- CHECK(evt_ptr->AddPayloadOctets1(0)); // Reserved
- CHECK(evt_ptr->AddPayloadOctets1(class_of_device.cod[0]));
- CHECK(evt_ptr->AddPayloadOctets1(class_of_device.cod[1]));
- CHECK(evt_ptr->AddPayloadOctets1(class_of_device.cod[2]));
- CHECK(!(clock_offset & 0x8000));
- CHECK(evt_ptr->AddPayloadOctets2(clock_offset));
- CHECK(evt_ptr->AddPayloadOctets1(rssi));
- CHECK(evt_ptr->AddPayloadOctets(extended_inquiry_response));
- evt_ptr->AddPayloadOctets1(0x00); // End marker
- while (evt_ptr->AddPayloadOctets1(0x00))
- ; // Fill packet
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.40
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateIoCapabilityRequestEvent(const Address& peer) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::IO_CAPABILITY_REQUEST));
-
- CHECK(evt_ptr->AddPayloadAddress(peer));
- return evt_ptr;
-} // namespace packets
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.41
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateIoCapabilityResponseEvent(
- const Address& peer, uint8_t io_capability, bool oob_data_present, uint8_t authentication_requirements) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::IO_CAPABILITY_RESPONSE));
-
- CHECK(evt_ptr->AddPayloadAddress(peer));
- CHECK(evt_ptr->AddPayloadOctets1(io_capability));
- CHECK(evt_ptr->AddPayloadOctets1(oob_data_present));
- CHECK(evt_ptr->AddPayloadOctets1(authentication_requirements));
- return evt_ptr;
-} // namespace test_vendor_lib
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.42
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateUserConfirmationRequestEvent(const Address& peer,
- uint32_t numeric_value) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::USER_CONFIRMATION_REQUEST));
-
- CHECK(evt_ptr->AddPayloadAddress(peer));
- CHECK(evt_ptr->AddPayloadOctets4(numeric_value));
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.43
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateUserPasskeyRequestEvent(const Address& peer) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::USER_PASSKEY_REQUEST));
-
- CHECK(evt_ptr->AddPayloadAddress(peer));
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.44
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateRemoteOobDataRequestEvent(const Address& peer) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::REMOTE_OOB_DATA_REQUEST));
-
- CHECK(evt_ptr->AddPayloadAddress(peer));
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.45
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateSimplePairingCompleteEvent(hci::Status status,
- const Address& peer) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::SIMPLE_PAIRING_COMPLETE));
-
- CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
- CHECK(evt_ptr->AddPayloadAddress(peer));
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.48
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateUserPasskeyNotificationEvent(const Address& peer,
- uint32_t passkey) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::USER_PASSKEY_NOTIFICATION));
-
- CHECK(evt_ptr->AddPayloadAddress(peer));
- CHECK(evt_ptr->AddPayloadOctets4(passkey));
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.49
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateKeypressNotificationEvent(const Address& peer,
- uint8_t notification_type) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::KEYPRESS_NOTIFICATION));
-
- CHECK(evt_ptr->AddPayloadAddress(peer));
- CHECK(evt_ptr->AddPayloadOctets1(notification_type));
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.1
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLeConnectionCompleteEvent(
- hci::Status status, uint16_t handle, uint8_t role, uint8_t peer_address_type, const Address& peer,
- uint16_t interval, uint16_t latency, uint16_t supervision_timeout) {
- std::unique_ptr<RawBuilder> meta_evt = LeMetaEventBuilder::CreateLeConnectionCompleteEvent(
- status, handle, role, peer_address_type, peer, interval, latency, supervision_timeout);
-
- return std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LE_META_EVENT, std::move(meta_evt)));
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLeEnhancedConnectionCompleteEvent(
- hci::Status status, uint16_t handle, uint8_t role, uint8_t peer_address_type, const Address& peer,
- const Address& local_private_address, const Address& peer_private_address, uint16_t interval, uint16_t latency,
- uint16_t supervision_timeout) {
- std::unique_ptr<RawBuilder> meta_evt = LeMetaEventBuilder::CreateLeEnhancedConnectionCompleteEvent(
- status, handle, role, peer_address_type, peer, local_private_address, peer_private_address, interval, latency,
- supervision_timeout);
-
- return std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LE_META_EVENT, std::move(meta_evt)));
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLeConnectionUpdateCompleteEvent(
- hci::Status status, uint16_t handle, uint16_t interval, uint16_t latency, uint16_t supervision_timeout) {
- std::unique_ptr<RawBuilder> meta_evt =
- LeMetaEventBuilder::CreateLeConnectionUpdateCompleteEvent(status, handle, interval, latency, supervision_timeout);
-
- return std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LE_META_EVENT, std::move(meta_evt)));
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.2
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLeAdvertisingReportEvent() {
- std::unique_ptr<RawBuilder> meta_evt = LeMetaEventBuilder::CreateLeAdvertisingReportEvent();
-
- return std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LE_META_EVENT, std::move(meta_evt)));
-}
-
-bool EventPacketBuilder::AddLeAdvertisingReport(LeAdvertisement::AdvertisementType event_type,
- LeAdvertisement::AddressType addr_type, const Address& addr,
- const vector<uint8_t>& data, uint8_t rssi) {
- CHECK(event_code_ == EventCode::LE_META_EVENT);
-
- // Upcast the payload to add the next report.
- LeMetaEventBuilder* meta_ptr = static_cast<LeMetaEventBuilder*>(payload_.get());
- return meta_ptr->AddLeAdvertisingReport(event_type, addr_type, addr, data, rssi);
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.4
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateLeRemoteUsedFeaturesEvent(hci::Status status,
- uint16_t handle,
- uint64_t features) {
- std::unique_ptr<RawBuilder> meta_evt = LeMetaEventBuilder::CreateLeRemoteUsedFeaturesEvent(status, handle, features);
- return std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::LE_META_EVENT, std::move(meta_evt)));
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateRemoteSupportedFeaturesEvent(hci::Status status,
- uint16_t handle,
- uint64_t features) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::READ_REMOTE_SUPPORTED_FEATURES_COMPLETE));
-
- CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
- CHECK(evt_ptr->AddPayloadOctets2(handle));
- CHECK(evt_ptr->AddPayloadOctets8(features));
-
- return evt_ptr;
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLinkKeyRequestReply(hci::Status status,
- Address address) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LINK_KEY_REQUEST_REPLY, status);
-
- CHECK(evt_ptr->AddPayloadAddress(address));
-
- return evt_ptr;
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLinkKeyRequestNegativeReply(
- hci::Status status, Address address) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LINK_KEY_REQUEST_NEGATIVE_REPLY, status);
-
- CHECK(evt_ptr->AddPayloadAddress(address));
-
- return evt_ptr;
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteWriteLinkPolicySettings(hci::Status status,
- uint16_t handle) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::WRITE_LINK_POLICY_SETTINGS, status);
-
- CHECK(evt_ptr->AddPayloadOctets2(handle));
-
- return evt_ptr;
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteWriteLinkSupervisionTimeout(
- hci::Status status, uint16_t handle) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::WRITE_LINK_SUPERVISION_TIMEOUT, status);
-
- CHECK(evt_ptr->AddPayloadOctets2(handle));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.2
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLeReadBufferSize(
- hci::Status status, uint16_t hc_le_data_packet_length, uint8_t hc_total_num_le_data_packets) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LE_READ_BUFFER_SIZE, status);
-
- CHECK(evt_ptr->AddPayloadOctets2(hc_le_data_packet_length));
- CHECK(evt_ptr->AddPayloadOctets1(hc_total_num_le_data_packets));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.3
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLeReadLocalSupportedFeatures(
- hci::Status status, uint64_t le_features) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LE_READ_LOCAL_SUPPORTED_FEATURES, status);
-
- CHECK(evt_ptr->AddPayloadOctets8(le_features));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.14
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLeReadWhiteListSize(
- hci::Status status, uint8_t white_list_size) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LE_READ_WHITE_LIST_SIZE, status);
-
- CHECK(evt_ptr->AddPayloadOctets8(white_list_size));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.23
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLeRand(hci::Status status,
- uint64_t random_val) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LE_RAND, status);
-
- CHECK(evt_ptr->AddPayloadOctets8(random_val));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.27
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLeReadSupportedStates(hci::Status status,
- uint64_t le_states) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LE_READ_SUPPORTED_STATES, status);
-
- CHECK(evt_ptr->AddPayloadOctets8(le_states));
-
- return evt_ptr;
-}
-
-// Vendor-specific commands
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateCommandCompleteLeGetVendorCapabilities(
- hci::Status status, const vector<uint8_t>& vendor_cap) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- EventPacketBuilder::CreateCommandCompleteOnlyStatusEvent(OpCode::LE_GET_VENDOR_CAPABILITIES, status);
-
- CHECK(evt_ptr->AddPayloadOctets(vendor_cap));
-
- return evt_ptr;
-}
-
-std::unique_ptr<EventPacketBuilder> EventPacketBuilder::CreateEncryptionChange(hci::Status status, uint16_t handle,
- uint8_t encryption_enable) {
- std::unique_ptr<EventPacketBuilder> evt_ptr =
- std::unique_ptr<EventPacketBuilder>(new EventPacketBuilder(EventCode::ENCRYPTION_CHANGE));
-
- CHECK(evt_ptr->AddPayloadOctets1(static_cast<uint8_t>(status)));
- CHECK(evt_ptr->AddPayloadOctets2(handle));
- CHECK(evt_ptr->AddPayloadOctets1(encryption_enable));
-
- return evt_ptr;
-}
-
-size_t EventPacketBuilder::size() const {
- size_t header_size = 2; // Event code and payload size
- return header_size + payload_->size();
-}
-
-void EventPacketBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const {
- insert(static_cast<uint8_t>(event_code_), it);
- uint8_t payload_size = size() - 2; // Event code and payload size
- CHECK(size() - 2 == static_cast<size_t>(payload_size)) << "Payload too large for an event: " << size();
- insert(payload_size, it);
- payload_->Serialize(it);
-}
-
-bool EventPacketBuilder::CanAddPayloadOctets(size_t octets) {
- return payload_->CanAddOctets(octets);
-}
-
-bool EventPacketBuilder::AddPayloadOctets(size_t octets, const std::vector<uint8_t>& bytes) {
- return payload_->AddOctets(octets, bytes);
-}
-
-bool EventPacketBuilder::AddPayloadOctets(const std::vector<uint8_t>& bytes) {
- return payload_->AddOctets(bytes);
-}
-
-bool EventPacketBuilder::AddPayloadOctets1(uint8_t value) {
- return payload_->AddOctets1(value);
-}
-
-bool EventPacketBuilder::AddPayloadOctets2(uint16_t value) {
- return payload_->AddOctets2(value);
-}
-
-bool EventPacketBuilder::AddPayloadOctets3(uint32_t value) {
- return payload_->AddOctets3(value);
-}
-
-bool EventPacketBuilder::AddPayloadOctets4(uint32_t value) {
- return payload_->AddOctets4(value);
-}
-
-bool EventPacketBuilder::AddPayloadOctets6(uint64_t value) {
- return payload_->AddOctets6(value);
-}
-
-bool EventPacketBuilder::AddPayloadOctets8(uint64_t value) {
- return payload_->AddOctets8(value);
-}
-
-bool EventPacketBuilder::AddPayloadAddress(Address address) {
- return payload_->AddAddress(address);
-}
-
-bool EventPacketBuilder::AddBuilder(std::unique_ptr<BasePacketBuilder> builder) {
- // Upcast the payload to add the next builder.
- CountedBuilder* temp_ptr = static_cast<CountedBuilder*>(payload_.get());
- temp_ptr->Add(std::move(builder));
- return true;
-}
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/event_packet_builder.h b/vendor_libs/test_vendor_lib/packets/hci/event_packet_builder.h
deleted file mode 100644
index 495e47a..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/event_packet_builder.h
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <base/logging.h>
-#include <cstdint>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "include/hci.h"
-#include "include/le_advertisement.h"
-#include "packets/counted_builder.h"
-#include "packets/hci/hci_packet_builder.h"
-#include "packets/packet_builder.h"
-#include "packets/packet_view.h"
-#include "packets/raw_builder.h"
-#include "types/address.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// Event Packets are specified in the Bluetooth Core Specification Version 4.2,
-// Volume 2, Part E, Section 5.4.4 (page 477). Event Packets begin with a 2
-// octet header formatted as follows:
-// - Event Code: 1 octet
-// - Parameter Total Length: 1 octet
-class EventPacketBuilder : public HciPacketBuilder {
- public:
- virtual ~EventPacketBuilder() override = default;
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.1
- static std::unique_ptr<EventPacketBuilder> CreateInquiryCompleteEvent(hci::Status status);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.14
- // This should only be used for testing to send non-standard packets
- // Most code should use the more specific functions that follow
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteEvent(
- hci::OpCode command_opcode, const std::vector<uint8_t>& event_return_parameters);
-
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteOnlyStatusEvent(hci::OpCode command_opcode,
- hci::Status status);
-
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteStatusAndAddressEvent(hci::OpCode command_opcode,
- hci::Status status,
- const Address& address);
-
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteUnknownOpCodeEvent(uint16_t command_opcode);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.15
- static std::unique_ptr<EventPacketBuilder> CreateCommandStatusEvent(hci::Status status, hci::OpCode command_opcode);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.19
- static std::unique_ptr<EventPacketBuilder> CreateNumberOfCompletedPacketsEvent(uint16_t handle,
- uint16_t num_completed_packets);
-
- void AddCompletedPackets(uint16_t handle, uint16_t num_completed_packets);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.1.10
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLinkKeyRequestReply(hci::Status status,
- Address address);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.1.11
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLinkKeyRequestNegativeReply(hci::Status status,
- Address address);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.2.10
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteWriteLinkPolicySettings(hci::Status status,
- uint16_t handle);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.10
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteDeleteStoredLinkKey(hci::Status status,
- uint16_t num_keys_deleted);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.12
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadLocalName(hci::Status status,
- const std::vector<uint8_t>& local_name);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.23
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadAuthenticationEnable(hci::Status status,
- uint8_t enable);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.3.42
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteWriteLinkSupervisionTimeout(hci::Status status,
- uint16_t handle);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.1
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadLocalVersionInformation(
- hci::Status status, uint8_t hci_version, uint16_t hci_revision, uint8_t lmp_pal_version,
- uint16_t manufacturer_name, uint16_t lmp_pal_subversion);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.2
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadLocalSupportedCommands(
- hci::Status status, const std::vector<uint8_t>& supported_commands);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.4
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadLocalExtendedFeatures(
- hci::Status status, uint8_t page_number, uint8_t maximum_page_number, uint64_t extended_lmp_features);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.5
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadBufferSize(
- hci::Status status, uint16_t hc_acl_data_packet_length, uint8_t hc_synchronous_data_packet_length,
- uint16_t hc_total_num_acl_data_packets, uint16_t hc_total_synchronous_data_packets);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.6
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadBdAddr(hci::Status status,
- const Address& bt_address);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.4.8
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadLocalSupportedCodecs(
- hci::Status status, const std::vector<uint8_t>& supported_codecs,
- const std::vector<uint32_t>& vendor_specific_codecs);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.6.1
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteReadLoopbackMode(hci::Status status,
- hci::LoopbackMode mode);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.2
- static std::unique_ptr<EventPacketBuilder> CreateInquiryResultEvent();
-
- // Returns true if the result can be added to the event packet.
- bool AddInquiryResult(const Address& bt_address, uint8_t page_scan_repetition_mode, ClassOfDevice class_of_device,
- uint16_t clock_offset);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.3
- static std::unique_ptr<EventPacketBuilder> CreateConnectionCompleteEvent(hci::Status status, uint16_t handle,
- const Address& address,
- hci::LinkType link_type,
- bool encryption_enabled);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.4
- static std::unique_ptr<EventPacketBuilder> CreateConnectionRequestEvent(const Address& address,
- ClassOfDevice class_of_device,
- hci::LinkType link_type);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.5
- static std::unique_ptr<EventPacketBuilder> CreateDisconnectionCompleteEvent(hci::Status status, uint16_t handle,
- uint8_t reason);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.6
- static std::unique_ptr<EventPacketBuilder> CreateAuthenticationCompleteEvent(hci::Status status, uint16_t handle);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.7
- static std::unique_ptr<EventPacketBuilder> CreateRemoteNameRequestCompleteEvent(hci::Status status,
- const Address& bt_address,
- const std::string& name);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.11
- static std::unique_ptr<EventPacketBuilder> CreateRemoteSupportedFeaturesEvent(hci::Status status, uint16_t handle,
- uint64_t features);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.12
- static std::unique_ptr<EventPacketBuilder> CreateReadRemoteVersionInformationEvent(hci::Status status,
- uint16_t connection_handle,
- uint8_t lmp_pal_version,
- uint16_t manufacturer_name,
- uint16_t lmp_pal_subversion);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.23
- static std::unique_ptr<EventPacketBuilder> CreateLinkKeyRequestEvent(const Address& remote);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.24
- static std::unique_ptr<EventPacketBuilder> CreateLinkKeyNotificationEvent(const Address& remote,
- const std::vector<uint8_t>& key,
- uint8_t key_type);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.25
- static std::unique_ptr<EventPacketBuilder> CreateLoopbackCommandEvent(hci::OpCode opcode, PacketView<true> payload);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.28
- static std::unique_ptr<EventPacketBuilder> CreateReadClockOffsetEvent(hci::Status status, uint16_t handle,
- uint16_t packet_type);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.29
- static std::unique_ptr<EventPacketBuilder> CreateConnectionPacketTypeChangedEvent(hci::Status status, uint16_t handle,
- uint16_t offset);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.34
- static std::unique_ptr<EventPacketBuilder> CreateReadRemoteExtendedFeaturesEvent(hci::Status status, uint16_t handle,
- uint8_t page_number,
- uint8_t maximum_page_number,
- uint64_t extended_lmp_features);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.37
- static std::unique_ptr<EventPacketBuilder> CreateSniffSubratingEvent(hci::Status status, uint16_t handle);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.38
- static std::unique_ptr<EventPacketBuilder> CreateExtendedInquiryResultEvent(
- const Address& bt_address, uint8_t page_scan_repetition_mode, ClassOfDevice class_of_device,
- uint16_t clock_offset, uint8_t rssi, const std::vector<uint8_t>& extended_inquiry_response);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.40
- static std::unique_ptr<EventPacketBuilder> CreateIoCapabilityRequestEvent(const Address& peer);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.41
- static std::unique_ptr<EventPacketBuilder> CreateIoCapabilityResponseEvent(const Address& peer, uint8_t io_capability,
- bool oob_data_present,
- uint8_t authentication_requirements);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.42
- static std::unique_ptr<EventPacketBuilder> CreateUserConfirmationRequestEvent(const Address& peer,
- uint32_t numeric_value);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.43
- static std::unique_ptr<EventPacketBuilder> CreateUserPasskeyRequestEvent(const Address& peer);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.44
- static std::unique_ptr<EventPacketBuilder> CreateRemoteOobDataRequestEvent(const Address& peer);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.45
- static std::unique_ptr<EventPacketBuilder> CreateSimplePairingCompleteEvent(hci::Status status, const Address& peer);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.48
- static std::unique_ptr<EventPacketBuilder> CreateUserPasskeyNotificationEvent(const Address& peer, uint32_t passkey);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.49
- static std::unique_ptr<EventPacketBuilder> CreateKeypressNotificationEvent(const Address& peer,
- uint8_t notification_type);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
- // 7.7.65.1
- static std::unique_ptr<EventPacketBuilder> CreateLeConnectionCompleteEvent(hci::Status status, uint16_t handle,
- uint8_t role, uint8_t peer_address_type,
- const Address& peer, uint16_t interval,
- uint16_t latency,
- uint16_t supervision_timeout);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
- // 7.7.65.2
- static std::unique_ptr<EventPacketBuilder> CreateLeAdvertisingReportEvent();
-
- // Returns true if the report can be added to the event packet.
- bool AddLeAdvertisingReport(LeAdvertisement::AdvertisementType event_type, LeAdvertisement::AddressType addr_type,
- const Address& addr, const std::vector<uint8_t>& data, uint8_t rssi);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
- // 7.7.65.3
- static std::unique_ptr<EventPacketBuilder> CreateLeConnectionUpdateCompleteEvent(hci::Status status, uint16_t handle,
- uint16_t interval, uint16_t latency,
- uint16_t supervision_timeout);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
- // 7.7.65.4
- static std::unique_ptr<EventPacketBuilder> CreateLeRemoteUsedFeaturesEvent(hci::Status status, uint16_t handle,
- uint64_t features);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
- // 7.7.65.10
- static std::unique_ptr<EventPacketBuilder> CreateLeEnhancedConnectionCompleteEvent(
- hci::Status status, uint16_t handle, uint8_t role, uint8_t peer_address_type, const Address& peer,
- const Address& local_private_address, const Address& peer_private_address, uint16_t interval, uint16_t latency,
- uint16_t supervision_timeout);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.2
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLeReadBufferSize(
- hci::Status status, uint16_t hc_le_data_packet_length, uint8_t hc_total_num_le_data_packets);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.3
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLeReadLocalSupportedFeatures(hci::Status status,
- uint64_t le_features);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.14
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLeReadWhiteListSize(hci::Status status,
- uint8_t white_list_size);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.23
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLeRand(hci::Status status, uint64_t random_val);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.8.27
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLeReadSupportedStates(hci::Status status,
- uint64_t le_states);
-
- /*
- static std::unique_ptr<EventPacketBuilder>
- CreateLeStartEncryption(hci::Status status, uint8_t encryption_enable);
-*/
- static std::unique_ptr<EventPacketBuilder> CreateEncryptionChange(hci::Status status, uint16_t handle,
- uint8_t encryption_enable);
-
- // Vendor-specific commands
-
- static std::unique_ptr<EventPacketBuilder> CreateCommandCompleteLeGetVendorCapabilities(
- hci::Status status, const std::vector<uint8_t>& vendor_cap);
-
- virtual size_t size() const override;
-
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override;
-
- bool CanAddPayloadOctets(size_t octets);
-
- bool AddPayloadOctets(size_t octets, const std::vector<uint8_t>& bytes);
-
- bool AddPayloadOctets(const std::vector<uint8_t>& bytes);
-
- bool AddPayloadOctets1(uint8_t value);
- bool AddPayloadOctets2(uint16_t value);
- bool AddPayloadOctets3(uint32_t value);
- bool AddPayloadOctets4(uint32_t value);
- bool AddPayloadOctets6(uint64_t value);
- bool AddPayloadOctets8(uint64_t value);
-
- bool AddPayloadAddress(Address address);
-
- bool AddBuilder(std::unique_ptr<BasePacketBuilder> builder);
-
- private:
- explicit EventPacketBuilder(hci::EventCode event_code);
- explicit EventPacketBuilder(hci::EventCode event_code, std::unique_ptr<RawBuilder> payload);
- hci::EventCode event_code_;
- std::unique_ptr<RawBuilder> payload_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/event_payload_builder.cc b/vendor_libs/test_vendor_lib/packets/hci/event_payload_builder.cc
deleted file mode 100644
index dd866a2..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/event_payload_builder.cc
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright 2018 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 "event_payload_builder.h"
-
-#include <base/logging.h>
-#include <algorithm>
-
-using std::vector;
-
-namespace test_vendor_lib {
-namespace packets {
-
-EventPayloadBuilder::EventPayloadBuilder(size_t max_bytes) : max_bytes_(max_bytes) {}
-
-bool EventPayloadBuilder::AddPayloadOctets(size_t octets, const vector<uint8_t>& bytes) {
- if (payload_.size() + octets > max_bytes_) return false;
-
- if (octets != bytes.size()) return false;
-
- payload_.insert(payload_.end(), bytes.begin(), bytes.end());
-
- return true;
-}
-
-bool EventPayloadBuilder::AddPayloadOctets(const vector<uint8_t>& bytes) {
- return AddPayloadOctets(bytes.size(), bytes);
-}
-
-bool EventPayloadBuilder::AddPayloadOctets(size_t octets, uint64_t value) {
- vector<uint8_t> val_vector;
-
- uint64_t v = value;
-
- if (octets > sizeof(uint64_t)) return false;
-
- for (size_t i = 0; i < octets; i++) {
- val_vector.push_back(v & 0xff);
- v = v >> 8;
- }
-
- if (v != 0) return false;
-
- return AddPayloadOctets(octets, val_vector);
-}
-
-bool EventPayloadBuilder::AddPayloadAddress(const Address& address) {
- if (payload_.size() + Address::kLength > max_bytes_) return false;
-
- for (size_t i = 0; i < Address::kLength; i++) {
- payload_.push_back(address.address[i]);
- }
- return true;
-}
-
-bool EventPayloadBuilder::AddPayloadOctets1(uint8_t value) {
- return AddPayloadOctets(1, value);
-}
-
-bool EventPayloadBuilder::AddPayloadOctets2(uint16_t value) {
- return AddPayloadOctets(2, value);
-}
-
-bool EventPayloadBuilder::AddPayloadOctets3(uint32_t value) {
- return AddPayloadOctets(3, value);
-}
-
-bool EventPayloadBuilder::AddPayloadOctets4(uint32_t value) {
- return AddPayloadOctets(4, value);
-}
-
-bool EventPayloadBuilder::AddPayloadOctets6(uint64_t value) {
- return AddPayloadOctets(6, value);
-}
-
-bool EventPayloadBuilder::AddPayloadOctets8(uint64_t value) {
- return AddPayloadOctets(8, value);
-}
-
-bool EventPayloadBuilder::CanAddPayloadOctets(size_t num_bytes) const {
- return payload_.size() + num_bytes <= max_bytes_;
-}
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/event_payload_builder.h b/vendor_libs/test_vendor_lib/packets/hci/event_payload_builder.h
deleted file mode 100644
index b656edf..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/event_payload_builder.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <vector>
-
-#include "packets/packet_builder.h"
-#include "types/address.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class EventPayloadBuilder : public PacketBuilder<true> {
- public:
- EventPayloadBuilder() = default;
- EventPayloadBuilder(size_t max_bytes);
- virtual ~EventPayloadBuilder() = default;
-
- virtual size_t size() const override;
-
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const;
-
- // Add |octets| bytes to the payload. Return true if:
- // - the size of |bytes| is equal to |octets| and
- // - the new size of the payload is still < |max_bytes_|
- bool AddPayloadOctets(size_t octets, const std::vector<uint8_t>& bytes);
-
- bool AddPayloadOctets(const std::vector<uint8_t>& bytes);
-
- bool AddPayloadOctets1(uint8_t value);
- bool AddPayloadOctets2(uint16_t value);
- bool AddPayloadOctets3(uint32_t value);
- bool AddPayloadOctets4(uint32_t value);
- bool AddPayloadOctets6(uint64_t value);
- bool AddPayloadOctets8(uint64_t value);
-
- private:
- // Add |octets| bytes to the payload. Return true if:
- // - the value of |value| fits in |octets| bytes and
- // - the new size of the payload is still < |max_bytes_|
- bool AddPayloadOctets(size_t octets, uint64_t value);
-
- // Add |address| to the payload. Return true if:
- // - the new size of the payload is still < |max_bytes_|
- bool AddPayloadAddress(const Address& address);
-
- // Return true if |num_bytes| can be added to the payload.
- bool CanAddPayloadOctets(size_t num_bytes) const;
-
- size_t max_bytes_{255};
-
- // Underlying containers for storing the actual packet
- std::vector<uint8_t> payload_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/hci_packet_builder.cc b/vendor_libs/test_vendor_lib/packets/hci/hci_packet_builder.cc
deleted file mode 100644
index 1d5689b..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/hci_packet_builder.cc
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2018 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 "packets/hci/hci_packet_builder.h"
-
-using std::vector;
-
-namespace test_vendor_lib {
-namespace packets {
-
-std::shared_ptr<std::vector<uint8_t>> HciPacketBuilder::ToVector() {
- std::shared_ptr<std::vector<uint8_t>> to_return = std::make_shared<std::vector<uint8_t>>();
- std::back_insert_iterator<std::vector<uint8_t>> it(*to_return);
- Serialize(it);
- return to_return;
-}
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/hci_packet_builder.h b/vendor_libs/test_vendor_lib/packets/hci/hci_packet_builder.h
deleted file mode 100644
index d508696..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/hci_packet_builder.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// Base packet for HCI packets specified in the Bluetooth Core Specification
-// Version 4.2, Volume 2, Part E, Section 5.4
-class HciPacketBuilder : public PacketBuilder<true> {
- public:
- virtual ~HciPacketBuilder() override = default;
-
- std::shared_ptr<std::vector<uint8_t>> ToVector();
-
- protected:
- HciPacketBuilder() = default;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/le_meta_event_builder.cc b/vendor_libs/test_vendor_lib/packets/hci/le_meta_event_builder.cc
deleted file mode 100644
index f0599a7..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/le_meta_event_builder.cc
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright 2018 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 "packets/hci/le_meta_event_builder.h"
-
-#include <base/logging.h>
-
-using std::vector;
-using test_vendor_lib::hci::LeSubEventCode;
-using test_vendor_lib::hci::Status;
-
-namespace test_vendor_lib {
-namespace packets {
-
-LeMetaEventBuilder::LeMetaEventBuilder(LeSubEventCode sub_event_code)
- : sub_event_code_(sub_event_code), payload_(std::make_unique<RawBuilder>()) {}
-
-LeMetaEventBuilder::LeMetaEventBuilder(LeSubEventCode sub_event_code, std::unique_ptr<RawBuilder> payload)
- : sub_event_code_(sub_event_code), payload_(std::move(payload)) {}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.1
-std::unique_ptr<LeMetaEventBuilder> LeMetaEventBuilder::CreateLeConnectionCompleteEvent(
- Status status, uint16_t handle, uint8_t role, uint8_t peer_address_type, const Address& peer, uint16_t interval,
- uint16_t latency, uint16_t supervision_timeout) {
- std::unique_ptr<LeMetaEventBuilder> evt_ptr =
- std::unique_ptr<LeMetaEventBuilder>(new LeMetaEventBuilder(LeSubEventCode::CONNECTION_COMPLETE));
-
- CHECK(evt_ptr->AddOctets1(static_cast<uint8_t>(status)));
- CHECK(evt_ptr->AddOctets2(handle));
- CHECK(evt_ptr->AddOctets1(role));
- CHECK(evt_ptr->AddOctets1(peer_address_type));
- CHECK(evt_ptr->AddAddress(peer));
- CHECK(evt_ptr->AddOctets2(interval));
- CHECK(evt_ptr->AddOctets2(latency));
- CHECK(evt_ptr->AddOctets2(supervision_timeout));
- CHECK(evt_ptr->AddOctets1(0x00)); // Master Clock Accuracy (unused for master)
-
- return evt_ptr;
-}
-
-std::unique_ptr<LeMetaEventBuilder> LeMetaEventBuilder::CreateLeEnhancedConnectionCompleteEvent(
- Status status, uint16_t handle, uint8_t role, uint8_t peer_address_type, const Address& peer,
- const Address& local_private_address, const Address& peer_private_address, uint16_t interval, uint16_t latency,
- uint16_t supervision_timeout) {
- std::unique_ptr<LeMetaEventBuilder> evt_ptr =
- std::unique_ptr<LeMetaEventBuilder>(new LeMetaEventBuilder(LeSubEventCode::ENHANCED_CONNECTION_COMPLETE));
-
- CHECK(evt_ptr->AddOctets1(static_cast<uint8_t>(status)));
- CHECK(evt_ptr->AddOctets2(handle));
- CHECK(evt_ptr->AddOctets1(role));
- CHECK(evt_ptr->AddOctets1(peer_address_type));
- CHECK(evt_ptr->AddAddress(peer));
- CHECK(evt_ptr->AddAddress(local_private_address));
- CHECK(evt_ptr->AddAddress(peer_private_address));
- CHECK(evt_ptr->AddOctets2(interval));
- CHECK(evt_ptr->AddOctets2(latency));
- CHECK(evt_ptr->AddOctets2(supervision_timeout));
- CHECK(evt_ptr->AddOctets1(0x00)); // Master Clock Accuracy (unused for master)
-
- return evt_ptr;
-}
-
-std::unique_ptr<LeMetaEventBuilder> LeMetaEventBuilder::CreateLeConnectionUpdateCompleteEvent(
- Status status, uint16_t handle, uint16_t interval, uint16_t latency, uint16_t supervision_timeout) {
- std::unique_ptr<LeMetaEventBuilder> evt_ptr =
- std::unique_ptr<LeMetaEventBuilder>(new LeMetaEventBuilder(LeSubEventCode::CONNECTION_UPDATE_COMPLETE));
-
- CHECK(evt_ptr->AddOctets1(static_cast<uint8_t>(status)));
- CHECK(evt_ptr->AddOctets2(handle));
- CHECK(evt_ptr->AddOctets2(interval));
- CHECK(evt_ptr->AddOctets2(latency));
- CHECK(evt_ptr->AddOctets2(supervision_timeout));
-
- return evt_ptr;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.2
-std::unique_ptr<LeMetaEventBuilder> LeMetaEventBuilder::CreateLeAdvertisingReportEvent() {
- std::unique_ptr<LeMetaEventBuilder> evt_ptr = std::unique_ptr<LeMetaEventBuilder>(
- new LeMetaEventBuilder(LeSubEventCode::ADVERTISING_REPORT, std::unique_ptr<RawBuilder>(new CountedBuilder())));
-
- return evt_ptr;
-}
-
-bool LeMetaEventBuilder::AddLeAdvertisingReport(LeAdvertisement::AdvertisementType event_type,
- LeAdvertisement::AddressType addr_type, const Address& addr,
- const vector<uint8_t>& data, uint8_t rssi) {
- if (!CanAddOctets(10 + data.size())) return false;
-
- CHECK(sub_event_code_ == LeSubEventCode::ADVERTISING_REPORT);
-
- std::unique_ptr<RawBuilder> ad = std::make_unique<RawBuilder>();
-
- CHECK(ad->AddOctets1(static_cast<uint8_t>(event_type)));
- CHECK(ad->AddOctets1(static_cast<uint8_t>(addr_type)));
- CHECK(ad->AddAddress(addr));
- CHECK(ad->AddOctets1(data.size()));
- CHECK(ad->AddOctets(data));
- CHECK(ad->AddOctets1(rssi));
- AddBuilder(std::move(ad));
- return true;
-}
-
-// Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section 7.7.65.4
-std::unique_ptr<LeMetaEventBuilder> LeMetaEventBuilder::CreateLeRemoteUsedFeaturesEvent(Status status, uint16_t handle,
- uint64_t features) {
- std::unique_ptr<LeMetaEventBuilder> evt_ptr =
- std::unique_ptr<LeMetaEventBuilder>(new LeMetaEventBuilder(LeSubEventCode::READ_REMOTE_FEATURES_COMPLETE));
-
- CHECK(evt_ptr->AddOctets1(static_cast<uint8_t>(status)));
- CHECK(evt_ptr->AddOctets2(handle));
- CHECK(evt_ptr->AddOctets8(features));
-
- return evt_ptr;
-}
-
-size_t LeMetaEventBuilder::size() const {
- return 1 + payload_->size(); // Add the sub_event_code
-}
-
-void LeMetaEventBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const {
- insert(static_cast<uint8_t>(sub_event_code_), it);
- uint8_t payload_size = size() - sizeof(uint8_t);
- CHECK(size() - sizeof(uint8_t) == static_cast<size_t>(payload_size)) << "Payload too large for an event: " << size();
- payload_->Serialize(it);
-}
-
-bool LeMetaEventBuilder::AddBuilder(std::unique_ptr<BasePacketBuilder> builder) {
- // Upcast the payload to add the next builder.
- CountedBuilder* temp_ptr = static_cast<CountedBuilder*>(payload_.get());
- temp_ptr->Add(std::move(builder));
- return true;
-}
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/le_meta_event_builder.h b/vendor_libs/test_vendor_lib/packets/hci/le_meta_event_builder.h
deleted file mode 100644
index b1d713d..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/le_meta_event_builder.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <base/logging.h>
-#include <cstdint>
-#include <memory>
-#include <string>
-#include <vector>
-
-#include "include/hci.h"
-#include "include/le_advertisement.h"
-#include "packets/counted_builder.h"
-#include "packets/hci/hci_packet_builder.h"
-#include "packets/packet_builder.h"
-#include "packets/packet_view.h"
-#include "packets/raw_builder.h"
-#include "types/address.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// LE Meta Event Packets are specified in the Bluetooth Core Specification
-// Version 4.2, Volume 2, Part E, Section 7.7.65. The first byte is the
-// Subevent_Code.
-class LeMetaEventBuilder : public RawBuilder {
- public:
- virtual ~LeMetaEventBuilder() override = default;
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
- // 7.7.65.1
- static std::unique_ptr<LeMetaEventBuilder> CreateLeConnectionCompleteEvent(hci::Status status, uint16_t handle,
- uint8_t role, uint8_t peer_address_type,
- const Address& peer, uint16_t interval,
- uint16_t latency,
- uint16_t supervision_timeout);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
- // 7.7.65.2
- static std::unique_ptr<LeMetaEventBuilder> CreateLeAdvertisingReportEvent();
-
- // Returns true if the report can be added to the event packet.
- bool AddLeAdvertisingReport(LeAdvertisement::AdvertisementType event_type, LeAdvertisement::AddressType addr_type,
- const Address& addr, const std::vector<uint8_t>& data, uint8_t rssi);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
- // 7.7.65.3
- static std::unique_ptr<LeMetaEventBuilder> CreateLeConnectionUpdateCompleteEvent(hci::Status status, uint16_t handle,
- uint16_t interval, uint16_t latency,
- uint16_t supervision_timeout);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
- // 7.7.65.4
- static std::unique_ptr<LeMetaEventBuilder> CreateLeRemoteUsedFeaturesEvent(hci::Status status, uint16_t handle,
- uint64_t features);
-
- // Bluetooth Core Specification Version 4.2, Volume 2, Part E, Section
- // 7.7.65.10
- static std::unique_ptr<LeMetaEventBuilder> CreateLeEnhancedConnectionCompleteEvent(
- hci::Status status, uint16_t handle, uint8_t role, uint8_t peer_address_type, const Address& peer,
- const Address& local_private_address, const Address& peer_private_address, uint16_t interval, uint16_t latency,
- uint16_t supervision_timeout);
-
- virtual size_t size() const override;
-
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override;
-
- bool AddBuilder(std::unique_ptr<BasePacketBuilder> builder);
-
- private:
- explicit LeMetaEventBuilder(hci::LeSubEventCode sub_event_code);
- explicit LeMetaEventBuilder(hci::LeSubEventCode sub_event_code, std::unique_ptr<RawBuilder> payload);
- hci::LeSubEventCode sub_event_code_;
- std::unique_ptr<RawBuilder> payload_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/sco_packet_builder.cc b/vendor_libs/test_vendor_lib/packets/hci/sco_packet_builder.cc
deleted file mode 100644
index 57203ed..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/sco_packet_builder.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2018 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 "packets/hci/sco_packet_builder.h"
-
-#include <base/logging.h>
-
-using std::vector;
-using test_vendor_lib::sco::PacketStatusFlagsType;
-
-namespace test_vendor_lib {
-namespace packets {
-
-ScoPacketBuilder::ScoPacketBuilder(uint16_t handle, PacketStatusFlagsType packet_status_flags,
- std::unique_ptr<BasePacketBuilder> payload)
- : handle_(handle), packet_status_flags_(packet_status_flags), payload_(std::move(payload)) {}
-
-size_t ScoPacketBuilder::size() const {
- return 2 * sizeof(uint16_t) + payload_->size();
-}
-
-void ScoPacketBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const {
- insert(static_cast<uint16_t>((handle_ & 0xfff) | (static_cast<uint16_t>(packet_status_flags_) << 12)), it);
- uint8_t payload_size = payload_->size();
-
- CHECK(static_cast<size_t>(payload_size) == payload_->size())
- << "Payload too large for a SCO packet: " << payload_->size();
- insert(payload_size, it);
- payload_->Serialize(it);
-}
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/sco_packet_builder.h b/vendor_libs/test_vendor_lib/packets/hci/sco_packet_builder.h
deleted file mode 100644
index a2d8561..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/sco_packet_builder.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <base/logging.h>
-#include <cstdint>
-#include <memory>
-#include <vector>
-
-#include "include/sco.h"
-#include "packets/hci/hci_packet_builder.h"
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// SCO data packets are specified in the Bluetooth Core Specification Version
-// 4.2, Volume 2, Part E, Section 5.4.3
-class ScoPacketBuilder : public HciPacketBuilder {
- public:
- virtual ~ScoPacketBuilder() override = default;
-
- static std::unique_ptr<ScoPacketBuilder> Create(uint16_t handle, sco::PacketStatusFlagsType packet_status_flags,
- std::unique_ptr<BasePacketBuilder> payload);
-
- virtual size_t size() const override;
-
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override;
-
- private:
- ScoPacketBuilder(uint16_t handle, sco::PacketStatusFlagsType packet_status_flags,
- std::unique_ptr<BasePacketBuilder> payload);
- ScoPacketBuilder() = delete;
- uint16_t handle_;
- sco::PacketStatusFlagsType packet_status_flags_;
- std::unique_ptr<BasePacketBuilder> payload_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/sco_packet_view.cc b/vendor_libs/test_vendor_lib/packets/hci/sco_packet_view.cc
deleted file mode 100644
index 9516ef4..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/sco_packet_view.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2018 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 "packets/hci/sco_packet_view.h"
-
-#include <base/logging.h>
-
-using test_vendor_lib::sco::PacketStatusFlagsType;
-
-namespace test_vendor_lib {
-namespace packets {
-
-ScoPacketView::ScoPacketView(std::shared_ptr<std::vector<uint8_t>> packet) : PacketView<true>(packet) {}
-
-ScoPacketView ScoPacketView::Create(std::shared_ptr<std::vector<uint8_t>> packet) {
- return ScoPacketView(packet);
-}
-
-uint16_t ScoPacketView::GetHandle() const {
- return begin().extract<uint16_t>() & 0xfff;
-}
-
-PacketStatusFlagsType ScoPacketView::GetPacketStatusFlags() const {
- return static_cast<PacketStatusFlagsType>(((begin() + 1).extract<uint8_t>() & 0x30) >> 4);
-}
-
-PacketView<true> ScoPacketView::GetPayload() const {
- uint8_t payload_size = (begin() + sizeof(uint16_t)).extract<uint8_t>();
- CHECK(static_cast<uint8_t>(size() - sizeof(uint16_t) - sizeof(uint8_t)) == payload_size)
- << "Malformed SCO packet payload_size " << payload_size << " + 4 != " << size();
- return SubViewLittleEndian(sizeof(uint16_t) + sizeof(uint8_t), size());
-}
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/sco_packet_view.h b/vendor_libs/test_vendor_lib/packets/hci/sco_packet_view.h
deleted file mode 100644
index 26b9489..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/sco_packet_view.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <base/logging.h>
-#include <cstdint>
-#include <memory>
-#include <vector>
-
-#include "include/sco.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// SCO data packets are specified in the Bluetooth Core Specification Version
-// 4.2, Volume 2, Part E, Section 5.4.3
-class ScoPacketView : public PacketView<true> {
- public:
- virtual ~ScoPacketView() override = default;
-
- static ScoPacketView Create(std::shared_ptr<std::vector<uint8_t>> packet);
-
- uint16_t GetHandle() const;
- sco::PacketStatusFlagsType GetPacketStatusFlags() const;
- PacketView<true> GetPayload() const;
-
- private:
- ScoPacketView(std::shared_ptr<std::vector<uint8_t>> packet);
- ScoPacketView() = delete;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/test/acl_builder_test.cc b/vendor_libs/test_vendor_lib/packets/hci/test/acl_builder_test.cc
deleted file mode 100644
index 61f8415..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/test/acl_builder_test.cc
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2018 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 "packets/hci/acl_packet_builder.h"
-#include "packets/hci/acl_packet_view.h"
-#include "packets/raw_builder.h"
-
-#include <gtest/gtest.h>
-#include <forward_list>
-#include <memory>
-
-#include "types/address.h"
-
-using std::vector;
-using test_vendor_lib::acl::BroadcastFlagsType;
-using test_vendor_lib::acl::PacketBoundaryFlagsType;
-
-namespace {
-vector<uint8_t> count = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-};
-
-vector<uint8_t> information_request = {
- 0xfe, 0x2e, 0x0a, 0x00, 0x06, 0x00, 0x01, 0x00, 0x0a, 0x02, 0x02, 0x00, 0x02, 0x00,
-};
-
-} // namespace
-
-namespace test_vendor_lib {
-namespace packets {
-
-class AclBuilderTest : public ::testing::Test {
- public:
- AclBuilderTest() = default;
- ~AclBuilderTest() = default;
-};
-
-TEST(AclBuilderTest, buildAclCountTest) {
- uint16_t handle = 0x0102;
- PacketBoundaryFlagsType packet_boundary_flags = PacketBoundaryFlagsType::FIRST_AUTOMATICALLY_FLUSHABLE;
- BroadcastFlagsType broadcast_flags = BroadcastFlagsType::ACTIVE_SLAVE_BROADCAST;
-
- std::unique_ptr<RawBuilder> count_payload = std::make_unique<RawBuilder>();
- count_payload->AddOctets(count);
- ASSERT_EQ(count.size(), count_payload->size());
-
- std::unique_ptr<AclPacketBuilder> count_packet =
- AclPacketBuilder::Create(handle, packet_boundary_flags, broadcast_flags, std::move(count_payload));
-
- ASSERT_EQ(count.size() + 4, count_packet->size());
-
- std::shared_ptr<std::vector<uint8_t>> count_packet_bytes = count_packet->ToVector();
- AclPacketView count_packet_view = AclPacketView::Create(count_packet_bytes);
-
- ASSERT_EQ(handle, count_packet_view.GetHandle());
- ASSERT_EQ(packet_boundary_flags, count_packet_view.GetPacketBoundaryFlags());
- ASSERT_EQ(broadcast_flags, count_packet_view.GetBroadcastFlags());
- PacketView<true> count_view = count_packet_view.GetPayload();
-
- ASSERT_EQ(count_view.size(), count.size());
- for (size_t i = 0; i < count_view.size(); i++) {
- ASSERT_EQ(count_view[i], count[i]);
- }
-}
-
-TEST(AclBuilderTest, buildInformationRequest) {
- uint16_t handle = 0x0efe;
- PacketBoundaryFlagsType packet_boundary_flags = PacketBoundaryFlagsType::FIRST_AUTOMATICALLY_FLUSHABLE;
- BroadcastFlagsType broadcast_flags = BroadcastFlagsType::POINT_TO_POINT;
-
- std::vector<uint8_t> payload_bytes(information_request.begin() + 4, information_request.end());
- std::unique_ptr<RawBuilder> payload = std::make_unique<RawBuilder>();
- payload->AddOctets(payload_bytes);
- ASSERT_EQ(payload_bytes.size(), payload->size());
-
- std::unique_ptr<AclPacketBuilder> packet =
- AclPacketBuilder::Create(handle, packet_boundary_flags, broadcast_flags, std::move(payload));
-
- ASSERT_EQ(information_request.size(), packet->size());
-
- std::shared_ptr<std::vector<uint8_t>> packet_bytes = packet->ToVector();
- AclPacketView packet_view = AclPacketView::Create(packet_bytes);
-
- ASSERT_EQ(packet_bytes->size(), information_request.size());
- for (size_t i = 0; i < packet_bytes->size(); i++) {
- ASSERT_EQ((*packet_bytes)[i], information_request[i]);
- }
-
- ASSERT_EQ(handle, packet_view.GetHandle());
- ASSERT_EQ(packet_boundary_flags, packet_view.GetPacketBoundaryFlags());
- ASSERT_EQ(broadcast_flags, packet_view.GetBroadcastFlags());
- PacketView<true> payload_view = packet_view.GetPayload();
-
- ASSERT_EQ(payload_view.size(), payload_bytes.size());
- for (size_t i = 0; i < payload_view.size(); i++) {
- ASSERT_EQ(payload_view[i], payload_bytes[i]);
- }
-
- ASSERT_EQ(packet_view.size(), information_request.size());
- for (size_t i = 0; i < packet_view.size(); i++) {
- ASSERT_EQ(packet_view[i], information_request[i]);
- }
-}
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/hci/test/event_builder_test.cc b/vendor_libs/test_vendor_lib/packets/hci/test/event_builder_test.cc
deleted file mode 100644
index e63c866..0000000
--- a/vendor_libs/test_vendor_lib/packets/hci/test/event_builder_test.cc
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright 2018 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 "packets/hci/event_packet_builder.h"
-
-#include <gtest/gtest.h>
-#include <forward_list>
-#include <memory>
-
-#include "types/address.h"
-
-using std::vector;
-
-namespace {
-vector<uint8_t> count = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-};
-
-} // namespace
-
-namespace test_vendor_lib {
-namespace packets {
-
-class EventBuilderTest : public ::testing::Test {
- public:
- EventBuilderTest() = default;
- ~EventBuilderTest() = default;
-};
-
-TEST(EventBuilderTest, buildLeAdvertisementSmallTest) {
- LeAdvertisement::AdvertisementType adv_type = LeAdvertisement::AdvertisementType::ADV_SCAN_IND;
- LeAdvertisement::AddressType addr_type = LeAdvertisement::AddressType::RANDOM;
- std::unique_ptr<EventPacketBuilder> le_adv = EventPacketBuilder::CreateLeAdvertisingReportEvent();
- Address addr({1, 2, 3, 4, 5, 6});
- uint8_t rssi = -93;
-
- std::vector<uint8_t> payload({0x23});
- le_adv->AddLeAdvertisingReport(adv_type, addr_type, addr, {payload}, rssi);
-
- uint8_t payload_size = payload.size();
- uint8_t event_size = payload_size + sizeof(Address) + sizeof(rssi) + 5;
- std::vector<uint8_t> expected({
- 0x3e, // HCI LE Event
- event_size,
- 0x02, // LE Advertising subevent code
- 0x01, // Number of responses
- 0x02, // Event type is scannable undirected
- 0x01, // Address type is random
- 0x01, // Address
- 0x02, // Address
- 0x03, // Address
- 0x04, // Address
- 0x05, // Address
- 0x06, // Address
- payload_size, // Length of the data
- });
-
- expected.push_back(payload[0]);
- expected.push_back(rssi);
-
- ASSERT_EQ(expected.size(), le_adv->size());
- ASSERT_EQ(expected, *le_adv->ToVector());
-}
-
-TEST(EventBuilderTest, buildLeAdvertisementTest) {
- LeAdvertisement::AdvertisementType adv_type = LeAdvertisement::AdvertisementType::ADV_SCAN_IND;
- LeAdvertisement::AddressType addr_type = LeAdvertisement::AddressType::RANDOM;
- std::unique_ptr<EventPacketBuilder> le_adv = EventPacketBuilder::CreateLeAdvertisingReportEvent();
- Address addr({1, 2, 3, 4, 5, 6});
- uint8_t rssi = -93;
-
- le_adv->AddLeAdvertisingReport(adv_type, addr_type, addr, count, rssi);
-
- uint8_t count_size = static_cast<uint8_t>(count.size());
- uint8_t event_size = count_size + sizeof(Address) + sizeof(rssi) + 5;
- std::vector<uint8_t> expected({
- 0x3e, // HCI LE Event
- event_size,
- 0x02, // LE Advertising subevent code
- 0x01, // Number of responses
- 0x02, // Event type is scannable undirected
- 0x01, // Address type is random
- 0x01, // Address
- 0x02, // Address
- 0x03, // Address
- 0x04, // Address
- 0x05, // Address
- 0x06, // Address
- count_size, // Length of the data
- });
-
- for (size_t i = 0; i < count.size(); i++) {
- expected.push_back(count[i]);
- }
- expected.push_back(rssi);
-
- std::shared_ptr<std::vector<uint8_t>> raw_adv = le_adv->ToVector();
- ASSERT_EQ(expected, *raw_adv);
-}
-
-TEST(EventBuilderTest, buildNumberOfCompletedPackets) {
- uint16_t handle = 0x0102;
- uint16_t num_packets = 0x0304;
-
- std::unique_ptr<EventPacketBuilder> event =
- EventPacketBuilder::CreateNumberOfCompletedPacketsEvent(handle, num_packets);
-
- uint8_t number_of_handles = 1;
- uint8_t event_size = sizeof(uint8_t) + number_of_handles * 2 * sizeof(uint16_t);
- std::vector<uint8_t> expected({
- 0x13, // HCI Number Of Completed Packets Event code
- event_size, number_of_handles, //
- 0x02, 0x01, // handle
- 0x04, 0x03, // count
- });
-
- std::shared_ptr<std::vector<uint8_t>> raw_event = event->ToVector();
- ASSERT_EQ(expected, *raw_event);
-}
-
-TEST(EventBuilderTest, buildNumberOfCompletedPacketsMultiple) {
- uint16_t handle = 0x0102;
- uint16_t num_packets = 0x0304;
- uint16_t handle2 = 0x0506;
- uint16_t num_packets2 = 0x0708;
-
- std::unique_ptr<EventPacketBuilder> event =
- EventPacketBuilder::CreateNumberOfCompletedPacketsEvent(handle, num_packets);
- event->AddCompletedPackets(handle2, num_packets2);
-
- uint8_t number_of_handles = 2;
- uint8_t event_size = sizeof(uint8_t) + number_of_handles * 2 * sizeof(uint16_t);
- std::vector<uint8_t> expected({
- 0x13, // HCI Number Of Completed Packets Event code
- event_size, number_of_handles, //
- 0x02, 0x01, // handle
- 0x04, 0x03, // count
- 0x06, 0x05, // handle
- 0x08, 0x07, // count
- });
-
- std::shared_ptr<std::vector<uint8_t>> raw_event = event->ToVector();
- ASSERT_EQ(expected, *raw_event);
-}
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/iterator.cc b/vendor_libs/test_vendor_lib/packets/iterator.cc
deleted file mode 100644
index 65173ee..0000000
--- a/vendor_libs/test_vendor_lib/packets/iterator.cc
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright 2018 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 "iterator.h"
-
-#include <base/logging.h>
-
-namespace test_vendor_lib {
-namespace packets {
-
-template <bool little_endian>
-Iterator<little_endian>::Iterator(std::forward_list<View> data, size_t offset) {
- data_ = data;
- index_ = offset;
- length_ = 0;
- for (auto& view : data) {
- length_ += view.size();
- }
-}
-
-template <bool little_endian>
-Iterator<little_endian> Iterator<little_endian>::operator+(int offset) {
- auto itr(*this);
-
- return itr += offset;
-}
-
-template <bool little_endian>
-Iterator<little_endian>& Iterator<little_endian>::operator+=(int offset) {
- index_ += offset;
- return *this;
-}
-
-template <bool little_endian>
-Iterator<little_endian> Iterator<little_endian>::operator++(int) {
- auto itr(*this);
- index_++;
- return itr;
-}
-
-template <bool little_endian>
-Iterator<little_endian>& Iterator<little_endian>::operator++() {
- index_++;
- return *this;
-}
-
-template <bool little_endian>
-Iterator<little_endian> Iterator<little_endian>::operator-(int offset) {
- auto itr(*this);
-
- return itr -= offset;
-}
-
-template <bool little_endian>
-int Iterator<little_endian>::operator-(Iterator<little_endian>& itr) {
- return index_ - itr.index_;
-}
-
-template <bool little_endian>
-Iterator<little_endian>& Iterator<little_endian>::operator-=(int offset) {
- index_ -= offset;
-
- return *this;
-}
-
-template <bool little_endian>
-Iterator<little_endian> Iterator<little_endian>::operator--(int) {
- auto itr(*this);
- if (index_ != 0) index_--;
-
- return itr;
-}
-
-template <bool little_endian>
-Iterator<little_endian>& Iterator<little_endian>::operator--() {
- if (index_ != 0) index_--;
-
- return *this;
-}
-
-template <bool little_endian>
-Iterator<little_endian>& Iterator<little_endian>::operator=(const Iterator<little_endian>& itr) {
- data_ = itr.data_;
- index_ = itr.index_;
-
- return *this;
-}
-
-template <bool little_endian>
-bool Iterator<little_endian>::operator==(const Iterator<little_endian>& itr) const {
- return index_ == itr.index_;
-}
-
-template <bool little_endian>
-bool Iterator<little_endian>::operator!=(const Iterator<little_endian>& itr) const {
- return !(*this == itr);
-}
-
-template <bool little_endian>
-bool Iterator<little_endian>::operator<(const Iterator<little_endian>& itr) const {
- return index_ < itr.index_;
-}
-
-template <bool little_endian>
-bool Iterator<little_endian>::operator>(const Iterator<little_endian>& itr) const {
- return index_ > itr.index_;
-}
-
-template <bool little_endian>
-bool Iterator<little_endian>::operator<=(const Iterator<little_endian>& itr) const {
- return index_ <= itr.index_;
-}
-
-template <bool little_endian>
-bool Iterator<little_endian>::operator>=(const Iterator<little_endian>& itr) const {
- return index_ >= itr.index_;
-}
-
-template <bool little_endian>
-uint8_t Iterator<little_endian>::operator*() const {
- CHECK(index_ < length_) << "Index " << index_ << " out of bounds: " << length_;
- size_t index = index_;
-
- for (auto view : data_) {
- if (index < view.size()) {
- return view[index];
- }
- index -= view.size();
- }
- CHECK(false) << "Out of fragments searching for Index " << index_;
- return 0;
-}
-
-template <bool little_endian>
-size_t Iterator<little_endian>::NumBytesRemaining() const {
- if (length_ > index_) {
- return length_ - index_;
- } else {
- return 0;
- }
-}
-
-// Explicit instantiations for both types of Iterators.
-template class Iterator<true>;
-template class Iterator<false>;
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/iterator.h b/vendor_libs/test_vendor_lib/packets/iterator.h
deleted file mode 100644
index b84ce64..0000000
--- a/vendor_libs/test_vendor_lib/packets/iterator.h
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <forward_list>
-
-#include "types/address.h"
-#include "view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// Templated Iterator for endianness
-template <bool little_endian>
-class Iterator : public std::iterator<std::random_access_iterator_tag, uint8_t> {
- public:
- Iterator(std::forward_list<View> data, size_t offset);
- Iterator(const Iterator& itr) = default;
- virtual ~Iterator() = default;
-
- // All addition and subtraction operators are unbounded.
- Iterator operator+(int offset);
- Iterator& operator+=(int offset);
- Iterator operator++(int);
- Iterator& operator++();
-
- Iterator operator-(int offset);
- int operator-(Iterator& itr);
- Iterator& operator-=(int offset);
- Iterator operator--(int);
- Iterator& operator--();
-
- Iterator& operator=(const Iterator& itr);
-
- bool operator!=(const Iterator& itr) const;
- bool operator==(const Iterator& itr) const;
-
- bool operator<(const Iterator& itr) const;
- bool operator>(const Iterator& itr) const;
-
- bool operator<=(const Iterator& itr) const;
- bool operator>=(const Iterator& itr) const;
-
- uint8_t operator*() const;
- uint8_t operator->() const;
-
- size_t NumBytesRemaining() const;
-
- // Get the next sizeof(FixedWidthPODType) bytes and return the filled type
- template <typename FixedWidthPODType>
- FixedWidthPODType extract() {
- static_assert(std::is_pod<FixedWidthPODType>::value, "Iterator::extract requires an fixed type.");
- FixedWidthPODType extracted_value;
- uint8_t* value_ptr = (uint8_t*)&extracted_value;
-
- for (size_t i = 0; i < sizeof(FixedWidthPODType); i++) {
- size_t index = (little_endian ? i : sizeof(FixedWidthPODType) - i - 1);
- value_ptr[index] = *((*this)++);
- }
- return extracted_value;
- }
-
- private:
- std::forward_list<View> data_;
- size_t index_;
- size_t length_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/command_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/command_builder.h
deleted file mode 100644
index 15a4ab8..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/command_builder.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-
-#include "packets/packet_builder.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class CommandBuilder : public PacketBuilder<true> {
- public:
- virtual ~CommandBuilder() = default;
-
- static std::unique_ptr<CommandBuilder> Create(uint16_t opcode, PacketView<true> args) {
- return std::unique_ptr<CommandBuilder>(new CommandBuilder(opcode, args));
- }
-
- virtual size_t size() const override {
- return sizeof(opcode_) + args_.size();
- }
-
- protected:
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
- insert(opcode_, it);
- for (const auto&& byte : args_) {
- insert(byte, it);
- }
- }
-
- private:
- explicit CommandBuilder(uint16_t opcode, PacketView<true> args) : opcode_(opcode), args_(args) {}
- uint16_t opcode_;
- PacketView<true> args_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/command_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/command_view.h
deleted file mode 100644
index 0aa5683..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/command_view.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-
-#include <log/log.h>
-
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class CommandView : public PacketView<true> {
- public:
- CommandView(const CommandView&) = default;
- virtual ~CommandView() = default;
-
- static CommandView GetCommand(const LinkLayerPacketView& view) {
- CHECK(view.GetType() == Link::PacketType::COMMAND);
- return CommandView(view.GetPayload());
- }
-
- uint16_t GetOpcode() {
- return begin().extract<uint16_t>();
- }
-
- Iterator<true> GetData() {
- return begin() + sizeof(uint16_t);
- }
-
- private:
- CommandView() = delete;
- CommandView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_builder.h
deleted file mode 100644
index 3c5a9f4..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_builder.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class DisconnectBuilder : public PacketBuilder<true> {
- public:
- virtual ~DisconnectBuilder() = default;
-
- static std::unique_ptr<DisconnectBuilder> Create(uint8_t reason) {
- return std::unique_ptr<DisconnectBuilder>(new DisconnectBuilder(reason));
- }
-
- virtual size_t size() const override {
- return sizeof(reason_);
- }
-
- protected:
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
- *it++ = reason_;
- }
-
- private:
- explicit DisconnectBuilder(uint8_t reason) : reason_(reason) {}
- uint8_t reason_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_view.h
deleted file mode 100644
index cdfcdc5..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/disconnect_view.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class DisconnectView : public PacketView<true> {
- public:
- DisconnectView(const DisconnectView&) = default;
- virtual ~DisconnectView() = default;
-
- static DisconnectView GetDisconnect(const LinkLayerPacketView& view) {
- CHECK(view.GetType() == Link::PacketType::DISCONNECT);
- return DisconnectView(view.GetPayload());
- }
-
- uint8_t GetReason() {
- return at(0);
- }
-
- private:
- DisconnectView() = delete;
- DisconnectView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_builder.h
deleted file mode 100644
index 329ecdb..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_builder.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2019 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class EncryptConnectionBuilder : public PacketBuilder<true> {
- public:
- virtual ~EncryptConnectionBuilder() = default;
-
- static std::unique_ptr<EncryptConnectionBuilder> Create(const std::vector<uint8_t>& key) {
- return std::unique_ptr<EncryptConnectionBuilder>(new EncryptConnectionBuilder(key));
- }
-
- virtual size_t size() const override {
- return key_.size();
- }
-
- protected:
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
- insert_vector(key_, it);
- }
-
- private:
- explicit EncryptConnectionBuilder(const std::vector<uint8_t>& key) : key_(key.begin(), key.begin() + 16) {}
- std::vector<uint8_t> key_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_view.h
deleted file mode 100644
index 665fe98..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/encrypt_connection_view.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class EncryptConnectionView : public PacketView<true> {
- public:
- EncryptConnectionView(const EncryptConnectionView&) = default;
- virtual ~EncryptConnectionView() = default;
-
- static EncryptConnectionView GetEncryptConnection(const LinkLayerPacketView& view) {
- CHECK(view.GetType() == Link::PacketType::ENCRYPT_CONNECTION ||
- view.GetType() == Link::PacketType::ENCRYPT_CONNECTION_RESPONSE);
- return EncryptConnectionView(view.GetPayload());
- }
-
- Iterator<true> GetKey() {
- return begin();
- }
-
- private:
- EncryptConnectionView() = delete;
- EncryptConnectionView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_builder.h
deleted file mode 100644
index 6703316..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_builder.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-
-#include "inquiry.h"
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class InquiryBuilder : public PacketBuilder<true> {
- public:
- virtual ~InquiryBuilder() = default;
-
- static std::unique_ptr<InquiryBuilder> Create(Inquiry::InquiryType inquiry_type) {
- return std::unique_ptr<InquiryBuilder>(new InquiryBuilder(inquiry_type));
- }
-
- virtual size_t size() const override {
- return sizeof(uint8_t);
- }
-
- protected:
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
- insert(static_cast<uint8_t>(inquiry_type_), it);
- }
-
- private:
- explicit InquiryBuilder(Inquiry::InquiryType inquiry_type) : inquiry_type_(inquiry_type) {}
- Inquiry::InquiryType inquiry_type_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_builder.h
deleted file mode 100644
index 694fe71..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_builder.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-
-#include "include/inquiry.h"
-#include "packets/packet_builder.h"
-#include "types/class_of_device.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class InquiryResponseBuilder : public PacketBuilder<true> {
- public:
- virtual ~InquiryResponseBuilder() = default;
-
- static std::unique_ptr<InquiryResponseBuilder> CreateStandard(uint8_t page_scan_repetition_mode,
- const ClassOfDevice& class_of_device,
- uint16_t clock_offset) {
- return std::unique_ptr<InquiryResponseBuilder>(new InquiryResponseBuilder(
- Inquiry::InquiryType::STANDARD, page_scan_repetition_mode, class_of_device, clock_offset));
- }
- static std::unique_ptr<InquiryResponseBuilder> CreateRssi(uint8_t page_scan_repetition_mode,
- const ClassOfDevice& class_of_device, uint16_t clock_offset,
- uint8_t rssi) {
- return std::unique_ptr<InquiryResponseBuilder>(new InquiryResponseBuilder(
- Inquiry::InquiryType::RSSI, page_scan_repetition_mode, class_of_device, clock_offset, rssi));
- }
- static std::unique_ptr<InquiryResponseBuilder> CreateExtended(uint8_t page_scan_repetition_mode,
- const ClassOfDevice& class_of_device,
- uint16_t clock_offset, uint8_t rssi,
- const std::vector<uint8_t>& extended_data) {
- return std::unique_ptr<InquiryResponseBuilder>(new InquiryResponseBuilder(
- Inquiry::InquiryType::EXTENDED, page_scan_repetition_mode, class_of_device, clock_offset, rssi, extended_data));
- }
-
- virtual size_t size() const override {
- size_t inquiry_size =
- sizeof(inquiry_type_) + sizeof(page_scan_repetition_mode_) + sizeof(class_of_device_) + sizeof(clock_offset_);
- if (inquiry_type_ == Inquiry::InquiryType::STANDARD) {
- return inquiry_size;
- }
- inquiry_size += sizeof(rssi_);
- if (inquiry_type_ == Inquiry::InquiryType::RSSI) {
- return inquiry_size;
- }
-
- return inquiry_size + extended_data_.size();
- }
-
- protected:
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
- insert(static_cast<uint8_t>(inquiry_type_), it);
- insert(page_scan_repetition_mode_, it);
- insert_class_of_device(class_of_device_, it);
- insert(clock_offset_, it);
- if (inquiry_type_ == Inquiry::InquiryType::STANDARD) {
- return;
- }
- insert(rssi_, it);
- if (inquiry_type_ == Inquiry::InquiryType::RSSI) {
- return;
- }
- insert_vector(extended_data_, it);
- }
-
- private:
- Inquiry::InquiryType inquiry_type_;
- uint8_t page_scan_repetition_mode_;
- ClassOfDevice class_of_device_;
- uint16_t clock_offset_;
- uint8_t rssi_{0xff};
- std::vector<uint8_t> extended_data_;
- explicit InquiryResponseBuilder(Inquiry::InquiryType inquiry_type, uint8_t page_scan_repetition_mode,
- const ClassOfDevice& class_of_device, uint16_t clock_offset)
- : inquiry_type_(inquiry_type), page_scan_repetition_mode_(page_scan_repetition_mode),
- class_of_device_(class_of_device), clock_offset_(clock_offset) {}
- explicit InquiryResponseBuilder(Inquiry::InquiryType inquiry_type, uint8_t page_scan_repetition_mode,
- const ClassOfDevice& class_of_device, uint16_t clock_offset, uint8_t rssi)
- : inquiry_type_(inquiry_type), page_scan_repetition_mode_(page_scan_repetition_mode),
- class_of_device_(class_of_device), clock_offset_(clock_offset), rssi_(rssi) {}
- explicit InquiryResponseBuilder(Inquiry::InquiryType inquiry_type, uint8_t page_scan_repetition_mode,
- const ClassOfDevice& class_of_device, uint16_t clock_offset, uint8_t rssi,
- const std::vector<uint8_t>& extended_data)
- : inquiry_type_(inquiry_type), page_scan_repetition_mode_(page_scan_repetition_mode),
- class_of_device_(class_of_device), clock_offset_(clock_offset), rssi_(rssi), extended_data_(extended_data) {}
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_view.h
deleted file mode 100644
index aac0585..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_response_view.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-
-#include "include/inquiry.h"
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class InquiryResponseView : public PacketView<true> {
- public:
- InquiryResponseView(const InquiryResponseView&) = default;
- virtual ~InquiryResponseView() = default;
-
- static InquiryResponseView GetInquiryResponse(const LinkLayerPacketView& view) {
- CHECK(view.GetType() == Link::PacketType::INQUIRY_RESPONSE);
- return InquiryResponseView(view.GetPayload());
- }
-
- Inquiry::InquiryType GetType() {
- return static_cast<Inquiry::InquiryType>(at(0));
- }
-
- uint8_t GetPageScanRepetitionMode() {
- return at(1);
- }
-
- ClassOfDevice GetClassOfDevice() {
- size_t offset = 2 * sizeof(uint8_t);
- return (begin() + offset).extract<ClassOfDevice>();
- }
-
- uint16_t GetClockOffset() {
- size_t offset = 2 * sizeof(uint8_t) + 3;
- return (begin() + offset).extract<uint16_t>();
- }
-
- uint8_t GetRssi() {
- size_t offset = 2 * sizeof(uint8_t) + 3 + sizeof(uint16_t);
- return at(offset);
- }
-
- Iterator<true> GetExtendedData() {
- size_t offset = 2 * sizeof(uint8_t) + 3 + sizeof(uint16_t) + sizeof(uint8_t);
- return begin() + offset;
- }
-
- private:
- InquiryResponseView() = delete;
- InquiryResponseView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_view.h
deleted file mode 100644
index eee861c..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/inquiry_view.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-
-#include "inquiry.h"
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class InquiryView : public PacketView<true> {
- public:
- InquiryView(const InquiryView&) = default;
- virtual ~InquiryView() = default;
-
- static InquiryView GetInquiry(const LinkLayerPacketView& view) {
- CHECK(view.GetType() == Link::PacketType::INQUIRY);
- return InquiryView(view.GetPayload());
- }
-
- Inquiry::InquiryType GetType() {
- return static_cast<Inquiry::InquiryType>(at(0));
- }
-
- private:
- InquiryView() = delete;
- InquiryView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_builder.h
deleted file mode 100644
index 79efb50..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_builder.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2019 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class IoCapabilityBuilder : public PacketBuilder<true> {
- public:
- virtual ~IoCapabilityBuilder() = default;
-
- static std::unique_ptr<IoCapabilityBuilder> Create(uint8_t io_capability, uint8_t oob_data_present,
- uint8_t authentication_requirements) {
- return std::unique_ptr<IoCapabilityBuilder>(
- new IoCapabilityBuilder(io_capability, oob_data_present, authentication_requirements));
- }
-
- virtual size_t size() const override {
- return sizeof(io_capability_) + sizeof(oob_data_present_) + sizeof(authentication_requirements_);
- }
-
- protected:
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
- insert(io_capability_, it);
- insert(oob_data_present_, it);
- insert(authentication_requirements_, it);
- }
-
- private:
- explicit IoCapabilityBuilder(uint8_t io_capability, uint8_t oob_data_present, uint8_t authentication_requirements)
- : io_capability_(io_capability), oob_data_present_(oob_data_present),
- authentication_requirements_(authentication_requirements) {}
- uint8_t io_capability_;
- uint8_t oob_data_present_;
- uint8_t authentication_requirements_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_builder.h
deleted file mode 100644
index c9e7601..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_builder.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2019 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class IoCapabilityNegativeResponseBuilder : public PacketBuilder<true> {
- public:
- virtual ~IoCapabilityNegativeResponseBuilder() = default;
-
- static std::unique_ptr<IoCapabilityNegativeResponseBuilder> Create(uint8_t reason) {
- return std::unique_ptr<IoCapabilityNegativeResponseBuilder>(new IoCapabilityNegativeResponseBuilder(reason));
- }
-
- virtual size_t size() const override {
- return sizeof(reason_);
- }
-
- protected:
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
- insert(reason_, it);
- }
-
- private:
- explicit IoCapabilityNegativeResponseBuilder(uint8_t reason) : reason_(reason) {}
- uint8_t reason_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_view.h
deleted file mode 100644
index 27c888f..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_negative_response_view.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class IoCapabilityNegativeResponseView : public PacketView<true> {
- public:
- IoCapabilityNegativeResponseView(const IoCapabilityNegativeResponseView&) = default;
- virtual ~IoCapabilityNegativeResponseView() = default;
-
- static IoCapabilityNegativeResponseView GetIoCapabilityNegativeResponse(const LinkLayerPacketView& view) {
- CHECK(view.GetType() == Link::PacketType::IO_CAPABILITY_NEGATIVE_RESPONSE);
- return IoCapabilityNegativeResponseView(view.GetPayload());
- }
-
- uint8_t GetReason() {
- return at(0);
- }
-
- private:
- IoCapabilityNegativeResponseView() = delete;
- IoCapabilityNegativeResponseView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_view.h
deleted file mode 100644
index 66c7564..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/io_capability_view.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class IoCapabilityView : public PacketView<true> {
- public:
- IoCapabilityView(const IoCapabilityView&) = default;
- virtual ~IoCapabilityView() = default;
-
- static IoCapabilityView GetIoCapability(const LinkLayerPacketView& view) {
- CHECK(view.GetType() == Link::PacketType::IO_CAPABILITY_RESPONSE ||
- view.GetType() == Link::PacketType::IO_CAPABILITY_REQUEST);
- return IoCapabilityView(view.GetPayload());
- }
-
- uint8_t GetIoCapability() {
- return at(0);
- }
- uint8_t GetOobDataPresent() {
- return at(1);
- }
- uint8_t GetAuthenticationRequirements() {
- return at(2);
- }
-
- private:
- IoCapabilityView() = delete;
- IoCapabilityView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_builder.h
deleted file mode 100644
index 18b3167..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_builder.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-
-#include "include/le_advertisement.h"
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class LeAdvertisementBuilder : public PacketBuilder<true>, public LeAdvertisement {
- public:
- virtual ~LeAdvertisementBuilder() = default;
-
- static std::unique_ptr<LeAdvertisementBuilder> Create(AddressType address_type, AdvertisementType advertisement_type,
- const std::vector<uint8_t>& advertisement) {
- return std::unique_ptr<LeAdvertisementBuilder>(
- new LeAdvertisementBuilder(address_type, advertisement_type, advertisement));
- }
-
- virtual size_t size() const override {
- return sizeof(address_type_) + sizeof(advertisement_type_) + advertisement_.size();
- }
-
- protected:
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
- insert(static_cast<uint8_t>(address_type_), it);
- insert(static_cast<uint8_t>(advertisement_type_), it);
- insert_vector(advertisement_, it);
- }
-
- private:
- LeAdvertisementBuilder() = delete;
- explicit LeAdvertisementBuilder(AddressType address_type, AdvertisementType advertisement_type,
- const std::vector<uint8_t>& advertisement)
- : address_type_(address_type), advertisement_type_(advertisement_type), advertisement_(advertisement) {}
- AddressType address_type_;
- AdvertisementType advertisement_type_;
- std::vector<uint8_t> advertisement_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_view.h
deleted file mode 100644
index 80e0367..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/le_advertisement_view.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-
-#include <log/log.h>
-
-#include "include/link.h"
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class LeAdvertisementView : public PacketView<true>, public LeAdvertisement {
- public:
- LeAdvertisementView(const LeAdvertisementView&) = default;
- virtual ~LeAdvertisementView() = default;
-
- static LeAdvertisementView GetLeAdvertisementView(const LinkLayerPacketView& view) {
- CHECK(view.GetType() == Link::PacketType::LE_ADVERTISEMENT || view.GetType() == Link::PacketType::LE_SCAN_RESPONSE);
- return LeAdvertisementView(view.GetPayload());
- }
-
- AddressType GetAddressType() {
- return static_cast<AddressType>(at(0));
- }
- AdvertisementType GetAdvertisementType() {
- return static_cast<AdvertisementType>(at(1));
- }
- Iterator<true> GetData() {
- return begin() + 2 * sizeof(uint8_t);
- }
-
- private:
- LeAdvertisementView() = delete;
- LeAdvertisementView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.cc b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.cc
deleted file mode 100644
index 426244f..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.cc
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright 2018 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 "link_layer_packet_builder.h"
-#include "link_layer_packet_view.h"
-
-#include "base/logging.h"
-
-using std::vector;
-
-namespace test_vendor_lib {
-
-namespace packets {
-
-LinkLayerPacketBuilder::LinkLayerPacketBuilder(Link::PacketType type, const Address& source, const Address& dest)
- : type_(type), source_addr_(source), dest_addr_(dest) {}
-
-LinkLayerPacketBuilder::LinkLayerPacketBuilder(Link::PacketType type, std::unique_ptr<PacketBuilder> packet,
- const Address& source)
- : type_(type), source_addr_(source), dest_addr_(Address::kEmpty), builder_(std::move(packet)) {}
-
-LinkLayerPacketBuilder::LinkLayerPacketBuilder(Link::PacketType type, std::unique_ptr<PacketBuilder> packet,
- const Address& source, const Address& dest)
- : type_(type), source_addr_(source), dest_addr_(dest), builder_(std::move(packet)) {}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapAcl(std::unique_ptr<ViewForwarderBuilder> acl,
- const Address& source, const Address& dest) {
- return std::shared_ptr<LinkLayerPacketBuilder>(
- new LinkLayerPacketBuilder(Link::PacketType::ACL, std::move(acl), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapCommand(std::unique_ptr<CommandBuilder> command,
- const Address& source,
- const Address& dest) {
- return std::shared_ptr<LinkLayerPacketBuilder>(
- new LinkLayerPacketBuilder(Link::PacketType::COMMAND, std::move(command), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapDisconnect(
- std::unique_ptr<DisconnectBuilder> disconnect, const Address& source, const Address& dest) {
- return std::shared_ptr<LinkLayerPacketBuilder>(
- new LinkLayerPacketBuilder(Link::PacketType::DISCONNECT, std::move(disconnect), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapEncryptConnection(
- std::unique_ptr<EncryptConnectionBuilder> encrypt_connection, const Address& source, const Address& dest) {
- return std::shared_ptr<LinkLayerPacketBuilder>(
- new LinkLayerPacketBuilder(Link::PacketType::ENCRYPT_CONNECTION, std::move(encrypt_connection), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapEncryptConnectionResponse(
- std::unique_ptr<EncryptConnectionBuilder> encrypt_connection, const Address& source, const Address& dest) {
- return std::shared_ptr<LinkLayerPacketBuilder>(new LinkLayerPacketBuilder(
- Link::PacketType::ENCRYPT_CONNECTION_RESPONSE, std::move(encrypt_connection), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapInquiry(std::unique_ptr<InquiryBuilder> inquiry,
- const Address& source) {
- return std::shared_ptr<LinkLayerPacketBuilder>(
- new LinkLayerPacketBuilder(Link::PacketType::INQUIRY, std::move(inquiry), source));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapInquiryResponse(
- std::unique_ptr<InquiryResponseBuilder> inquiry_response, const Address& source, const Address& dest) {
- return std::shared_ptr<LinkLayerPacketBuilder>(
- new LinkLayerPacketBuilder(Link::PacketType::INQUIRY_RESPONSE, std::move(inquiry_response), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapIoCapabilityRequest(
- std::unique_ptr<IoCapabilityBuilder> io_capability, const Address& source, const Address& dest) {
- return std::shared_ptr<LinkLayerPacketBuilder>(
- new LinkLayerPacketBuilder(Link::PacketType::IO_CAPABILITY_REQUEST, std::move(io_capability), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapIoCapabilityResponse(
- std::unique_ptr<IoCapabilityBuilder> io_capability, const Address& source, const Address& dest) {
- return std::shared_ptr<LinkLayerPacketBuilder>(
- new LinkLayerPacketBuilder(Link::PacketType::IO_CAPABILITY_RESPONSE, std::move(io_capability), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapIoCapabilityNegativeResponse(
- std::unique_ptr<IoCapabilityNegativeResponseBuilder> io_capability_negative_response, const Address& source,
- const Address& dest) {
- return std::shared_ptr<LinkLayerPacketBuilder>(new LinkLayerPacketBuilder(
- Link::PacketType::IO_CAPABILITY_NEGATIVE_RESPONSE, std::move(io_capability_negative_response), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapLeAdvertisement(
- std::unique_ptr<LeAdvertisementBuilder> advertisement, const Address& source) {
- return std::shared_ptr<LinkLayerPacketBuilder>(
- new LinkLayerPacketBuilder(Link::PacketType::LE_ADVERTISEMENT, std::move(advertisement), source));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapLeScan(const Address& source, const Address& dest) {
- return std::shared_ptr<LinkLayerPacketBuilder>(new LinkLayerPacketBuilder(Link::PacketType::LE_SCAN, source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapLeScanResponse(
- std::unique_ptr<LeAdvertisementBuilder> scan_response, const Address& source, const Address& dest) {
- return std::shared_ptr<LinkLayerPacketBuilder>(
- new LinkLayerPacketBuilder(Link::PacketType::LE_SCAN_RESPONSE, std ::move(scan_response), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapPage(std::unique_ptr<PageBuilder> page,
- const Address& source, const Address& dest) {
- return std::shared_ptr<LinkLayerPacketBuilder>(
- new LinkLayerPacketBuilder(Link::PacketType::PAGE, std::move(page), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapPageResponse(
- std::unique_ptr<PageResponseBuilder> page_response, const Address& source, const Address& dest) {
- return std::shared_ptr<LinkLayerPacketBuilder>(
- new LinkLayerPacketBuilder(Link::PacketType::PAGE_RESPONSE, std::move(page_response), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapResponse(std::unique_ptr<ResponseBuilder> response,
- const Address& source,
- const Address& dest) {
- return std::shared_ptr<LinkLayerPacketBuilder>(
- new LinkLayerPacketBuilder(Link::PacketType::RESPONSE, std::move(response), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::WrapSco(std::unique_ptr<ViewForwarderBuilder> sco,
- const Address& source, const Address& dest) {
- return std::shared_ptr<LinkLayerPacketBuilder>(
- new LinkLayerPacketBuilder(Link::PacketType::SCO, std::move(sco), source, dest));
-}
-
-std::shared_ptr<LinkLayerPacketBuilder> LinkLayerPacketBuilder::ReWrap(
- const std::shared_ptr<std::vector<uint8_t>> raw_packet) {
- LinkLayerPacketView received = LinkLayerPacketView::Create(raw_packet);
- Link::PacketType packet_type = received.GetType();
- Address source = received.GetSourceAddress();
- Address dest = received.GetDestinationAddress();
- PacketView<true> payload = received.GetPayload();
- std::unique_ptr<PacketBuilder> builder = ViewForwarderBuilder::Create(payload);
- return std::shared_ptr<LinkLayerPacketBuilder>(
- new LinkLayerPacketBuilder(packet_type, std::move(builder), source, dest));
-}
-
-size_t LinkLayerPacketBuilder::size() const {
- size_t builder_size = (builder_ ? builder_->size() : 0);
- return Link::kTypeBytes + Link::kSizeBytes + 2 * Address::kLength + builder_size;
-}
-
-void LinkLayerPacketBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const {
- insert(static_cast<uint32_t>(size() - Link::kSizeBytes), it);
- insert(static_cast<uint8_t>(type_), it);
- insert_address(source_addr_.address, it);
- insert_address(dest_addr_.address, it);
- if (builder_) {
- builder_->Serialize(it);
- }
-}
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.h
deleted file mode 100644
index a9d7741..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_builder.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <string>
-#include <vector>
-
-#include "link.h"
-#include "packets/link_layer/command_builder.h"
-#include "packets/link_layer/disconnect_builder.h"
-#include "packets/link_layer/encrypt_connection_builder.h"
-#include "packets/link_layer/inquiry_builder.h"
-#include "packets/link_layer/inquiry_response_builder.h"
-#include "packets/link_layer/io_capability_builder.h"
-#include "packets/link_layer/io_capability_negative_response_builder.h"
-#include "packets/link_layer/le_advertisement_builder.h"
-#include "packets/link_layer/page_builder.h"
-#include "packets/link_layer/page_response_builder.h"
-#include "packets/link_layer/response_builder.h"
-#include "packets/link_layer/view_forwarder_builder.h"
-#include "packets/packet_builder.h"
-#include "types/address.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// Link-layer packets are an abstraction of LMP PDUs.
-class LinkLayerPacketBuilder : PacketBuilder<true> {
- public:
- virtual ~LinkLayerPacketBuilder() = default;
-
- static std::shared_ptr<LinkLayerPacketBuilder> WrapAcl(std::unique_ptr<ViewForwarderBuilder> acl,
- const Address& source, const Address& dest);
- static std::shared_ptr<LinkLayerPacketBuilder> WrapCommand(std::unique_ptr<CommandBuilder> command,
- const Address& source, const Address& dest);
- static std::shared_ptr<LinkLayerPacketBuilder> WrapDisconnect(std::unique_ptr<DisconnectBuilder> disconnect,
- const Address& source, const Address& dest);
- static std::shared_ptr<LinkLayerPacketBuilder> WrapEncryptConnection(
- std::unique_ptr<EncryptConnectionBuilder> encrypt_connection, const Address& source, const Address& dest);
- static std::shared_ptr<LinkLayerPacketBuilder> WrapEncryptConnectionResponse(
- std::unique_ptr<EncryptConnectionBuilder> encrypt_connection, const Address& source, const Address& dest);
- static std::shared_ptr<LinkLayerPacketBuilder> WrapInquiry(std::unique_ptr<InquiryBuilder> inquiry,
- const Address& source);
- static std::shared_ptr<LinkLayerPacketBuilder> WrapInquiryResponse(
- std::unique_ptr<InquiryResponseBuilder> inquiry_response, const Address& source, const Address& dest);
- static std::shared_ptr<LinkLayerPacketBuilder> WrapIoCapabilityRequest(
- std::unique_ptr<IoCapabilityBuilder> io_capability, const Address& source, const Address& dest);
- static std::shared_ptr<LinkLayerPacketBuilder> WrapIoCapabilityResponse(
- std::unique_ptr<IoCapabilityBuilder> io_capability, const Address& source, const Address& dest);
- static std::shared_ptr<LinkLayerPacketBuilder> WrapIoCapabilityNegativeResponse(
- std::unique_ptr<IoCapabilityNegativeResponseBuilder> io_capability_negative_response, const Address& source,
- const Address& dest);
- static std::shared_ptr<LinkLayerPacketBuilder> WrapLeAdvertisement(
- std::unique_ptr<LeAdvertisementBuilder> advertisement, const Address& source);
- static std::shared_ptr<LinkLayerPacketBuilder> WrapLeScan(const Address& source, const Address& dest);
- static std::shared_ptr<LinkLayerPacketBuilder> WrapLeScanResponse(
- std::unique_ptr<LeAdvertisementBuilder> scan_response, const Address& source, const Address& dest);
- static std::shared_ptr<LinkLayerPacketBuilder> WrapPage(std::unique_ptr<PageBuilder> page, const Address& source,
- const Address& dest);
- static std::shared_ptr<LinkLayerPacketBuilder> WrapPageResponse(std::unique_ptr<PageResponseBuilder> page_response,
- const Address& source, const Address& dest);
- static std::shared_ptr<LinkLayerPacketBuilder> WrapResponse(const std::unique_ptr<ResponseBuilder> response,
- const Address& source, const Address& dest);
- static std::shared_ptr<LinkLayerPacketBuilder> WrapSco(std::unique_ptr<ViewForwarderBuilder> sco,
- const Address& source, const Address& dest);
- static std::shared_ptr<LinkLayerPacketBuilder> ReWrap(const std::shared_ptr<std::vector<uint8_t>> raw_packet);
-
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override;
-
- virtual size_t size() const override;
-
- private:
- LinkLayerPacketBuilder(const LinkLayerPacketBuilder&) = delete;
- LinkLayerPacketBuilder() = delete;
- LinkLayerPacketBuilder(Link::PacketType type, const Address& source, const Address& dest);
- LinkLayerPacketBuilder(Link::PacketType type, std::unique_ptr<PacketBuilder> builder, const Address& source,
- const Address& dest);
- LinkLayerPacketBuilder(Link::PacketType type, std::unique_ptr<PacketBuilder> builder, const Address& source);
- Link::PacketType type_;
- Address source_addr_;
- Address dest_addr_;
- std::unique_ptr<PacketBuilder> builder_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.cc b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.cc
deleted file mode 100644
index 04518ca..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.cc
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2018 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 "link_layer_packet_view.h"
-#include "base/logging.h"
-
-namespace test_vendor_lib {
-constexpr size_t Link::kSizeBytes;
-constexpr size_t Link::kTypeBytes;
-
-namespace packets {
-LinkLayerPacketView::LinkLayerPacketView(std::shared_ptr<std::vector<uint8_t>> raw) : PacketView<true>(raw) {}
-
-LinkLayerPacketView LinkLayerPacketView::Create(std::shared_ptr<std::vector<uint8_t>> raw) {
- CHECK(raw->size() >= Link::kSizeBytes + Link::kTypeBytes + 2 * Address::kLength);
- return LinkLayerPacketView(raw);
-}
-
-Link::PacketType LinkLayerPacketView::GetType() const {
- return static_cast<Link::PacketType>(at(Link::kSizeBytes));
-}
-
-Address LinkLayerPacketView::GetSourceAddress() const {
- size_t offset = Link::kSizeBytes + Link::kTypeBytes;
- return (begin() + offset).extract<Address>();
-}
-
-Address LinkLayerPacketView::GetDestinationAddress() const {
- size_t offset = Link::kSizeBytes + Link::kTypeBytes + Address::kLength;
- return (begin() + offset).extract<Address>();
-}
-
-PacketView<true> LinkLayerPacketView::GetPayload() const {
- return SubViewLittleEndian(Link::kSizeBytes + Link::kTypeBytes + 2 * Address::kLength, size());
-}
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.h
deleted file mode 100644
index bdbfaa7..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/link_layer_packet_view.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <string>
-#include <vector>
-
-#include "include/link.h"
-#include "packets/packet_view.h"
-#include "types/address.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// Link-layer packets are an abstraction of LMP PDUs.
-class LinkLayerPacketView : public PacketView<true> {
- public:
- LinkLayerPacketView(const LinkLayerPacketView&) = default;
- virtual ~LinkLayerPacketView() = default;
-
- static LinkLayerPacketView Create(std::shared_ptr<std::vector<uint8_t>> raw);
-
- Link::PacketType GetType() const;
- Address GetSourceAddress() const;
- Address GetDestinationAddress() const;
- PacketView<true> GetPayload() const;
-
- private:
- LinkLayerPacketView() = delete;
- LinkLayerPacketView(std::shared_ptr<std::vector<uint8_t>> raw);
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/page_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/page_builder.h
deleted file mode 100644
index 0e18cb3..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/page_builder.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <memory>
-
-#include <base/logging.h>
-
-#include "packets/packet_builder.h"
-#include "types/class_of_device.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class PageBuilder : public PacketBuilder<true> {
- public:
- virtual ~PageBuilder() = default;
-
- static std::unique_ptr<PageBuilder> Create(const ClassOfDevice& class_of_device, uint8_t allow_role_switch) {
- return std::unique_ptr<PageBuilder>(new PageBuilder(class_of_device, allow_role_switch));
- }
-
- virtual size_t size() const override {
- return sizeof(class_of_device_) + sizeof(allow_role_switch_);
- }
-
- protected:
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
- insert_class_of_device(class_of_device_, it);
- insert(allow_role_switch_, it);
- }
-
- private:
- explicit PageBuilder(const ClassOfDevice& class_of_device, uint8_t allow_role_switch)
- : class_of_device_(class_of_device), allow_role_switch_(allow_role_switch) {}
- ClassOfDevice class_of_device_;
- uint8_t allow_role_switch_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/page_response_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/page_response_builder.h
deleted file mode 100644
index 78f9a80..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/page_response_builder.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class PageResponseBuilder : public PacketBuilder<true> {
- public:
- virtual ~PageResponseBuilder() = default;
-
- static std::unique_ptr<PageResponseBuilder> Create(uint8_t try_role_switch) {
- return std::unique_ptr<PageResponseBuilder>(new PageResponseBuilder(try_role_switch));
- }
-
- virtual size_t size() const override {
- return sizeof(try_role_switch_);
- }
-
- protected:
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
- insert(try_role_switch_, it);
- }
-
- private:
- explicit PageResponseBuilder(uint8_t try_role_switch) : try_role_switch_(try_role_switch) {}
- uint8_t try_role_switch_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/page_response_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/page_response_view.h
deleted file mode 100644
index 20f0b68..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/page_response_view.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class PageResponseView : public PacketView<true> {
- public:
- PageResponseView(const PageResponseView&) = default;
- virtual ~PageResponseView() = default;
-
- static PageResponseView GetPageResponse(const LinkLayerPacketView& view) {
- CHECK(view.GetType() == Link::PacketType::PAGE_RESPONSE);
- return PageResponseView(view.GetPayload());
- }
-
- uint8_t GetTryRoleSwitch() {
- return at(0);
- }
-
- private:
- PageResponseView() = delete;
- PageResponseView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/page_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/page_view.h
deleted file mode 100644
index a26446d..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/page_view.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class PageView : public PacketView<true> {
- public:
- PageView(const PageView&) = default;
- virtual ~PageView() = default;
-
- static PageView GetPage(const LinkLayerPacketView& view) {
- CHECK(view.GetType() == Link::PacketType::PAGE);
- return PageView(view.GetPayload());
- }
-
- ClassOfDevice GetClassOfDevice() {
- return begin().extract<ClassOfDevice>();
- }
-
- uint8_t GetAllowRoleSwitch() {
- return at(3);
- }
-
- private:
- PageView() = delete;
- PageView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/response_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/response_builder.h
deleted file mode 100644
index 18f765d..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/response_builder.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <memory>
-#include <vector>
-
-#include "packets/packet_builder.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class ResponseBuilder : public PacketBuilder<true> {
- public:
- virtual ~ResponseBuilder() = default;
-
- static std::unique_ptr<ResponseBuilder> Create(uint16_t opcode, const std::vector<uint64_t>& data) {
- return std::unique_ptr<ResponseBuilder>(new ResponseBuilder(opcode, data));
- }
-
- virtual size_t size() const override {
- return sizeof(opcode_) + data_.size() * sizeof(uint64_t);
- }
-
- protected:
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
- insert(opcode_, it);
- insert_vector(data_, it);
- }
-
- private:
- explicit ResponseBuilder(uint16_t opcode, const std::vector<uint64_t> data) : opcode_(opcode), data_(data) {}
- uint16_t opcode_;
- std::vector<uint64_t> data_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/response_view.h b/vendor_libs/test_vendor_lib/packets/link_layer/response_view.h
deleted file mode 100644
index f1ff7c9..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/response_view.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-
-#include <log/log.h>
-
-#include "packets/link_layer/link_layer_packet_view.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class ResponseView : public PacketView<true> {
- public:
- ResponseView(const ResponseView&) = default;
- virtual ~ResponseView() = default;
-
- static ResponseView GetResponse(const LinkLayerPacketView& view) {
- CHECK(view.GetType() == Link::PacketType::RESPONSE);
- return ResponseView(view.GetPayload());
- }
-
- uint16_t GetOpcode() {
- return begin().extract<uint16_t>();
- }
-
- Iterator<true> GetResponseData() {
- return begin() + sizeof(uint16_t);
- }
-
- private:
- ResponseView() = delete;
- ResponseView(const PacketView<true>& view) : PacketView(view) {}
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer/view_forwarder_builder.h b/vendor_libs/test_vendor_lib/packets/link_layer/view_forwarder_builder.h
deleted file mode 100644
index da0d827..0000000
--- a/vendor_libs/test_vendor_lib/packets/link_layer/view_forwarder_builder.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <memory>
-
-#include "base/logging.h"
-
-#include "packets/packet_builder.h"
-#include "packets/packet_view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class ViewForwarderBuilder : public PacketBuilder<true> {
- public:
- virtual ~ViewForwarderBuilder() = default;
-
- static std::unique_ptr<ViewForwarderBuilder> Create(PacketView<true> view) {
- return std::unique_ptr<ViewForwarderBuilder>(new ViewForwarderBuilder(view));
- }
-
- virtual size_t size() const override {
- return view_.size();
- }
-
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
- for (size_t i = 0; i < view_.size(); i++) {
- insert(view_[i], it);
- }
- }
-
- private:
- explicit ViewForwarderBuilder(PacketView<true> view) : view_(view) {}
- PacketView<true> view_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/link_layer_packets.pdl b/vendor_libs/test_vendor_lib/packets/link_layer_packets.pdl
new file mode 100644
index 0000000..2d601cd
--- /dev/null
+++ b/vendor_libs/test_vendor_lib/packets/link_layer_packets.pdl
@@ -0,0 +1,236 @@
+little_endian_packets
+
+custom_field Address : 48 "hci/"
+custom_field ClassOfDevice : 24 "hci/"
+
+enum PacketType : 8 {
+ UNKNOWN = 0x00,
+ ACL = 0x01,
+ DISCONNECT = 0x02,
+ ENCRYPT_CONNECTION = 0x03,
+ ENCRYPT_CONNECTION_RESPONSE = 0x04,
+ EVENT = 0x05,
+ INQUIRY = 0x06,
+ INQUIRY_RESPONSE = 0x07,
+ IO_CAPABILITY_REQUEST = 0x08,
+ IO_CAPABILITY_RESPONSE = 0x09,
+ IO_CAPABILITY_NEGATIVE_RESPONSE = 0x0A,
+ LE_ADVERTISEMENT = 0x0B,
+ LE_CONNECT = 0x0C,
+ LE_CONNECT_COMPLETE = 0x0D,
+ LE_SCAN = 0x0E,
+ LE_SCAN_RESPONSE = 0x0F,
+ PAGE = 0x10,
+ PAGE_RESPONSE = 0x11,
+ PAGE_REJECT = 0x12,
+ READ_CLOCK_OFFSET = 0x13,
+ READ_CLOCK_OFFSET_RESPONSE = 0x14,
+ READ_REMOTE_SUPPORTED_FEATURES = 0x15,
+ READ_REMOTE_SUPPORTED_FEATURES_RESPONSE = 0x16,
+ READ_REMOTE_LMP_FEATURES = 0x17,
+ READ_REMOTE_LMP_FEATURES_RESPONSE = 0x18,
+ READ_REMOTE_EXTENDED_FEATURES = 0x19,
+ READ_REMOTE_EXTENDED_FEATURES_RESPONSE = 0x1A,
+ READ_REMOTE_VERSION_INFORMATION = 0x1B,
+ READ_REMOTE_VERSION_INFORMATION_RESPONSE = 0x1C,
+ REMOTE_NAME_REQUEST = 0x1D,
+ REMOTE_NAME_REQUEST_RESPONSE = 0x1E,
+ SCO = 0x1F,
+ COMMAND = 0x23, // Remove
+ RESPONSE = 0x24, // Remove
+}
+
+packet LinkLayerPacket {
+ type : PacketType,
+ source_address : Address,
+ destination_address : Address,
+ _body_,
+}
+
+packet Command : LinkLayerPacket (type = COMMAND) {
+ _payload_,
+}
+
+packet Response : LinkLayerPacket (type = RESPONSE) {
+ opcode : 16,
+ _payload_,
+}
+
+packet AclPacket : LinkLayerPacket (type = ACL) {
+ _payload_,
+}
+
+packet Disconnect : LinkLayerPacket (type = DISCONNECT) {
+ reason : 8,
+}
+
+packet EncryptConnection : LinkLayerPacket (type = ENCRYPT_CONNECTION) {
+ key : 8[],
+}
+
+packet EncryptConnectionResponse : LinkLayerPacket (type = ENCRYPT_CONNECTION_RESPONSE) {
+ key : 8[],
+}
+
+enum InquiryState : 8 {
+ STANDBY = 0x00,
+ INQUIRY = 0x01,
+}
+
+enum InquiryType : 8 {
+ STANDARD = 0x00,
+ RSSI = 0x01,
+ EXTENDED = 0x02,
+}
+
+packet Inquiry : LinkLayerPacket (type = INQUIRY) {
+ inquiry_type : InquiryType,
+}
+
+packet BasicInquiryResponse : LinkLayerPacket(type = INQUIRY_RESPONSE) {
+ inquiry_type : InquiryType,
+ page_scan_repetition_mode : 8,
+ class_of_device : ClassOfDevice,
+ clock_offset : 15,
+ _reserved_ : 1,
+ _body_,
+}
+
+packet InquiryResponse : BasicInquiryResponse (inquiry_type = STANDARD) {
+}
+
+packet InquiryResponseWithRssi : BasicInquiryResponse (inquiry_type = RSSI) {
+ rssi: 8,
+}
+
+packet ExtendedInquiryResponse : BasicInquiryResponse (inquiry_type = EXTENDED) {
+ rssi: 8,
+ extended_data : 8[],
+}
+
+packet IoCapabilityRequest : LinkLayerPacket (type = IO_CAPABILITY_REQUEST) {
+ io_capability : 8,
+ oob_data_present : 8,
+ authentication_requirements : 8,
+}
+
+packet IoCapabilityResponse : LinkLayerPacket (type = IO_CAPABILITY_RESPONSE) {
+ io_capability : 8,
+ oob_data_present : 8,
+ authentication_requirements : 8,
+}
+
+packet IoCapabilityNegativeResponse : LinkLayerPacket (type = IO_CAPABILITY_NEGATIVE_RESPONSE) {
+ reason : 8,
+}
+
+enum AddressType : 8 {
+ PUBLIC = 0,
+ RANDOM = 1,
+ PUBLIC_IDENTITY = 2,
+ RANDOM_IDENTITY = 3,
+}
+
+enum AdvertisementType : 8 {
+ ADV_IND = 0, // Connectable and scannable
+ ADV_DIRECT_IND = 1, // Connectable directed
+ ADV_SCAN_IND = 2, // Scannable undirected
+ ADV_NONCONN_IND = 3, // Non connectable undirected
+ SCAN_RESPONSE = 4,
+}
+
+packet LeAdvertisement : LinkLayerPacket (type = LE_ADVERTISEMENT) {
+ address_type : AddressType,
+ advertisement_type : AdvertisementType,
+ data : 8[],
+}
+
+packet LeConnect : LinkLayerPacket (type = LE_CONNECT) {
+ le_connection_interval_min : 16,
+ le_connection_interval_max : 16,
+ le_connection_latency : 16,
+ le_connection_supervision_timeout : 16,
+ address_type : 8,
+}
+
+packet LeConnectComplete : LinkLayerPacket (type = LE_CONNECT_COMPLETE) {
+ le_connection_interval : 16,
+ le_connection_latency : 16,
+ le_connection_supervision_timeout : 16,
+ address_type : 8,
+}
+
+packet LeScan : LinkLayerPacket (type = LE_SCAN) {
+}
+
+packet LeScanResponse : LinkLayerPacket (type = LE_SCAN_RESPONSE) {
+ address_type : AddressType,
+ advertisement_type : AdvertisementType,
+ data : 8[],
+}
+
+packet Page : LinkLayerPacket (type = PAGE) {
+ class_of_device : ClassOfDevice,
+ allow_role_switch : 8,
+}
+
+packet PageResponse : LinkLayerPacket (type = PAGE_RESPONSE) {
+ try_role_switch : 8,
+}
+
+packet PageReject : LinkLayerPacket (type = PAGE_REJECT) {
+ reason : 8,
+}
+
+packet ReadClockOffset : LinkLayerPacket (type = READ_CLOCK_OFFSET) {
+}
+
+packet ReadClockOffsetResponse : LinkLayerPacket (type = READ_CLOCK_OFFSET_RESPONSE) {
+ offset : 16,
+}
+
+packet ReadRemoteSupportedFeatures : LinkLayerPacket (type = READ_REMOTE_SUPPORTED_FEATURES) {
+}
+
+packet ReadRemoteSupportedFeaturesResponse : LinkLayerPacket (type = READ_REMOTE_SUPPORTED_FEATURES_RESPONSE) {
+ features : 64,
+}
+
+packet ReadRemoteLmpFeatures : LinkLayerPacket (type = READ_REMOTE_LMP_FEATURES) {
+}
+
+packet ReadRemoteLmpFeaturesResponse : LinkLayerPacket (type = READ_REMOTE_LMP_FEATURES_RESPONSE) {
+ features : 64,
+}
+
+packet ReadRemoteExtendedFeatures : LinkLayerPacket (type = READ_REMOTE_EXTENDED_FEATURES) {
+ page_number : 8,
+}
+
+packet ReadRemoteExtendedFeaturesResponse : LinkLayerPacket (type = READ_REMOTE_EXTENDED_FEATURES_RESPONSE) {
+ status : 8,
+ page_number : 8,
+ max_page_number : 8,
+ features : 64,
+}
+
+packet ReadRemoteVersionInformation : LinkLayerPacket (type = READ_REMOTE_VERSION_INFORMATION) {
+}
+
+packet ReadRemoteVersionInformationResponse : LinkLayerPacket (type = READ_REMOTE_VERSION_INFORMATION_RESPONSE) {
+ lmp_version : 8,
+ lmp_subversion : 8,
+ manufacturer_name : 16,
+}
+
+packet RemoteNameRequest : LinkLayerPacket (type = REMOTE_NAME_REQUEST) {
+}
+
+packet RemoteNameRequestResponse : LinkLayerPacket (type = REMOTE_NAME_REQUEST_RESPONSE) {
+ name : 8[248],
+}
+
+packet ScoPacket : LinkLayerPacket (type = SCO) {
+ _payload_,
+}
+
diff --git a/vendor_libs/test_vendor_lib/packets/packet_builder.h b/vendor_libs/test_vendor_lib/packets/packet_builder.h
deleted file mode 100644
index 947b02a..0000000
--- a/vendor_libs/test_vendor_lib/packets/packet_builder.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <forward_list>
-#include <iterator>
-#include <memory>
-#include <vector>
-
-#include "base_packet_builder.h"
-#include "types/address.h"
-#include "types/class_of_device.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// Abstract base class that is subclassed to build specifc packets.
-// The template parameter little_endian controls the generation of insert().
-template <bool little_endian>
-class PacketBuilder : public BasePacketBuilder {
- public:
- PacketBuilder() = default;
- virtual ~PacketBuilder() = default;
-
- // Classes which need fragmentation should define a function like this:
- // std::forward_list<DerivedBuilder>& Fragment(size_t max_size);
-
- protected:
- // Write sizeof(FixedWidthIntegerType) bytes using the iterator
- template <typename FixedWidthIntegerType,
- typename std::enable_if<std::is_integral<FixedWidthIntegerType>::value, int>::type = 0>
- void insert(FixedWidthIntegerType value, std::back_insert_iterator<std::vector<uint8_t>> it) const {
- for (size_t i = 0; i < sizeof(FixedWidthIntegerType); i++) {
- if (little_endian == true) {
- *it = static_cast<uint8_t>(value >> (i * 8));
- } else {
- *it = static_cast<uint8_t>(value >> ((sizeof(FixedWidthIntegerType) - i - 1) * 8));
- }
- it++;
- }
- }
-
- // Specialized insert that allows inserting enums without casting
- template <typename Enum, typename std::enable_if<std::is_enum_v<Enum>, int>::type = 0>
- inline void insert(Enum value, std::back_insert_iterator<std::vector<uint8_t>> it) const {
- using enum_type = typename std::underlying_type_t<Enum>;
- static_assert(std::is_unsigned_v<enum_type>, "Enum type is signed. Did you forget to specify the enum size?");
- insert<enum_type>(static_cast<enum_type>(value), it);
- }
-
- // Write a vector of FixedWidthIntegerType using the iterator
- template <typename FixedWidthIntegerType>
- void insert_vector(const std::vector<FixedWidthIntegerType>& vec,
- std::back_insert_iterator<std::vector<uint8_t>> it) const {
- static_assert(std::is_integral<FixedWidthIntegerType>::value,
- "PacketBuilder::insert requires an integral type vector.");
- for (const auto& element : vec) {
- insert(element, it);
- }
- }
-
- void insert_address(const Address& addr, std::back_insert_iterator<std::vector<uint8_t>> it) const {
- for (const auto& element : addr.address) {
- insert(element, it);
- }
- }
-
- void insert_class_of_device(const ClassOfDevice& cod, std::back_insert_iterator<std::vector<uint8_t>> it) const {
- for (const auto& element : cod.cod) {
- insert(element, it);
- }
- }
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/packet_view.cc b/vendor_libs/test_vendor_lib/packets/packet_view.cc
deleted file mode 100644
index 7ffe71a..0000000
--- a/vendor_libs/test_vendor_lib/packets/packet_view.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright 2018 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 "packet_view.h"
-
-#include <algorithm>
-
-#include <base/logging.h>
-
-namespace test_vendor_lib {
-namespace packets {
-
-template <bool little_endian>
-PacketView<little_endian>::PacketView(const std::forward_list<class View> fragments)
- : fragments_(fragments), length_(0) {
- for (auto fragment : fragments_) {
- length_ += fragment.size();
- }
-}
-
-template <bool little_endian>
-PacketView<little_endian>::PacketView(std::shared_ptr<std::vector<uint8_t>> packet)
- : fragments_({View(packet, 0, packet->size())}), length_(packet->size()) {}
-
-template <bool little_endian>
-Iterator<little_endian> PacketView<little_endian>::begin() const {
- return Iterator<little_endian>(this->fragments_, 0);
-}
-
-template <bool little_endian>
-Iterator<little_endian> PacketView<little_endian>::end() const {
- return Iterator<little_endian>(this->fragments_, size());
-}
-
-template <bool little_endian>
-uint8_t PacketView<little_endian>::operator[](size_t index) const {
- return at(index);
-}
-
-template <bool little_endian>
-uint8_t PacketView<little_endian>::at(size_t index) const {
- CHECK(index < length_) << "Index " << index << " out of bounds";
- for (const auto& fragment : fragments_) {
- if (index < fragment.size()) {
- return fragment[index];
- }
- index -= fragment.size();
- }
- CHECK(false) << "Out of fragments searching for Index " << index;
- return 0;
-}
-
-template <bool little_endian>
-size_t PacketView<little_endian>::size() const {
- return length_;
-}
-
-template <bool little_endian>
-std::forward_list<View> PacketView<little_endian>::SubViewList(size_t begin, size_t end) const {
- CHECK(begin <= end) << "Begin " << begin << " is past end";
- CHECK(end <= length_) << "End " << end << " is too large";
- std::forward_list<View> view_list;
- std::forward_list<View>::iterator it = view_list.before_begin();
- size_t length = end - begin;
- for (const auto& fragment : fragments_) {
- if (begin >= fragment.size()) {
- begin -= fragment.size();
- } else {
- View view(fragment, begin, begin + std::min(length, fragment.size() - begin));
- length -= view.size();
- it = view_list.insert_after(it, view);
- begin = 0;
- }
- }
- return view_list;
-}
-
-template <bool little_endian>
-PacketView<true> PacketView<little_endian>::SubViewLittleEndian(size_t begin, size_t end) const {
- return PacketView<true>(SubViewList(begin, end));
-}
-
-template <bool little_endian>
-PacketView<false> PacketView<little_endian>::SubViewBigEndian(size_t begin, size_t end) const {
- return PacketView<false>(SubViewList(begin, end));
-}
-
-// Explicit instantiations for both types of PacketViews.
-template class PacketView<true>;
-template class PacketView<false>;
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/packet_view.h b/vendor_libs/test_vendor_lib/packets/packet_view.h
deleted file mode 100644
index 16255fa..0000000
--- a/vendor_libs/test_vendor_lib/packets/packet_view.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <forward_list>
-
-#include "iterator.h"
-#include "view.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-// Abstract base class that is subclassed to provide type-specifc accessors.
-// Holds a shared pointer to the underlying data.
-// The template parameter little_endian controls the generation of extract().
-template <bool little_endian>
-class PacketView {
- public:
- PacketView(const std::forward_list<class View> fragments);
- PacketView(const PacketView& PacketView) = default;
- virtual ~PacketView() = default;
-
- virtual Iterator<little_endian> begin() const;
-
- virtual Iterator<little_endian> end() const;
-
- uint8_t operator[](size_t i) const;
-
- uint8_t at(size_t index) const;
-
- size_t size() const;
-
- PacketView<true> SubViewLittleEndian(size_t begin, size_t end) const;
-
- PacketView<false> SubViewBigEndian(size_t begin, size_t end) const;
-
- protected:
- PacketView(std::shared_ptr<std::vector<uint8_t>> packet);
-
- private:
- std::forward_list<View> fragments_;
- size_t length_;
- PacketView<little_endian>() = delete;
- std::forward_list<View> SubViewList(size_t begin, size_t end) const;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/raw_builder.cc b/vendor_libs/test_vendor_lib/packets/raw_builder.cc
deleted file mode 100644
index 794fbb7..0000000
--- a/vendor_libs/test_vendor_lib/packets/raw_builder.cc
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2018 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 "raw_builder.h"
-
-#include <base/logging.h>
-#include <algorithm>
-
-using std::vector;
-
-namespace test_vendor_lib {
-namespace packets {
-
-RawBuilder::RawBuilder(size_t max_bytes) : max_bytes_(max_bytes) {}
-
-bool RawBuilder::AddOctets(size_t octets, const vector<uint8_t>& bytes) {
- if (payload_.size() + octets > max_bytes_) return false;
-
- if (octets != bytes.size()) return false;
-
- payload_.insert(payload_.end(), bytes.begin(), bytes.end());
-
- return true;
-}
-
-bool RawBuilder::AddOctets(const vector<uint8_t>& bytes) {
- return AddOctets(bytes.size(), bytes);
-}
-
-bool RawBuilder::AddOctets(size_t octets, uint64_t value) {
- vector<uint8_t> val_vector;
-
- uint64_t v = value;
-
- if (octets > sizeof(uint64_t)) return false;
-
- for (size_t i = 0; i < octets; i++) {
- val_vector.push_back(v & 0xff);
- v = v >> 8;
- }
-
- if (v != 0) return false;
-
- return AddOctets(octets, val_vector);
-}
-
-bool RawBuilder::AddAddress(const Address& address) {
- if (payload_.size() + Address::kLength > max_bytes_) return false;
-
- for (size_t i = 0; i < Address::kLength; i++) {
- payload_.push_back(address.address[i]);
- }
- return true;
-}
-
-bool RawBuilder::AddOctets1(uint8_t value) {
- return AddOctets(1, value);
-}
-
-bool RawBuilder::AddOctets2(uint16_t value) {
- return AddOctets(2, value);
-}
-
-bool RawBuilder::AddOctets3(uint32_t value) {
- return AddOctets(3, value);
-}
-
-bool RawBuilder::AddOctets4(uint32_t value) {
- return AddOctets(4, value);
-}
-
-bool RawBuilder::AddOctets6(uint64_t value) {
- return AddOctets(6, value);
-}
-
-bool RawBuilder::AddOctets8(uint64_t value) {
- return AddOctets(8, value);
-}
-
-bool RawBuilder::CanAddOctets(size_t num_bytes) const {
- return payload_.size() + num_bytes <= max_bytes_;
-}
-
-void RawBuilder::Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const {
- for (const auto& val : payload_) {
- insert(val, it);
- }
-}
-
-size_t RawBuilder::size() const {
- return payload_.size();
-}
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/raw_builder.h b/vendor_libs/test_vendor_lib/packets/raw_builder.h
deleted file mode 100644
index cbc7d6f..0000000
--- a/vendor_libs/test_vendor_lib/packets/raw_builder.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <vector>
-
-#include "packets/packet_builder.h"
-#include "types/address.h"
-
-namespace test_vendor_lib {
-namespace packets {
-
-class RawBuilder : public PacketBuilder<true> {
- public:
- RawBuilder() = default;
- RawBuilder(size_t max_bytes);
- virtual ~RawBuilder() = default;
-
- virtual size_t size() const override;
-
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const;
-
- // Add |address| to the payload. Return true if:
- // - the new size of the payload is still <= |max_bytes_|
- bool AddAddress(const Address& address);
-
- // Return true if |num_bytes| can be added to the payload.
- bool CanAddOctets(size_t num_bytes) const;
-
- // Add |octets| bytes to the payload. Return true if:
- // - the size of |bytes| is equal to |octets| and
- // - the new size of the payload is still <= |max_bytes_|
- bool AddOctets(size_t octets, const std::vector<uint8_t>& bytes);
-
- bool AddOctets(const std::vector<uint8_t>& bytes);
-
- bool AddOctets1(uint8_t value);
- bool AddOctets2(uint16_t value);
- bool AddOctets3(uint32_t value);
- bool AddOctets4(uint32_t value);
- bool AddOctets6(uint64_t value);
- bool AddOctets8(uint64_t value);
-
- private:
- // Add |octets| bytes to the payload. Return true if:
- // - the value of |value| fits in |octets| bytes and
- // - the new size of the payload is still <= |max_bytes_|
- bool AddOctets(size_t octets, uint64_t value);
-
- size_t max_bytes_{255};
-
- // Underlying containers for storing the actual packet
- std::vector<uint8_t> payload_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/test/counted_builder_test.cc b/vendor_libs/test_vendor_lib/packets/test/counted_builder_test.cc
deleted file mode 100644
index 8d4d53a..0000000
--- a/vendor_libs/test_vendor_lib/packets/test/counted_builder_test.cc
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2018 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 "packets/counted_builder.h"
-
-#include <gtest/gtest.h>
-#include <forward_list>
-#include <memory>
-
-#include "types/address.h"
-
-using std::vector;
-
-namespace {
-vector<uint8_t> count = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-};
-
-} // namespace
-
-namespace test_vendor_lib {
-namespace packets {
-
-class CountedBuilderTest : public ::testing::Test {
- public:
- CountedBuilderTest() = default;
- ~CountedBuilderTest() = default;
-};
-
-TEST(CountedBuilderTest, buildCountTest) {
- std::unique_ptr<CountedBuilder> count_builder = std::make_unique<CountedBuilder>();
- ASSERT_EQ(1u, count_builder->size());
- std::unique_ptr<RawBuilder> raw1 = std::make_unique<RawBuilder>();
- std::unique_ptr<RawBuilder> raw2 = std::make_unique<RawBuilder>();
- std::unique_ptr<RawBuilder> raw3 = std::make_unique<RawBuilder>();
- std::unique_ptr<RawBuilder> raw4 = std::make_unique<RawBuilder>();
- std::unique_ptr<RawBuilder> raw5 = std::make_unique<RawBuilder>();
- std::unique_ptr<RawBuilder> raw6 = std::make_unique<RawBuilder>();
- std::unique_ptr<RawBuilder> raw7 = std::make_unique<RawBuilder>();
- raw1->AddOctets8(0x0706050403020100);
- raw2->AddOctets4(0x0b0a0908);
- raw3->AddOctets2(0x0d0c);
- raw4->AddOctets1(0x0e);
- raw5->AddOctets1(0x0f);
- raw6->AddAddress(Address({0x10, 0x11, 0x12, 0x13, 0x14, 0x15}));
- std::vector<uint8_t> count_subset(count.begin() + 0x16, count.end());
- raw7->AddOctets(count_subset);
-
- count_builder->Add(std::move(raw1));
- count_builder->Add(std::move(raw2));
- count_builder->Add(std::move(raw3));
- count_builder->Add(std::move(raw4));
- count_builder->Add(std::move(raw5));
- count_builder->Add(std::move(raw6));
- count_builder->Add(std::move(raw7));
-
- ASSERT_EQ(count.size(), count_builder->size() - 1);
-
- std::vector<uint8_t> packet;
- std::back_insert_iterator<std::vector<uint8_t>> it(packet);
-
- count_builder->Serialize(it);
- ASSERT_EQ(7u, packet[0]);
- std::vector<uint8_t> payload_packet(packet.begin() + 1, packet.end());
-
- ASSERT_EQ(count, payload_packet);
-}
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/test/link_layer_packet_builder_test.cc b/vendor_libs/test_vendor_lib/packets/test/link_layer_packet_builder_test.cc
deleted file mode 100644
index cc6c460..0000000
--- a/vendor_libs/test_vendor_lib/packets/test/link_layer_packet_builder_test.cc
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * Copyright 2018 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 "packets/link_layer/link_layer_packet_builder.h"
-
-#include <gtest/gtest.h>
-#include <forward_list>
-#include <memory>
-
-#include "link.h"
-#include "packets/link_layer/command_view.h"
-#include "packets/link_layer/disconnect_view.h"
-#include "packets/link_layer/encrypt_connection_view.h"
-#include "packets/link_layer/inquiry_response_view.h"
-#include "packets/link_layer/inquiry_view.h"
-#include "packets/link_layer/io_capability_negative_response_view.h"
-#include "packets/link_layer/io_capability_view.h"
-#include "packets/link_layer/le_advertisement_view.h"
-#include "packets/link_layer/page_response_view.h"
-#include "packets/link_layer/page_view.h"
-#include "packets/link_layer/response_view.h"
-
-#include "base/logging.h"
-
-using std::vector;
-
-namespace {
-vector<uint8_t> count = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-};
-
-} // namespace
-
-namespace test_vendor_lib {
-namespace packets {
-
-class LinkLayerPacketBuilderTest : public ::testing::Test {
- public:
- LinkLayerPacketBuilderTest() = default;
- ~LinkLayerPacketBuilderTest() = default;
-
- Address source_{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06}};
- Address dest_{{0x11, 0x12, 0x13, 0x14, 0x15, 0x16}};
-};
-
-TEST_F(LinkLayerPacketBuilderTest, constructorTest) {
- uint8_t reason = 0xf2;
- auto disconnect = DisconnectBuilder::Create(reason);
- ASSERT_EQ(disconnect->size(), sizeof(reason));
- auto wrapped_disconnect = LinkLayerPacketBuilder::WrapDisconnect(std::move(disconnect), source_, dest_);
-
- size_t wrapped_size = sizeof(uint8_t) + sizeof(uint32_t) + 2 * sizeof(Address) + sizeof(reason);
- ASSERT_EQ(wrapped_disconnect->size(), wrapped_size);
- std::vector<uint8_t> wrapped_vect;
- std::back_insert_iterator<std::vector<uint8_t>> it(wrapped_vect);
- wrapped_disconnect->Serialize(it);
- ASSERT_EQ(wrapped_size, wrapped_vect.size());
-
- std::vector<uint8_t> hand_wrapped_vect;
- // Add the size
- hand_wrapped_vect.push_back(sizeof(uint8_t) + 2 * sizeof(Address) + sizeof(reason));
- hand_wrapped_vect.push_back(0);
- hand_wrapped_vect.push_back(0);
- hand_wrapped_vect.push_back(0);
-
- hand_wrapped_vect.push_back(static_cast<uint8_t>(Link::PacketType::DISCONNECT));
-
- for (auto byte : source_.address) {
- hand_wrapped_vect.push_back(byte);
- }
- for (auto byte : dest_.address) {
- hand_wrapped_vect.push_back(byte);
- }
- hand_wrapped_vect.push_back(reason);
- ASSERT_EQ(wrapped_vect, hand_wrapped_vect);
-}
-
-TEST_F(LinkLayerPacketBuilderTest, disconnectTest) {
- uint8_t reason = 0x32;
- auto disconnect_builder = DisconnectBuilder::Create(reason);
- auto wrapped_disconnect = LinkLayerPacketBuilder::WrapDisconnect(std::move(disconnect_builder), source_, dest_);
- std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
- wrapped_disconnect->Serialize(it);
-
- LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
- ASSERT_EQ(view.size(), wrapped_disconnect->size());
- ASSERT_EQ(view.GetType(), Link::PacketType::DISCONNECT);
- ASSERT_EQ(source_, view.GetSourceAddress());
- ASSERT_EQ(dest_, view.GetDestinationAddress());
- DisconnectView disconnect = DisconnectView::GetDisconnect(view);
- ASSERT_EQ(disconnect.GetReason(), reason);
-}
-
-TEST_F(LinkLayerPacketBuilderTest, encryptConnectionTest) {
- std::vector<uint8_t> key = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
- auto encrypt_connection_builder = EncryptConnectionBuilder::Create(key);
- auto wrapped_encrypt_connection =
- LinkLayerPacketBuilder::WrapEncryptConnection(std::move(encrypt_connection_builder), source_, dest_);
- std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
- wrapped_encrypt_connection->Serialize(it);
-
- LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
- ASSERT_EQ(view.size(), wrapped_encrypt_connection->size());
- ASSERT_EQ(view.GetType(), Link::PacketType::ENCRYPT_CONNECTION);
- ASSERT_EQ(source_, view.GetSourceAddress());
- ASSERT_EQ(dest_, view.GetDestinationAddress());
- EncryptConnectionView encrypt_connection = EncryptConnectionView::GetEncryptConnection(view);
- auto key_itr = encrypt_connection.GetKey();
- ASSERT_EQ(key_itr.NumBytesRemaining(), key.size());
- for (size_t i = 0; i < key.size(); i++) {
- ASSERT_EQ(key[i], key_itr.extract<uint8_t>());
- }
-}
-
-TEST_F(LinkLayerPacketBuilderTest, encryptConnectionResponseTest) {
- std::vector<uint8_t> key = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
- auto encrypt_connection_builder = EncryptConnectionBuilder::Create(key);
- auto wrapped_encrypt_connection_response =
- LinkLayerPacketBuilder::WrapEncryptConnectionResponse(std::move(encrypt_connection_builder), source_, dest_);
- std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
- wrapped_encrypt_connection_response->Serialize(it);
-
- LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
- ASSERT_EQ(view.size(), wrapped_encrypt_connection_response->size());
- ASSERT_EQ(view.GetType(), Link::PacketType::ENCRYPT_CONNECTION_RESPONSE);
- ASSERT_EQ(source_, view.GetSourceAddress());
- ASSERT_EQ(dest_, view.GetDestinationAddress());
- EncryptConnectionView encrypt_connection = EncryptConnectionView::GetEncryptConnection(view);
- auto key_itr = encrypt_connection.GetKey();
- ASSERT_EQ(key_itr.NumBytesRemaining(), key.size());
- for (size_t i = 0; i < key.size(); i++) {
- ASSERT_EQ(key[i], key_itr.extract<uint8_t>());
- }
-}
-
-TEST_F(LinkLayerPacketBuilderTest, inquiryTest) {
- Inquiry::InquiryType inquiry_type = Inquiry::InquiryType::RSSI;
- auto inquiry_builder = InquiryBuilder::Create(inquiry_type);
- auto wrapped_inquiry = LinkLayerPacketBuilder::WrapInquiry(std::move(inquiry_builder), source_);
- std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
- wrapped_inquiry->Serialize(it);
-
- LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
- ASSERT_EQ(view.size(), wrapped_inquiry->size());
- ASSERT_EQ(view.GetType(), Link::PacketType::INQUIRY);
- ASSERT_EQ(source_, view.GetSourceAddress());
- ASSERT_EQ(Address::kEmpty, view.GetDestinationAddress());
- ASSERT_EQ(InquiryView::GetInquiry(view).GetType(), inquiry_type);
-}
-
-TEST_F(LinkLayerPacketBuilderTest, standardInquiryResponseTest) {
- uint8_t mode = 23;
- ClassOfDevice class_of_device{{0x11, 0x22, 0x33}};
- uint16_t offset = 0x3456;
- auto inquiry_response_builder = InquiryResponseBuilder::CreateStandard(mode, class_of_device, offset);
- auto wrapped_inquiry =
- LinkLayerPacketBuilder::WrapInquiryResponse(std::move(inquiry_response_builder), source_, dest_);
- std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
- wrapped_inquiry->Serialize(it);
- ASSERT_EQ(packet_ptr->size(), 24u);
-
- LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
- ASSERT_EQ(view.size(), wrapped_inquiry->size());
- ASSERT_EQ(view.GetType(), Link::PacketType::INQUIRY_RESPONSE);
- ASSERT_EQ(source_, view.GetSourceAddress());
- ASSERT_EQ(dest_, view.GetDestinationAddress());
- ASSERT_EQ(view.GetPayload().size(), 7u);
- InquiryResponseView inquiry_response = InquiryResponseView::GetInquiryResponse(view);
- ASSERT_EQ(inquiry_response.GetClockOffset(), offset);
- ASSERT_EQ(inquiry_response.GetType(), Inquiry::InquiryType::STANDARD);
- ASSERT_EQ(inquiry_response.GetPageScanRepetitionMode(), mode);
- ASSERT_EQ(inquiry_response.GetClassOfDevice(), class_of_device);
- ASSERT_EQ(inquiry_response.GetClockOffset(), offset);
-}
-
-TEST_F(LinkLayerPacketBuilderTest, rssiInquiryResponseTest) {
- uint8_t mode = 23;
- ClassOfDevice class_of_device{{0x11, 0x22, 0x33}};
- uint16_t offset = 0x3456;
- uint8_t rssi = 0x78;
- auto inquiry_response_builder = InquiryResponseBuilder::CreateRssi(mode, class_of_device, offset, rssi);
- auto wrapped_inquiry =
- LinkLayerPacketBuilder::WrapInquiryResponse(std::move(inquiry_response_builder), source_, dest_);
- std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
- wrapped_inquiry->Serialize(it);
-
- LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
- ASSERT_EQ(view.size(), wrapped_inquiry->size());
- ASSERT_EQ(view.GetType(), Link::PacketType::INQUIRY_RESPONSE);
- ASSERT_EQ(source_, view.GetSourceAddress());
- ASSERT_EQ(dest_, view.GetDestinationAddress());
- InquiryResponseView inquiry_response = InquiryResponseView::GetInquiryResponse(view);
- ASSERT_EQ(inquiry_response.GetClockOffset(), offset);
- ASSERT_EQ(inquiry_response.GetType(), Inquiry::InquiryType::RSSI);
- ASSERT_EQ(inquiry_response.GetPageScanRepetitionMode(), mode);
- ASSERT_EQ(inquiry_response.GetClassOfDevice(), class_of_device);
- ASSERT_EQ(inquiry_response.GetClockOffset(), offset);
- ASSERT_EQ(inquiry_response.GetRssi(), rssi);
-}
-
-TEST_F(LinkLayerPacketBuilderTest, extendedInquiryResponseTest) {
- uint8_t mode = 23;
- ClassOfDevice class_of_device{{0x11, 0x22, 0x33}};
- uint16_t offset = 0x3456;
- uint8_t rssi = 0x78;
- auto inquiry_response_builder = InquiryResponseBuilder::CreateExtended(mode, class_of_device, offset, rssi, count);
- auto wrapped_inquiry =
- LinkLayerPacketBuilder::WrapInquiryResponse(std::move(inquiry_response_builder), source_, dest_);
- std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
- wrapped_inquiry->Serialize(it);
-
- LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
- ASSERT_EQ(view.size(), wrapped_inquiry->size());
- ASSERT_EQ(view.GetType(), Link::PacketType::INQUIRY_RESPONSE);
- ASSERT_EQ(source_, view.GetSourceAddress());
- ASSERT_EQ(dest_, view.GetDestinationAddress());
- InquiryResponseView inquiry_response = InquiryResponseView::GetInquiryResponse(view);
- ASSERT_EQ(inquiry_response.GetClockOffset(), offset);
- ASSERT_EQ(inquiry_response.GetType(), Inquiry::InquiryType::EXTENDED);
- ASSERT_EQ(inquiry_response.GetPageScanRepetitionMode(), mode);
- ASSERT_EQ(inquiry_response.GetClassOfDevice(), class_of_device);
- ASSERT_EQ(inquiry_response.GetClockOffset(), offset);
- ASSERT_EQ(inquiry_response.GetRssi(), rssi);
- auto ext_it = inquiry_response.GetExtendedData();
- ASSERT_EQ(ext_it.NumBytesRemaining(), count.size());
- for (size_t i = 0; i < count.size(); i++) {
- ASSERT_EQ(count[i], *(ext_it++));
- }
-}
-
-TEST_F(LinkLayerPacketBuilderTest, ioCapabilityRequestTest) {
- uint8_t io_cap = 0x2;
- uint8_t oob_data_present = 0x1;
- uint8_t authentication_requirements = 0x5;
- auto io_capability_builder = IoCapabilityBuilder::Create(io_cap, oob_data_present, authentication_requirements);
- auto wrapped_io_capability_request =
- LinkLayerPacketBuilder::WrapIoCapabilityRequest(std::move(io_capability_builder), source_, dest_);
- std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
- wrapped_io_capability_request->Serialize(it);
-
- LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
- ASSERT_EQ(view.size(), wrapped_io_capability_request->size());
- ASSERT_EQ(view.GetType(), Link::PacketType::IO_CAPABILITY_REQUEST);
- ASSERT_EQ(source_, view.GetSourceAddress());
- ASSERT_EQ(dest_, view.GetDestinationAddress());
- IoCapabilityView io_capability = IoCapabilityView::GetIoCapability(view);
- ASSERT_EQ(io_capability.GetIoCapability(), io_cap);
- ASSERT_EQ(io_capability.GetOobDataPresent(), oob_data_present);
- ASSERT_EQ(io_capability.GetAuthenticationRequirements(), authentication_requirements);
-}
-
-TEST_F(LinkLayerPacketBuilderTest, ioCapabilityResponseTest) {
- uint8_t io_cap = 0x2;
- uint8_t oob_data_present = 0x1;
- uint8_t authentication_requirements = 0x5;
- auto io_capability_builder = IoCapabilityBuilder::Create(io_cap, oob_data_present, authentication_requirements);
- auto wrapped_io_capability_response =
- LinkLayerPacketBuilder::WrapIoCapabilityResponse(std::move(io_capability_builder), source_, dest_);
- std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
- wrapped_io_capability_response->Serialize(it);
-
- LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
- ASSERT_EQ(view.size(), wrapped_io_capability_response->size());
- ASSERT_EQ(view.GetType(), Link::PacketType::IO_CAPABILITY_RESPONSE);
- ASSERT_EQ(source_, view.GetSourceAddress());
- ASSERT_EQ(dest_, view.GetDestinationAddress());
- IoCapabilityView io_capability = IoCapabilityView::GetIoCapability(view);
- ASSERT_EQ(io_capability.GetIoCapability(), io_cap);
- ASSERT_EQ(io_capability.GetOobDataPresent(), oob_data_present);
- ASSERT_EQ(io_capability.GetAuthenticationRequirements(), authentication_requirements);
-}
-
-TEST_F(LinkLayerPacketBuilderTest, ioCapabilityNegativeResponseTest) {
- uint8_t reason = 23;
- auto io_capability_negative_response_builder = IoCapabilityNegativeResponseBuilder::Create(reason);
- auto wrapped_io_capability_negative_response = LinkLayerPacketBuilder::WrapIoCapabilityNegativeResponse(
- std::move(io_capability_negative_response_builder), source_, dest_);
- std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
- wrapped_io_capability_negative_response->Serialize(it);
-
- LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
- ASSERT_EQ(view.size(), wrapped_io_capability_negative_response->size());
- ASSERT_EQ(view.GetType(), Link::PacketType::IO_CAPABILITY_NEGATIVE_RESPONSE);
- ASSERT_EQ(source_, view.GetSourceAddress());
- ASSERT_EQ(dest_, view.GetDestinationAddress());
- IoCapabilityNegativeResponseView io_capability_negative_response =
- IoCapabilityNegativeResponseView::GetIoCapabilityNegativeResponse(view);
- ASSERT_EQ(io_capability_negative_response.GetReason(), reason);
-}
-
-TEST_F(LinkLayerPacketBuilderTest, pageTest) {
- uint8_t allow_role_switch = 1;
- ClassOfDevice class_of_device{{0x11, 0x22, 0x33}};
- auto page_builder = PageBuilder::Create(class_of_device, allow_role_switch);
- auto wrapped_page = LinkLayerPacketBuilder::WrapPage(std::move(page_builder), source_, dest_);
- std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
- wrapped_page->Serialize(it);
-
- LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
- ASSERT_EQ(view.size(), wrapped_page->size());
- ASSERT_EQ(view.GetType(), Link::PacketType::PAGE);
- ASSERT_EQ(source_, view.GetSourceAddress());
- ASSERT_EQ(dest_, view.GetDestinationAddress());
- PageView page = PageView::GetPage(view);
- ASSERT_EQ(page.GetAllowRoleSwitch(), allow_role_switch);
- ASSERT_EQ(page.GetClassOfDevice(), class_of_device);
-}
-
-TEST_F(LinkLayerPacketBuilderTest, pageResponseTest) {
- uint8_t try_role_switch = 2;
- auto page_response_builder = PageResponseBuilder::Create(try_role_switch);
- auto wrapped_page_response =
- LinkLayerPacketBuilder::WrapPageResponse(std::move(page_response_builder), source_, dest_);
- std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
- wrapped_page_response->Serialize(it);
-
- LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
- ASSERT_EQ(view.size(), wrapped_page_response->size());
- ASSERT_EQ(view.GetType(), Link::PacketType::PAGE_RESPONSE);
- ASSERT_EQ(source_, view.GetSourceAddress());
- ASSERT_EQ(dest_, view.GetDestinationAddress());
- PageResponseView page_response = PageResponseView::GetPageResponse(view);
- ASSERT_EQ(page_response.GetTryRoleSwitch(), try_role_switch);
-}
-
-TEST_F(LinkLayerPacketBuilderTest, responseTest) {
- uint16_t opcode = 0x1234;
- std::vector<uint64_t> data{
- 0x7060504030201000, 0x7161514131211101, 0x7262524232221202, 0x7363534333231303,
- 0x7464544434241404, 0x7565554535251505, 0x7666564636261606, 0x7767574737271707,
- 0x7868584838281808, 0x7969594939291909, 0x7a6a5a4a3a2a1a0a, 0x7b6b5b4b3b2b1b0b,
- 0x7c6c5c4c3c2c1c0c, 0x7d6d5d4d3d2d1d0d, 0x7e6e5e4e3e2e1e0e, 0x7f6f5f4f3f2f1f0f,
- };
- auto response_builder = ResponseBuilder::Create(opcode, data);
- auto wrapped_response = LinkLayerPacketBuilder::WrapResponse(std::move(response_builder), source_, dest_);
- std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
- wrapped_response->Serialize(it);
-
- LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
- ASSERT_EQ(view.size(), wrapped_response->size());
- ASSERT_EQ(view.GetType(), Link::PacketType::RESPONSE);
- ASSERT_EQ(source_, view.GetSourceAddress());
- ASSERT_EQ(dest_, view.GetDestinationAddress());
- ResponseView response = ResponseView::GetResponse(view);
- ASSERT_EQ(opcode, response.GetOpcode());
- auto data_it = response.GetResponseData();
- ASSERT_EQ(data.size(), data_it.NumBytesRemaining() / sizeof(uint64_t));
- ASSERT_EQ(0u, data_it.NumBytesRemaining() % sizeof(uint64_t));
- for (size_t i = 0; i < data.size(); i++) {
- ASSERT_EQ(data[i], data_it.extract<uint64_t>());
- }
-}
-
-TEST_F(LinkLayerPacketBuilderTest, wrapAclTest) {
- std::shared_ptr<std::vector<uint8_t>> count_shared = std::make_shared<std::vector<uint8_t>>(count);
- View count_view(count_shared, 0, count_shared->size());
- PacketView<true> count_packet_view({count_view});
- auto builder = ViewForwarderBuilder::Create(count_packet_view);
- auto wrapped_acl = LinkLayerPacketBuilder::WrapAcl(std::move(builder), source_, dest_);
- std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
- wrapped_acl->Serialize(it);
-
- LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
- ASSERT_EQ(view.size(), wrapped_acl->size());
- ASSERT_EQ(view.GetType(), Link::PacketType::ACL);
- ASSERT_EQ(source_, view.GetSourceAddress());
- ASSERT_EQ(dest_, view.GetDestinationAddress());
- auto acl_view = view.GetPayload();
- ASSERT_EQ(acl_view.size(), count_view.size());
- for (size_t i = 0; i < count_view.size(); i++) {
- ASSERT_EQ(acl_view[i], count_view[i]);
- }
-}
-
-TEST_F(LinkLayerPacketBuilderTest, wrapCommandTest) {
- uint16_t opcode = 0x0102;
- std::shared_ptr<std::vector<uint8_t>> count_shared = std::make_shared<std::vector<uint8_t>>(count);
- View count_view(count_shared, 0, count_shared->size());
- PacketView<true> args({count_view});
- auto builder = CommandBuilder::Create(opcode, args);
- auto wrapped_command = LinkLayerPacketBuilder::WrapCommand(std::move(builder), source_, dest_);
- std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
- wrapped_command->Serialize(it);
-
- LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
- ASSERT_EQ(view.size(), wrapped_command->size());
- ASSERT_EQ(view.GetType(), Link::PacketType::COMMAND);
- ASSERT_EQ(source_, view.GetSourceAddress());
- ASSERT_EQ(dest_, view.GetDestinationAddress());
- auto command_view = CommandView::GetCommand(view);
- ASSERT_EQ(opcode, command_view.GetOpcode());
- auto args_itr = command_view.GetData();
- ASSERT_EQ(args_itr.NumBytesRemaining(), count.size());
- for (size_t i = 0; i < count.size(); i++) {
- ASSERT_EQ(*args_itr++, count[i]);
- }
-}
-
-TEST_F(LinkLayerPacketBuilderTest, wrapLeAdvertisementTest) {
- LeAdvertisement::AddressType address_type = LeAdvertisement::AddressType::RANDOM;
- LeAdvertisement::AdvertisementType advertisement_type = LeAdvertisement::AdvertisementType::ADV_NONCONN_IND;
- auto builder = LeAdvertisementBuilder::Create(address_type, advertisement_type, count);
- auto wrapped_le_advertisement = LinkLayerPacketBuilder::WrapLeAdvertisement(std::move(builder), source_);
- std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
- wrapped_le_advertisement->Serialize(it);
-
- LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
- ASSERT_EQ(view.size(), wrapped_le_advertisement->size());
- ASSERT_EQ(view.GetType(), Link::PacketType::LE_ADVERTISEMENT);
- ASSERT_EQ(source_, view.GetSourceAddress());
- ASSERT_EQ(Address::kEmpty, view.GetDestinationAddress());
- LeAdvertisementView le_advertisement_view = LeAdvertisementView::GetLeAdvertisementView(view);
- ASSERT_EQ(address_type, le_advertisement_view.GetAddressType());
- ASSERT_EQ(advertisement_type, le_advertisement_view.GetAdvertisementType());
- auto le_advertisement_itr = le_advertisement_view.GetData();
- ASSERT_EQ(le_advertisement_itr.NumBytesRemaining(), count.size());
- for (size_t i = 0; i < count.size(); i++) {
- ASSERT_EQ(*(le_advertisement_itr++), count[i]);
- }
-}
-
-TEST_F(LinkLayerPacketBuilderTest, wrapLeScanTest) {
- auto le_scan = LinkLayerPacketBuilder::WrapLeScan(source_, dest_);
- std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
- le_scan->Serialize(it);
-
- LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
- ASSERT_EQ(view.size(), le_scan->size());
- ASSERT_EQ(view.GetType(), Link::PacketType::LE_SCAN);
- ASSERT_EQ(source_, view.GetSourceAddress());
- ASSERT_EQ(dest_, view.GetDestinationAddress());
- auto le_scan_view = view.GetPayload();
- ASSERT_EQ(0u, le_scan_view.size());
-}
-
-TEST_F(LinkLayerPacketBuilderTest, wrapLeScanResponseTest) {
- LeAdvertisement::AddressType address_type = LeAdvertisement::AddressType::PUBLIC_IDENTITY;
- LeAdvertisement::AdvertisementType advertisement_type = LeAdvertisement::AdvertisementType::SCAN_RESPONSE;
- auto builder = LeAdvertisementBuilder::Create(address_type, advertisement_type, count);
- auto wrapped_scan_response = LinkLayerPacketBuilder::WrapLeScanResponse(std::move(builder), source_, dest_);
- std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
- wrapped_scan_response->Serialize(it);
-
- LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
- ASSERT_EQ(view.size(), wrapped_scan_response->size());
- ASSERT_EQ(view.GetType(), Link::PacketType::LE_SCAN_RESPONSE);
- ASSERT_EQ(source_, view.GetSourceAddress());
- ASSERT_EQ(dest_, view.GetDestinationAddress());
- LeAdvertisementView le_advertisement_view = LeAdvertisementView::GetLeAdvertisementView(view);
- ASSERT_EQ(address_type, le_advertisement_view.GetAddressType());
- ASSERT_EQ(advertisement_type, le_advertisement_view.GetAdvertisementType());
- auto scan_response_itr = le_advertisement_view.GetData();
- ASSERT_EQ(scan_response_itr.NumBytesRemaining(), count.size());
- for (size_t i = 0; i < count.size(); i++) {
- ASSERT_EQ((*scan_response_itr++), count[i]);
- }
-}
-
-TEST_F(LinkLayerPacketBuilderTest, wrapScoTest) {
- std::shared_ptr<std::vector<uint8_t>> count_shared = std::make_shared<std::vector<uint8_t>>(count);
- View count_view(count_shared, 0, count_shared->size());
- PacketView<true> count_packet_view({count_view});
- auto builder = ViewForwarderBuilder::Create(count_packet_view);
- auto wrapped_sco = LinkLayerPacketBuilder::WrapSco(std::move(builder), source_, dest_);
- std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
- wrapped_sco->Serialize(it);
-
- LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
- ASSERT_EQ(view.size(), wrapped_sco->size());
- ASSERT_EQ(view.GetType(), Link::PacketType::SCO);
- ASSERT_EQ(source_, view.GetSourceAddress());
- ASSERT_EQ(dest_, view.GetDestinationAddress());
- auto sco_view = view.GetPayload();
- ASSERT_EQ(sco_view.size(), count.size());
- for (size_t i = 0; i < count.size(); i++) {
- ASSERT_EQ(sco_view[i], count[i]);
- }
-}
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/test/packet_builder_test.cc b/vendor_libs/test_vendor_lib/packets/test/packet_builder_test.cc
deleted file mode 100644
index 60e5d95..0000000
--- a/vendor_libs/test_vendor_lib/packets/test/packet_builder_test.cc
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright 2018 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 "packets/packet_builder.h"
-
-#include <gtest/gtest.h>
-#include <forward_list>
-#include <memory>
-
-using std::vector;
-
-namespace {
-vector<uint8_t> count_all = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-};
-
-vector<uint8_t> count_1 = {
- 0x00,
- 0x01,
- 0x02,
-};
-
-vector<uint8_t> count_2 = {
- 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
-};
-
-vector<uint8_t> count_3 = {
- 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-};
-} // namespace
-
-namespace test_vendor_lib {
-namespace packets {
-
-template <bool little_endian>
-class EndianBuilder : public PacketBuilder<little_endian> {
- public:
- EndianBuilder(uint8_t byte, uint16_t two_bytes, uint32_t four_bytes, uint64_t eight_bytes)
- : byte_(byte), two_bytes_(two_bytes), four_bytes_(four_bytes), eight_bytes_(eight_bytes) {}
- ~EndianBuilder() = default;
-
- virtual size_t size() const override {
- return sizeof(signature_) + sizeof(byte_) + sizeof(two_bytes_) + sizeof(four_bytes_) + sizeof(eight_bytes_);
- }
-
- virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
- std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
- packet->reserve(size());
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet);
- Serialize(it);
- return packet;
- }
-
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
- PacketBuilder<little_endian>::insert(signature_, it);
- PacketBuilder<little_endian>::insert(byte_, it);
- PacketBuilder<little_endian>::insert(two_bytes_, it);
- PacketBuilder<little_endian>::insert(four_bytes_, it);
- PacketBuilder<little_endian>::insert(eight_bytes_, it);
- }
-
- private:
- uint32_t signature_{(little_endian ? 0x03020100 : 0x00010203)};
- uint8_t byte_;
- uint16_t two_bytes_;
- uint32_t four_bytes_;
- uint64_t eight_bytes_;
-};
-
-class PacketBuilderEndianTest : public ::testing::Test {
- public:
- PacketBuilderEndianTest() = default;
- ~PacketBuilderEndianTest() = default;
-};
-
-TEST(PacketBuilderEndianTest, insertTest) {
- EndianBuilder<true> little(0x04, 0x0605, 0x0a090807, 0x1211100f0e0d0c0b);
- EndianBuilder<false> big(0x04, 0x0506, 0x0708090a, 0x0b0c0d0e0f101112);
- ASSERT_EQ(*big.FinalPacket(), *little.FinalPacket());
-}
-
-template <typename T>
-class VectorBuilder : public PacketBuilder<true> {
- public:
- VectorBuilder(std::vector<uint64_t> vect) {
- for (uint64_t element : vect) {
- vect.push_back(static_cast<T>(element));
- }
- }
- ~VectorBuilder() = default;
-
- virtual size_t size() const override {
- return vect_.size() * sizeof(T);
- }
-
- virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
- std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
- packet->reserve(size());
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet);
- Serialize(it);
- return packet;
- }
-
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
- PacketBuilder<true>::insert_vector(vect_, it);
- }
-
- private:
- std::vector<T> vect_;
-};
-
-template <typename T>
-class InsertElementsBuilder : public PacketBuilder<true> {
- public:
- InsertElementsBuilder(std::vector<uint64_t> vect) {
- for (uint64_t element : vect) {
- vect.push_back(static_cast<T>(element));
- }
- }
- virtual ~InsertElementsBuilder() = default;
-
- virtual size_t size() const override {
- return vect_.size() * sizeof(T);
- }
-
- virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
- std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
- packet->reserve(size());
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet);
- Serialize(it);
- return packet;
- }
-
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
- for (T elem : vect_) {
- PacketBuilder<true>::insert(elem, it);
- }
- }
-
- private:
- std::vector<T> vect_;
-};
-
-std::vector<uint64_t> vector_data{
- 0x7060504030201000, 0x7161514131211101, 0x7262524232221202, 0x7363534333231303, 0x7464544434241404,
- 0x7565554535251505, 0x7666564636261606, 0x7767574737271707, 0x7868584838281808,
-};
-
-template <typename T>
-class VectorBuilderTest : public ::testing::Test {
- public:
- VectorBuilderTest() = default;
- ~VectorBuilderTest() = default;
-
- void SetUp() {
- packet_1_ = std::shared_ptr<VectorBuilder<T>>(new VectorBuilder<T>(vector_data));
- packet_2_ = std::shared_ptr<InsertElementsBuilder<T>>(new InsertElementsBuilder<T>(vector_data));
- }
-
- void TearDown() {
- packet_1_.reset();
- packet_2_.reset();
- }
-
- std::shared_ptr<VectorBuilder<T>> packet_1_;
- std::shared_ptr<InsertElementsBuilder<T>> packet_2_;
-};
-
-using VectorBaseTypes = ::testing::Types<uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t>;
-TYPED_TEST_CASE(VectorBuilderTest, VectorBaseTypes);
-
-TYPED_TEST(VectorBuilderTest, insertVectorTest) {
- ASSERT_EQ(*(this->packet_1_->FinalPacket()), *(this->packet_2_->FinalPacket()));
-}
-
-class NestedBuilder : public PacketBuilder<true> {
- public:
- ~NestedBuilder() = default;
-
- virtual size_t size() const override {
- size_t payload_size = (payload_ ? payload_->size() : 0);
- return 1 + payload_size;
- }
-
- static std::unique_ptr<NestedBuilder> Create(uint8_t level) {
- return std::unique_ptr<NestedBuilder>(new NestedBuilder(level));
- }
-
- static std::unique_ptr<NestedBuilder> CreateNested(std::unique_ptr<BasePacketBuilder> payload, uint8_t level) {
- return std::unique_ptr<NestedBuilder>(new NestedBuilder(std::move(payload), level));
- }
-
- virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
- std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
- packet->reserve(size());
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet);
- Serialize(it);
- return packet;
- }
-
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
- PacketBuilder<true>::insert(level_, it);
- if (payload_) {
- payload_->Serialize(it);
- }
- }
-
- private:
- std::unique_ptr<BasePacketBuilder> payload_;
- uint8_t level_;
-
- NestedBuilder(std::unique_ptr<BasePacketBuilder> inner, uint8_t level) : payload_(std::move(inner)), level_(level) {}
- NestedBuilder(uint8_t level) : level_(level) {}
-};
-
-class BuilderBuilderTest : public ::testing::Test {};
-
-TEST(BuilderBuilderTest, nestingTest) {
- std::unique_ptr<BasePacketBuilder> innermost = NestedBuilder::Create(0);
- std::unique_ptr<BasePacketBuilder> number_1 = NestedBuilder::CreateNested(std::move(innermost), 1);
- std::unique_ptr<BasePacketBuilder> number_2 = NestedBuilder::CreateNested(std::move(number_1), 2);
- std::unique_ptr<BasePacketBuilder> number_3 = NestedBuilder::CreateNested(std::move(number_2), 3);
- std::unique_ptr<BasePacketBuilder> number_4 = NestedBuilder::CreateNested(std::move(number_3), 4);
- std::unique_ptr<NestedBuilder> number_5 = NestedBuilder::CreateNested(std::move(number_4), 5);
-
- std::vector<uint8_t> count_down{5, 4, 3, 2, 1, 0};
- ASSERT_EQ(*number_5->FinalPacket(), count_down);
-}
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/test/packet_view_test.cc b/vendor_libs/test_vendor_lib/packets/test/packet_view_test.cc
deleted file mode 100644
index 65cd305..0000000
--- a/vendor_libs/test_vendor_lib/packets/test/packet_view_test.cc
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * Copyright 2018 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 "packets/packet_view.h"
-
-#include <gtest/gtest.h>
-#include <forward_list>
-#include <memory>
-
-#include "types/address.h"
-
-using std::vector;
-
-namespace {
-vector<uint8_t> count_all = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-};
-
-vector<uint8_t> count_1 = {
- 0x00,
- 0x01,
- 0x02,
-};
-
-vector<uint8_t> count_2 = {
- 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
-};
-
-vector<uint8_t> count_3 = {
- 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-};
-} // namespace
-
-namespace test_vendor_lib {
-namespace packets {
-
-template <typename T>
-class IteratorTest : public ::testing::Test {
- public:
- IteratorTest() = default;
- ~IteratorTest() = default;
-
- void SetUp() {
- packet = std::shared_ptr<T>(new T({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())}));
- }
-
- void TearDown() {
- packet.reset();
- }
-
- std::shared_ptr<T> packet;
-};
-
-using PacketViewTypes = ::testing::Types<PacketView<true>, PacketView<false>>;
-TYPED_TEST_CASE(IteratorTest, PacketViewTypes);
-
-class IteratorExtractTest : public ::testing::Test {
- public:
- IteratorExtractTest() = default;
- ~IteratorExtractTest() = default;
-};
-
-template <typename T>
-class PacketViewTest : public IteratorTest<T> {
- public:
- PacketViewTest() = default;
- ~PacketViewTest() = default;
-};
-
-using PacketViewTypes = ::testing::Types<PacketView<true>, PacketView<false>>;
-TYPED_TEST_CASE(PacketViewTest, PacketViewTypes);
-
-class PacketViewMultiViewTest : public ::testing::Test {
- public:
- PacketViewMultiViewTest() = default;
- ~PacketViewMultiViewTest() = default;
-};
-
-class ViewTest : public ::testing::Test {
- public:
- ViewTest() = default;
- ~ViewTest() = default;
-};
-
-TEST(IteratorExtractTest, extractLeTest) {
- PacketView<true> packet({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
- auto general_case = packet.begin();
-
- ASSERT_EQ(0x00, general_case.extract<uint8_t>());
- ASSERT_EQ(0x0201, general_case.extract<uint16_t>());
- ASSERT_EQ(0x06050403u, general_case.extract<uint32_t>());
- ASSERT_EQ(0x0e0d0c0b0a090807u, general_case.extract<uint64_t>());
- ASSERT_EQ(0x0f, general_case.extract<uint8_t>());
- Address raw({0x10, 0x11, 0x12, 0x13, 0x14, 0x15});
- ASSERT_EQ(raw, general_case.extract<Address>());
- ASSERT_EQ(0x16, general_case.extract<uint8_t>());
-}
-
-TEST(IteratorExtractTest, extractBeTest) {
- PacketView<false> packet({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
- auto general_case = packet.begin();
-
- ASSERT_EQ(0x00, general_case.extract<uint8_t>());
- ASSERT_EQ(0x0102, general_case.extract<uint16_t>());
- ASSERT_EQ(0x03040506u, general_case.extract<uint32_t>());
- ASSERT_EQ(0x0708090a0b0c0d0eu, general_case.extract<uint64_t>());
- ASSERT_EQ(0x0f, general_case.extract<uint8_t>());
- Address raw({0x15, 0x14, 0x13, 0x12, 0x11, 0x10});
- ASSERT_EQ(raw, general_case.extract<Address>());
- ASSERT_EQ(0x16, general_case.extract<uint8_t>());
-}
-
-TYPED_TEST(IteratorTest, extractBoundsDeathTest) {
- auto bounds_test = this->packet->end();
-
- ASSERT_DEATH(bounds_test.template extract<uint8_t>(), "");
- ASSERT_DEATH(bounds_test.template extract<uint16_t>(), "");
- ASSERT_DEATH(bounds_test.template extract<uint32_t>(), "");
- ASSERT_DEATH(bounds_test.template extract<uint64_t>(), "");
-}
-
-TYPED_TEST(IteratorTest, dereferenceDeathTest) {
- auto dereference_test = this->packet->end();
-
- ASSERT_DEATH(*dereference_test, "");
- ASSERT_EQ(0x1f, *(dereference_test - 1));
-}
-
-TYPED_TEST(IteratorTest, plusEqTest) {
- auto plus_eq = this->packet->begin();
- for (size_t i = 0; i < count_all.size(); i += 2) {
- ASSERT_EQ(count_all[i], *plus_eq) << "+= test: Dereferenced iterator does not equal expected at index " << i;
- plus_eq += 2;
- }
-}
-
-TYPED_TEST(IteratorTest, preIncrementTest) {
- auto plus_plus = this->packet->begin();
- for (size_t i = 0; i < count_all.size() - 1; i++) {
- ASSERT_EQ(count_all[i + 1], *(++plus_plus)) << "Pre-increment test: Dereferenced iterator does not equal expected "
- << "at index " << i;
- }
-}
-
-TYPED_TEST(IteratorTest, postIncrementTest) {
- auto plus_plus = this->packet->begin();
- for (size_t i = 0; i < count_all.size(); i++) {
- ASSERT_EQ(count_all[i], *(plus_plus++)) << "Post-increment test: Dereferenced iterator does not equal expected "
- << "at index " << i;
- }
-}
-
-TYPED_TEST(IteratorTest, additionTest) {
- auto plus = this->packet->begin();
- for (size_t i = 0; i < count_all.size(); i++) {
- ASSERT_EQ(count_all[i], *plus) << "+ test: Dereferenced iterator does not equal expected at index " << i;
- plus = plus + 1;
- }
-}
-
-TYPED_TEST(IteratorTest, minusEqTest) {
- auto minus_eq = this->packet->end();
- minus_eq -= 1;
- size_t index = count_all.size() - 1;
- for (size_t i = 0; index > i; i++) {
- ASSERT_EQ(count_all[index], *minus_eq)
- << "-= test: Dereferenced iterator does not equal expected at index " << index;
- index -= i;
- minus_eq -= i;
- }
-}
-
-TYPED_TEST(IteratorTest, preDecrementTest) {
- auto minus_minus = this->packet->end();
- for (size_t i = count_all.size(); i > 0; i--) {
- ASSERT_EQ(count_all[i - 1], *(--minus_minus))
- << "Pre-decrement test: Dereferenced iterator does not equal expected "
- << "at index " << i;
- }
-}
-
-TYPED_TEST(IteratorTest, postDecrementTest) {
- auto minus_minus = this->packet->end();
- minus_minus--;
- for (size_t i = count_all.size() - 1; i > 0; i--) {
- ASSERT_EQ(count_all[i], *(minus_minus--)) << "Post-decrement test: Dereferenced iterator does not equal expected "
- << "at index " << i;
- }
-}
-
-TYPED_TEST(IteratorTest, subtractionTest) {
- auto minus = this->packet->end();
- minus = minus - 1;
- for (size_t i = count_all.size() - 1; i > 0; i--) {
- ASSERT_EQ(count_all[i], *minus) << "- test: Dereferenced iterator does not equal expected at index " << i;
- minus = minus - 1;
- }
-}
-
-TYPED_TEST(IteratorTest, differenceTest) {
- auto begin = this->packet->begin();
- auto end = this->packet->end();
- int difference = end - begin;
- ASSERT_EQ(difference, static_cast<int>(count_all.size()));
- int neg_difference = begin - end;
- ASSERT_EQ(neg_difference, -static_cast<int>(count_all.size()));
-}
-
-TYPED_TEST(IteratorTest, equalityTest) {
- auto begin = this->packet->begin();
- auto end = this->packet->end();
- auto begin_copy = this->packet->begin();
- auto end_copy = this->packet->end();
- ASSERT_EQ(begin_copy, begin);
- ASSERT_EQ(end_copy, end);
-}
-
-TYPED_TEST(IteratorTest, comparisonsTest) {
- auto begin = this->packet->begin();
- auto end = this->packet->end();
- auto begin_copy = this->packet->begin();
- auto end_copy = this->packet->end();
- ASSERT_EQ(begin_copy, begin);
- ASSERT_EQ(end_copy, end);
- ASSERT_NE(begin, end);
- ASSERT_TRUE(begin < end);
- ASSERT_FALSE(end < end);
- ASSERT_FALSE(end < begin);
- ASSERT_FALSE(begin > end);
- ASSERT_FALSE(end > end);
- ASSERT_TRUE(end > begin);
- ASSERT_TRUE(begin <= end);
- ASSERT_TRUE(end <= end);
- ASSERT_FALSE(end <= begin);
- ASSERT_FALSE(begin >= end);
- ASSERT_TRUE(end >= end);
- ASSERT_TRUE(end >= begin);
-}
-
-TYPED_TEST(PacketViewTest, getLengthTest) {
- size_t length = this->packet->size();
- ASSERT_EQ(length, count_all.size());
-}
-
-TYPED_TEST(PacketViewTest, getAtIndexTest) {
- size_t past_end = this->packet->size();
- ASSERT_DEATH(this->packet->at(past_end), "");
- size_t working_index = 0x1f;
- ASSERT_EQ(0x1f, this->packet->at(working_index));
-}
-
-TYPED_TEST(PacketViewTest, arrayOperatorTest) {
- size_t past_end = this->packet->size();
- ASSERT_DEATH((*(this->packet))[past_end], "");
- size_t working_index = 0x1f;
- ASSERT_EQ(0x1f, (*(this->packet))[working_index]);
-}
-
-TYPED_TEST(PacketViewTest, numBytesRemainingTest) {
- auto all = this->packet->begin();
- size_t remaining = all.NumBytesRemaining();
- for (size_t n = remaining; n > 0; n--) {
- ASSERT_EQ(remaining, all.NumBytesRemaining());
- all++;
- remaining--;
- }
- ASSERT_EQ(static_cast<size_t>(0), all.NumBytesRemaining());
- ASSERT_DEATH(*(all++), "");
- all++;
- ASSERT_EQ(static_cast<size_t>(0), all.NumBytesRemaining());
- ASSERT_DEATH(*(all++), "");
-}
-
-using SubViewTestParam = std::pair<size_t, size_t>;
-class SubViewBaseTest : public ::testing::TestWithParam<SubViewTestParam> {
- public:
- class SubPacketView : public PacketView<true> {
- public:
- using PacketView<true>::PacketView;
- PacketView<true> Slice(size_t header, size_t tail) {
- return PacketView<true>::SubViewLittleEndian(header, tail);
- }
- };
-};
-
-class SubViewPassTest : public SubViewBaseTest {};
-
-TEST_P(SubViewPassTest, subViewTest) {
- auto header = GetParam().first;
- auto tail = GetParam().second;
- SubPacketView single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
- SubPacketView multi_view({
- View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
- View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
- View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
- });
-
- auto single_slice = single_view.Slice(header, tail);
- auto multi_slice = multi_view.Slice(header, tail);
-
- ASSERT_EQ(single_slice.size(), tail - header);
- ASSERT_EQ(single_slice.size(), multi_slice.size());
- for (size_t i = 0; i < single_slice.size(); i++) {
- ASSERT_EQ(single_slice[i], multi_slice[i]);
- }
-}
-
-static const size_t boundary_1 = count_1.size();
-static const size_t boundary_2 = count_1.size() + count_2.size();
-
-INSTANTIATE_TEST_CASE_P(
- chopomatic, SubViewPassTest,
- ::testing::Values(
- // {begin, end} pairs for subsets into the PacketView
- SubViewTestParam{0, 0}, SubViewTestParam{0, boundary_1}, SubViewTestParam{0, boundary_1 + 1},
- SubViewTestParam{0, boundary_2}, SubViewTestParam{0, boundary_2 + 1}, SubViewTestParam{0, count_all.size()},
- SubViewTestParam{boundary_1 - 1, boundary_1}, SubViewTestParam{boundary_1 - 1, boundary_1 + 1},
- SubViewTestParam{boundary_1 - 1, boundary_2}, SubViewTestParam{boundary_1 - 1, boundary_2 + 1},
- SubViewTestParam{boundary_1 - 1, count_all.size()}, SubViewTestParam{boundary_1, boundary_1},
- SubViewTestParam{boundary_1, boundary_2}, SubViewTestParam{boundary_1, boundary_2 + 1},
- SubViewTestParam{boundary_1, count_all.size()}, SubViewTestParam{boundary_2 - 1, boundary_2},
- SubViewTestParam{boundary_2 - 1, boundary_2 + 1}, SubViewTestParam{boundary_2 - 1, count_all.size()},
- SubViewTestParam{boundary_2, boundary_2}, SubViewTestParam{boundary_2, boundary_2 + 1},
- SubViewTestParam{boundary_2, count_all.size()}, SubViewTestParam{count_all.size() - 1, count_all.size()},
- SubViewTestParam{count_all.size(), count_all.size()}));
-
-class SubViewDeathTest : public SubViewBaseTest {};
-
-TEST_P(SubViewDeathTest, subViewDeathTest) {
- auto header = GetParam().first;
- auto tail = GetParam().second;
- SubPacketView single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
- SubPacketView multi_view({
- View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
- View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
- View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
- });
-
- ASSERT_DEATH(auto single_slice = single_view.Slice(header, tail), "");
- ASSERT_DEATH(auto multi_slice = multi_view.Slice(header, tail), "");
-}
-
-INSTANTIATE_TEST_CASE_P(chopomaticDeath, SubViewDeathTest,
- ::testing::Values(
- // {begin, end} pairs for subsets into the PacketView
- SubViewTestParam{1, 0}, SubViewTestParam{count_all.size(), count_all.size() - 1},
- SubViewTestParam{count_all.size(), count_all.size() + 1}));
-
-TEST(SubViewTest, simpleSubViewTest) {
- PacketView<true> view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
- PacketView<true> sub_1_view = view.SubViewLittleEndian(0, view.size());
- PacketView<true> sub_2_view = sub_1_view.SubViewLittleEndian(0, sub_1_view.size());
- PacketView<true> sub_3_view = sub_2_view.SubViewLittleEndian(0, sub_2_view.size());
- PacketView<true> sub_4_view = sub_3_view.SubViewLittleEndian(0, sub_3_view.size());
- ASSERT_EQ(sub_1_view.size(), view.size());
- ASSERT_EQ(sub_2_view.size(), view.size());
- ASSERT_EQ(sub_3_view.size(), view.size());
- ASSERT_EQ(sub_4_view.size(), view.size());
-}
-
-TEST(SubViewTest, realSubViewTest) {
- PacketView<true> view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
- std::vector<PacketView<true>> sub_views{view};
- for (size_t i = 1; i < 6; i++) {
- size_t parent_size = sub_views[i - 1].size();
- sub_views.push_back(sub_views[i - 1].SubViewLittleEndian(1, parent_size - 1));
- ASSERT_EQ(sub_views[i][0], i);
- ASSERT_EQ(sub_views[i].size(), parent_size - 2);
- }
-}
-
-TEST(SubViewTest, subSubViewTest) {
- PacketView<true> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
- PacketView<true> multi_view({
- View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
- View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
- View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
- });
- ASSERT_EQ(single_view.size(), multi_view.size());
- for (size_t i = 0; i < count_all.size() / 2; i++) {
- PacketView<true> sub_single_view = single_view.SubViewLittleEndian(i, count_all.size() - i);
- PacketView<true> sub_multi_view = multi_view.SubViewLittleEndian(i, count_all.size() - i);
- ASSERT_EQ(count_all.size() - 2 * i, sub_single_view.size());
- ASSERT_EQ(sub_single_view.size(), sub_multi_view.size());
- for (size_t j = 0; j < sub_single_view.size() / 2; j++) {
- PacketView<true> sub_sub_single_view = sub_single_view.SubViewLittleEndian(j, sub_single_view.size() - j);
- PacketView<true> sub_sub_multi_view = sub_multi_view.SubViewLittleEndian(j, sub_multi_view.size() - j);
- ASSERT_EQ(sub_single_view.size() - 2 * j, sub_sub_single_view.size());
- ASSERT_EQ(sub_sub_single_view.size(), sub_sub_multi_view.size());
- }
- }
-}
-
-TEST(PacketViewMultiViewTest, sizeTest) {
- PacketView<true> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
- PacketView<true> multi_view({
- View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
- View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
- View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
- });
- ASSERT_EQ(single_view.size(), multi_view.size());
-}
-
-TEST(PacketViewMultiViewTest, dereferenceTestLittleEndian) {
- PacketView<true> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
- PacketView<true> multi_view({
- View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
- View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
- View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
- });
- auto single_itr = single_view.begin();
- auto multi_itr = multi_view.begin();
- for (size_t i = 0; i < single_view.size(); i++) {
- ASSERT_EQ(*(single_itr++), *(multi_itr++));
- }
- ASSERT_DEATH(*multi_itr, "");
-}
-
-TEST(PacketViewMultiViewTest, dereferenceTestBigEndian) {
- PacketView<false> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
- PacketView<false> multi_view({
- View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
- View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
- View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
- });
- auto single_itr = single_view.begin();
- auto multi_itr = multi_view.begin();
- for (size_t i = 0; i < single_view.size(); i++) {
- ASSERT_EQ(*(single_itr++), *(multi_itr++));
- }
- ASSERT_DEATH(*multi_itr, "");
-}
-
-TEST(PacketViewMultiViewTest, arrayOperatorTest) {
- PacketView<true> single_view({View(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size())});
- PacketView<true> multi_view({
- View(std::make_shared<const vector<uint8_t>>(count_1), 0, count_1.size()),
- View(std::make_shared<const vector<uint8_t>>(count_2), 0, count_2.size()),
- View(std::make_shared<const vector<uint8_t>>(count_3), 0, count_3.size()),
- });
- for (size_t i = 0; i < single_view.size(); i++) {
- ASSERT_EQ(single_view[i], multi_view[i]);
- }
- ASSERT_DEATH(multi_view[single_view.size()], "");
-}
-
-TEST(ViewTest, arrayOperatorTest) {
- View view_all(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size());
- size_t past_end = view_all.size();
- for (size_t i = 0; i < past_end; i++) {
- ASSERT_EQ(view_all[i], count_all[i]);
- }
- ASSERT_DEATH(view_all[past_end], "");
-
- size_t header_size = 2;
- size_t tail_size = 3;
- View view_subset(std::make_shared<const vector<uint8_t>>(count_all), header_size, count_all.size() - tail_size);
- View view_subset2(view_all, header_size, count_all.size() - tail_size);
- size_t subset_length = view_subset.size();
- for (size_t i = 0; i < subset_length; i++) {
- ASSERT_EQ(view_subset[i], count_all[header_size + i]);
- ASSERT_EQ(view_subset[i], view_subset2[i]);
- }
- ASSERT_DEATH(view_subset[subset_length + 1], "");
- ASSERT_DEATH(view_subset2[subset_length + 1], "");
-}
-
-TEST(ViewTest, earlySubSubViewTest) {
- View view(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size());
- View sub_1_view(view, view.size() - 3, view.size() - 1);
- View sub_2_view(sub_1_view, 1, 2);
- ASSERT_EQ(sub_1_view.size(), 2u);
- ASSERT_EQ(sub_2_view.size(), 1u);
-}
-
-TEST(ViewTest, subSubViewTest) {
- View view(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size());
- std::vector<View> sub_views{view};
- for (size_t i = 1; i < 6; i++) {
- size_t parent_size = sub_views[i - 1].size();
- sub_views.push_back({View(sub_views[i - 1], 1, parent_size - 1)});
- ASSERT_EQ(sub_views[i][0], i);
- ASSERT_EQ(sub_views[i].size(), parent_size - 2);
- }
-}
-
-TEST(ViewTest, zeroSubViewTest) {
- View view(std::make_shared<const vector<uint8_t>>(count_all), 0, count_all.size());
- View subview(view, view.size(), view.size() + 1);
- ASSERT_EQ(subview.size(), 0u);
-}
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/test/raw_builder_test.cc b/vendor_libs/test_vendor_lib/packets/test/raw_builder_test.cc
deleted file mode 100644
index f67ba0b..0000000
--- a/vendor_libs/test_vendor_lib/packets/test/raw_builder_test.cc
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2018 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 "packets/raw_builder.h"
-
-#include <gtest/gtest.h>
-#include <forward_list>
-#include <memory>
-
-#include "types/address.h"
-
-using std::vector;
-
-namespace {
-vector<uint8_t> count = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-};
-
-} // namespace
-
-namespace test_vendor_lib {
-namespace packets {
-
-class RawBuilderTest : public ::testing::Test {
- public:
- RawBuilderTest() = default;
- ~RawBuilderTest() = default;
-};
-
-TEST(RawBuilderTest, buildCountTest) {
- std::unique_ptr<RawBuilder> count_builder = std::make_unique<RawBuilder>();
- ASSERT_EQ(0u, count_builder->size());
- count_builder->AddOctets8(0x0706050403020100);
- count_builder->AddOctets4(0x0b0a0908);
- count_builder->AddOctets2(0x0d0c);
- count_builder->AddOctets1(0x0e);
- count_builder->AddOctets1(0x0f);
- count_builder->AddAddress(Address({0x10, 0x11, 0x12, 0x13, 0x14, 0x15}));
- std::vector<uint8_t> count_subset(count.begin() + 0x16, count.end());
- count_builder->AddOctets(count_subset);
-
- ASSERT_EQ(count.size(), count_builder->size());
-
- std::vector<uint8_t> packet;
- std::back_insert_iterator<std::vector<uint8_t>> it(packet);
-
- count_builder->Serialize(it);
-
- ASSERT_EQ(count, packet);
-}
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/view.cc b/vendor_libs/test_vendor_lib/packets/view.cc
deleted file mode 100644
index 7dbd8bd..0000000
--- a/vendor_libs/test_vendor_lib/packets/view.cc
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2018 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 "view.h"
-
-#include <base/logging.h>
-
-namespace test_vendor_lib {
-namespace packets {
-
-View::View(std::shared_ptr<const std::vector<uint8_t>> data, size_t begin, size_t end)
- : data_(data), begin_(begin < data_->size() ? begin : data_->size()),
- end_(end < data_->size() ? end : data_->size()) {}
-
-View::View(const View& view, size_t begin, size_t end) : data_(view.data_) {
- begin_ = (begin < view.size() ? begin : view.size());
- begin_ += view.begin_;
- end_ = (end < view.size() ? end : view.size());
- end_ += view.begin_;
-}
-
-uint8_t View::operator[](size_t i) const {
- CHECK(i + begin_ < end_) << "Out of bounds access at " << i;
- return data_->operator[](i + begin_);
-}
-
-size_t View::size() const {
- return end_ - begin_;
-}
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/packets/view.h b/vendor_libs/test_vendor_lib/packets/view.h
deleted file mode 100644
index ca38875..0000000
--- a/vendor_libs/test_vendor_lib/packets/view.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright 2018 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.
- */
-
-#pragma once
-
-#include <cstdint>
-#include <vector>
-
-namespace test_vendor_lib {
-namespace packets {
-
-// Base class that holds a shared pointer to data with bounds.
-class View {
- public:
- View(std::shared_ptr<const std::vector<uint8_t>> data, size_t begin, size_t end);
- View(const View& view, size_t begin, size_t end);
- View(const View& view) = default;
- virtual ~View() = default;
-
- uint8_t operator[](size_t i) const;
-
- size_t size() const;
-
- private:
- std::shared_ptr<const std::vector<uint8_t>> data_;
- size_t begin_;
- size_t end_;
-};
-
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/scripts/simple_stack.py b/vendor_libs/test_vendor_lib/scripts/simple_stack.py
index 4f42bf2..95d973a 100644
--- a/vendor_libs/test_vendor_lib/scripts/simple_stack.py
+++ b/vendor_libs/test_vendor_lib/scripts/simple_stack.py
@@ -146,7 +146,7 @@
def receive_response(self):
ready_to_read, ready_to_write, in_error = \
- select.select(
+ select(
[ self._connection._socket ],
[ ],
[ self._connection._socket ],
diff --git a/vendor_libs/test_vendor_lib/scripts/test_channel.py b/vendor_libs/test_vendor_lib/scripts/test_channel.py
index 15f5f1f..447130b 100644
--- a/vendor_libs/test_vendor_lib/scripts/test_channel.py
+++ b/vendor_libs/test_vendor_lib/scripts/test_channel.py
@@ -208,6 +208,12 @@
"""
self._test_channel.send_command('set', args.split())
+ def do_set_device_address(self, args):
+ """Arguments: dev_num addr Set the address of device dev_num equal to addr.
+
+ """
+ self._test_channel.send_command('set_device_address', args.split())
+
def do_list(self, args):
"""Arguments: [dev_num [attr]] List the devices from the controller, optionally filtered by device and attr.
diff --git a/vendor_libs/test_vendor_lib/test/iterator_test.cc b/vendor_libs/test_vendor_lib/test/iterator_test.cc
index 4a85068..0e7b67c 100644
--- a/vendor_libs/test_vendor_lib/test/iterator_test.cc
+++ b/vendor_libs/test_vendor_lib/test/iterator_test.cc
@@ -46,13 +46,13 @@
class IteratorTest : public ::testing::Test {
public:
IteratorTest() = default;
- ~IteratorTest() = default;
+ ~IteratorTest() override = default;
- void SetUp() {
+ void SetUp() override {
packet = TestPacket::make_new_packet(complete_l2cap_packet);
}
- void TearDown() {
+ void TearDown() override {
packet.reset();
}
diff --git a/vendor_libs/test_vendor_lib/test/l2cap_sdu_test.cc b/vendor_libs/test_vendor_lib/test/l2cap_sdu_test.cc
index 3a1cd5c..7aa0ec6 100644
--- a/vendor_libs/test_vendor_lib/test/l2cap_sdu_test.cc
+++ b/vendor_libs/test_vendor_lib/test/l2cap_sdu_test.cc
@@ -39,7 +39,7 @@
public:
L2capSduTest(){};
- ~L2capSduTest() = default;
+ ~L2capSduTest() override = default;
}; // L2capSduTest
diff --git a/vendor_libs/test_vendor_lib/test/link_layer_socket_device_test.cc b/vendor_libs/test_vendor_lib/test/link_layer_socket_device_test.cc
index f24bf0e..5b4ee49 100644
--- a/vendor_libs/test_vendor_lib/test/link_layer_socket_device_test.cc
+++ b/vendor_libs/test_vendor_lib/test/link_layer_socket_device_test.cc
@@ -27,11 +27,8 @@
#include <sys/types.h>
#include <unistd.h>
-#include "include/link.h"
#include "model/setup/async_manager.h"
#include "packets/link_layer/command_view.h"
-#include "packets/link_layer/link_layer_packet_builder.h"
-#include "packets/link_layer/link_layer_packet_view.h"
std::vector<uint8_t> count = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
@@ -60,11 +57,11 @@
public:
MockPhyLayer(const std::function<void(std::shared_ptr<LinkLayerPacketBuilder>)>& on_receive)
: PhyLayer(Phy::Type::LOW_ENERGY, 0, [](LinkLayerPacketView) {}), on_receive_(on_receive) {}
- virtual void Send(const std::shared_ptr<LinkLayerPacketBuilder> packet) override {
+ void Send(const std::shared_ptr<LinkLayerPacketBuilder> packet) override {
on_receive_(packet);
}
- virtual void Receive(LinkLayerPacketView) override {}
- virtual void TimerTick() override {}
+ void Receive(LinkLayerPacketView) override {}
+ void TimerTick() override {}
private:
std::function<void(std::shared_ptr<LinkLayerPacketBuilder>)> on_receive_;
@@ -185,14 +182,7 @@
LinkLayerPacketView NextPacket() {
std::shared_ptr<std::vector<uint8_t>> count_shared = std::make_shared<std::vector<uint8_t>>(count);
- View count_view(count_shared, 0, count_shared->size());
- PacketView<true> args({count_view});
- auto builder = CommandBuilder::Create(packet_id_++, args);
- auto wrapped_command = LinkLayerPacketBuilder::WrapCommand(std::move(builder), source_, dest_);
- std::shared_ptr<std::vector<uint8_t>> packet_ptr = std::make_shared<std::vector<uint8_t>>();
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet_ptr);
- wrapped_command->Serialize(it);
- LinkLayerPacketView view = LinkLayerPacketView::Create(packet_ptr);
+ LinkLayerPacketView view = LinkLayerPacketView::Create(count_shared);
return view;
}
diff --git a/vendor_libs/test_vendor_lib/test/packet_builder_test.cc b/vendor_libs/test_vendor_lib/test/packet_builder_test.cc
deleted file mode 100644
index 60e5d95..0000000
--- a/vendor_libs/test_vendor_lib/test/packet_builder_test.cc
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright 2018 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 "packets/packet_builder.h"
-
-#include <gtest/gtest.h>
-#include <forward_list>
-#include <memory>
-
-using std::vector;
-
-namespace {
-vector<uint8_t> count_all = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-};
-
-vector<uint8_t> count_1 = {
- 0x00,
- 0x01,
- 0x02,
-};
-
-vector<uint8_t> count_2 = {
- 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
-};
-
-vector<uint8_t> count_3 = {
- 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
-};
-} // namespace
-
-namespace test_vendor_lib {
-namespace packets {
-
-template <bool little_endian>
-class EndianBuilder : public PacketBuilder<little_endian> {
- public:
- EndianBuilder(uint8_t byte, uint16_t two_bytes, uint32_t four_bytes, uint64_t eight_bytes)
- : byte_(byte), two_bytes_(two_bytes), four_bytes_(four_bytes), eight_bytes_(eight_bytes) {}
- ~EndianBuilder() = default;
-
- virtual size_t size() const override {
- return sizeof(signature_) + sizeof(byte_) + sizeof(two_bytes_) + sizeof(four_bytes_) + sizeof(eight_bytes_);
- }
-
- virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
- std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
- packet->reserve(size());
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet);
- Serialize(it);
- return packet;
- }
-
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
- PacketBuilder<little_endian>::insert(signature_, it);
- PacketBuilder<little_endian>::insert(byte_, it);
- PacketBuilder<little_endian>::insert(two_bytes_, it);
- PacketBuilder<little_endian>::insert(four_bytes_, it);
- PacketBuilder<little_endian>::insert(eight_bytes_, it);
- }
-
- private:
- uint32_t signature_{(little_endian ? 0x03020100 : 0x00010203)};
- uint8_t byte_;
- uint16_t two_bytes_;
- uint32_t four_bytes_;
- uint64_t eight_bytes_;
-};
-
-class PacketBuilderEndianTest : public ::testing::Test {
- public:
- PacketBuilderEndianTest() = default;
- ~PacketBuilderEndianTest() = default;
-};
-
-TEST(PacketBuilderEndianTest, insertTest) {
- EndianBuilder<true> little(0x04, 0x0605, 0x0a090807, 0x1211100f0e0d0c0b);
- EndianBuilder<false> big(0x04, 0x0506, 0x0708090a, 0x0b0c0d0e0f101112);
- ASSERT_EQ(*big.FinalPacket(), *little.FinalPacket());
-}
-
-template <typename T>
-class VectorBuilder : public PacketBuilder<true> {
- public:
- VectorBuilder(std::vector<uint64_t> vect) {
- for (uint64_t element : vect) {
- vect.push_back(static_cast<T>(element));
- }
- }
- ~VectorBuilder() = default;
-
- virtual size_t size() const override {
- return vect_.size() * sizeof(T);
- }
-
- virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
- std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
- packet->reserve(size());
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet);
- Serialize(it);
- return packet;
- }
-
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
- PacketBuilder<true>::insert_vector(vect_, it);
- }
-
- private:
- std::vector<T> vect_;
-};
-
-template <typename T>
-class InsertElementsBuilder : public PacketBuilder<true> {
- public:
- InsertElementsBuilder(std::vector<uint64_t> vect) {
- for (uint64_t element : vect) {
- vect.push_back(static_cast<T>(element));
- }
- }
- virtual ~InsertElementsBuilder() = default;
-
- virtual size_t size() const override {
- return vect_.size() * sizeof(T);
- }
-
- virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
- std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
- packet->reserve(size());
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet);
- Serialize(it);
- return packet;
- }
-
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
- for (T elem : vect_) {
- PacketBuilder<true>::insert(elem, it);
- }
- }
-
- private:
- std::vector<T> vect_;
-};
-
-std::vector<uint64_t> vector_data{
- 0x7060504030201000, 0x7161514131211101, 0x7262524232221202, 0x7363534333231303, 0x7464544434241404,
- 0x7565554535251505, 0x7666564636261606, 0x7767574737271707, 0x7868584838281808,
-};
-
-template <typename T>
-class VectorBuilderTest : public ::testing::Test {
- public:
- VectorBuilderTest() = default;
- ~VectorBuilderTest() = default;
-
- void SetUp() {
- packet_1_ = std::shared_ptr<VectorBuilder<T>>(new VectorBuilder<T>(vector_data));
- packet_2_ = std::shared_ptr<InsertElementsBuilder<T>>(new InsertElementsBuilder<T>(vector_data));
- }
-
- void TearDown() {
- packet_1_.reset();
- packet_2_.reset();
- }
-
- std::shared_ptr<VectorBuilder<T>> packet_1_;
- std::shared_ptr<InsertElementsBuilder<T>> packet_2_;
-};
-
-using VectorBaseTypes = ::testing::Types<uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t>;
-TYPED_TEST_CASE(VectorBuilderTest, VectorBaseTypes);
-
-TYPED_TEST(VectorBuilderTest, insertVectorTest) {
- ASSERT_EQ(*(this->packet_1_->FinalPacket()), *(this->packet_2_->FinalPacket()));
-}
-
-class NestedBuilder : public PacketBuilder<true> {
- public:
- ~NestedBuilder() = default;
-
- virtual size_t size() const override {
- size_t payload_size = (payload_ ? payload_->size() : 0);
- return 1 + payload_size;
- }
-
- static std::unique_ptr<NestedBuilder> Create(uint8_t level) {
- return std::unique_ptr<NestedBuilder>(new NestedBuilder(level));
- }
-
- static std::unique_ptr<NestedBuilder> CreateNested(std::unique_ptr<BasePacketBuilder> payload, uint8_t level) {
- return std::unique_ptr<NestedBuilder>(new NestedBuilder(std::move(payload), level));
- }
-
- virtual const std::unique_ptr<std::vector<uint8_t>> FinalPacket() {
- std::unique_ptr<std::vector<uint8_t>> packet = std::make_unique<std::vector<uint8_t>>();
- packet->reserve(size());
- std::back_insert_iterator<std::vector<uint8_t>> it(*packet);
- Serialize(it);
- return packet;
- }
-
- virtual void Serialize(std::back_insert_iterator<std::vector<uint8_t>> it) const override {
- PacketBuilder<true>::insert(level_, it);
- if (payload_) {
- payload_->Serialize(it);
- }
- }
-
- private:
- std::unique_ptr<BasePacketBuilder> payload_;
- uint8_t level_;
-
- NestedBuilder(std::unique_ptr<BasePacketBuilder> inner, uint8_t level) : payload_(std::move(inner)), level_(level) {}
- NestedBuilder(uint8_t level) : level_(level) {}
-};
-
-class BuilderBuilderTest : public ::testing::Test {};
-
-TEST(BuilderBuilderTest, nestingTest) {
- std::unique_ptr<BasePacketBuilder> innermost = NestedBuilder::Create(0);
- std::unique_ptr<BasePacketBuilder> number_1 = NestedBuilder::CreateNested(std::move(innermost), 1);
- std::unique_ptr<BasePacketBuilder> number_2 = NestedBuilder::CreateNested(std::move(number_1), 2);
- std::unique_ptr<BasePacketBuilder> number_3 = NestedBuilder::CreateNested(std::move(number_2), 3);
- std::unique_ptr<BasePacketBuilder> number_4 = NestedBuilder::CreateNested(std::move(number_3), 4);
- std::unique_ptr<NestedBuilder> number_5 = NestedBuilder::CreateNested(std::move(number_4), 5);
-
- std::vector<uint8_t> count_down{5, 4, 3, 2, 1, 0};
- ASSERT_EQ(*number_5->FinalPacket(), count_down);
-}
-} // namespace packets
-} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/test/packet_stream_unittest.cc b/vendor_libs/test_vendor_lib/test/packet_stream_unittest.cc
index 375c090..c67c95e 100644
--- a/vendor_libs/test_vendor_lib/test/packet_stream_unittest.cc
+++ b/vendor_libs/test_vendor_lib/test/packet_stream_unittest.cc
@@ -48,7 +48,7 @@
CheckSocketpairInit();
}
- ~PacketStreamTest() {
+ ~PacketStreamTest() override {
close(socketpair_fds_[0]);
close(socketpair_fds_[1]);
}
@@ -83,33 +83,6 @@
for (int i = 0; i < payload_size; ++i) EXPECT_EQ(packet[4 + i], received_payload[i + 1]);
}
- void CheckedSendEvent(std::unique_ptr<EventPacket> event) {
- const vector<uint8_t> expected_payload = event->GetPayload();
- auto expected_size = event->GetPacketSize();
- auto expected_code = event->GetEventCode();
- auto expected_payload_size = event->GetPayloadSize();
-
- EXPECT_TRUE(packet_stream_.SendEvent(std::move(event), socketpair_fds_[0]));
-
- // Read the packet sent by |packet_stream_|.
- uint8_t event_header[2];
- read(socketpair_fds_[1], event_header, 2);
-
- uint8_t return_parameters_size;
- read(socketpair_fds_[1], &return_parameters_size, 1);
-
- uint8_t return_parameters[return_parameters_size];
- read(socketpair_fds_[1], return_parameters, sizeof(return_parameters));
-
- // Validate the packet by checking that it's the
- // appropriate size and then checking each byte.
- EXPECT_EQ(expected_size, sizeof(event_header) + return_parameters_size + 1);
- EXPECT_EQ(DATA_TYPE_EVENT, event_header[0]);
- EXPECT_EQ(expected_code, event_header[1]);
- EXPECT_EQ(expected_payload_size, static_cast<size_t>(return_parameters_size) + 1);
- for (int i = 0; i < return_parameters_size; ++i) EXPECT_EQ(expected_payload[i + 1], return_parameters[i]);
- }
-
protected:
PacketStream packet_stream_;
@@ -141,9 +114,4 @@
CheckedReceiveCommand(large_payload, HCI_RESET);
}
-TEST_F(PacketStreamTest, SendEvent) {
- const vector<uint8_t> return_parameters = {0};
- CheckedSendEvent(EventPacket::CreateCommandCompleteEvent(HCI_RESET, return_parameters));
-}
-
} // namespace test_vendor_lib
diff --git a/vendor_libs/test_vendor_lib/test/security_manager_unittest.cc b/vendor_libs/test_vendor_lib/test/security_manager_unittest.cc
index 8fa3a03..9c19c4f 100644
--- a/vendor_libs/test_vendor_lib/test/security_manager_unittest.cc
+++ b/vendor_libs/test_vendor_lib/test/security_manager_unittest.cc
@@ -16,22 +16,20 @@
*
******************************************************************************/
-#include <gtest/gtest.h>
-#include <string>
-#include <vector>
-using std::vector;
-
#include "model/controller/security_manager.h"
+#include <gtest/gtest.h>
+#include <array>
+#include <string>
+
namespace {
const std::string kTestAddr1 = "12:34:56:78:9a:bc";
const std::string kTestAddr2 = "cb:a9:87:65:43:21";
const std::string kTestAddr3 = "cb:a9:56:78:9a:bc";
const std::string kTestAddr4 = "12:34:56:78:9a:bc";
-const vector<uint8_t> kZeros_octets = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-const vector<uint8_t> kTestAddr1_octets = {0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12};
-const vector<uint8_t> kTestKey = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
- 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10};
+const std::array<uint8_t, 16> kTestKey = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c,
+ 0x0d, 0x0e, 0x0f, 0x10};
} // namespace
namespace test_vendor_lib {
@@ -39,7 +37,7 @@
class SecurityManagerTest : public ::testing::Test {
public:
SecurityManagerTest() {}
- ~SecurityManagerTest() {}
+ ~SecurityManagerTest() override {}
};
TEST_F(SecurityManagerTest, WriteKey) {
diff --git a/vendor_libs/test_vendor_lib/types/Android.bp b/vendor_libs/test_vendor_lib/types/Android.bp
index 07198e9..7e1193c 100644
--- a/vendor_libs/test_vendor_lib/types/Android.bp
+++ b/vendor_libs/test_vendor_lib/types/Android.bp
@@ -16,8 +16,6 @@
],
host_supported: true,
srcs: [
- "class_of_device.cc",
- "address.cc",
"bluetooth/uuid.cc",
],
header_libs: ["libbt-rootcanal-types-header"],
@@ -31,8 +29,6 @@
defaults: ["fluoride_defaults"],
host_supported: true,
srcs: [
- "test/class_of_device_unittest.cc",
- "test/address_unittest.cc",
"test/bluetooth/uuid_unittest.cc",
],
static_libs: [
diff --git a/vendor_libs/test_vendor_lib/types/address.cc b/vendor_libs/test_vendor_lib/types/address.cc
deleted file mode 100644
index b3c1db4..0000000
--- a/vendor_libs/test_vendor_lib/types/address.cc
+++ /dev/null
@@ -1,71 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2017 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 "address.h"
-
-#include <base/strings/string_split.h>
-#include <base/strings/stringprintf.h>
-#include <stdint.h>
-#include <algorithm>
-#include <vector>
-
-static_assert(sizeof(Address) == 6, "Address must be 6 bytes long!");
-
-const Address Address::kAny{{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}};
-const Address Address::kEmpty{{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
-
-Address::Address(const uint8_t (&addr)[6]) {
- std::copy(addr, addr + kLength, address);
-};
-
-std::string Address::ToString() const {
- return base::StringPrintf("%02x:%02x:%02x:%02x:%02x:%02x", address[5], address[4], address[3], address[2], address[1],
- address[0]);
-}
-
-bool Address::FromString(const std::string& from, Address& to) {
- Address new_addr;
- if (from.length() != 17) return false;
-
- std::vector<std::string> byte_tokens = base::SplitString(from, ":", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-
- if (byte_tokens.size() != 6) return false;
-
- for (int i = 0; i < 6; i++) {
- const auto& token = byte_tokens[i];
-
- if (token.length() != 2) return false;
-
- char* temp = nullptr;
- new_addr.address[5 - i] = strtol(token.c_str(), &temp, 16);
- if (*temp != '\0') return false;
- }
-
- to = new_addr;
- return true;
-}
-
-size_t Address::FromOctets(const uint8_t* from) {
- std::copy(from, from + kLength, address);
- return kLength;
-};
-
-bool Address::IsValidAddress(const std::string& address) {
- Address tmp;
- return Address::FromString(address, tmp);
-}
diff --git a/vendor_libs/test_vendor_lib/types/address.h b/vendor_libs/test_vendor_lib/types/address.h
deleted file mode 100644
index 1aa8c97..0000000
--- a/vendor_libs/test_vendor_lib/types/address.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2017 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.
- *
- ******************************************************************************/
-
-#pragma once
-
-#include <string>
-
-/** Bluetooth Address */
-class Address final {
- public:
- static constexpr unsigned int kLength = 6;
-
- uint8_t address[kLength];
-
- Address() = default;
- Address(const uint8_t (&addr)[6]);
-
- bool operator<(const Address& rhs) const {
- return (std::memcmp(address, rhs.address, sizeof(address)) < 0);
- }
- bool operator==(const Address& rhs) const {
- return (std::memcmp(address, rhs.address, sizeof(address)) == 0);
- }
- bool operator>(const Address& rhs) const {
- return (rhs < *this);
- }
- bool operator<=(const Address& rhs) const {
- return !(*this > rhs);
- }
- bool operator>=(const Address& rhs) const {
- return !(*this < rhs);
- }
- bool operator!=(const Address& rhs) const {
- return !(*this == rhs);
- }
-
- bool IsEmpty() const {
- return *this == kEmpty;
- }
-
- std::string ToString() const;
-
- // Converts |string| to Address and places it in |to|. If |from| does
- // not represent a Bluetooth address, |to| is not modified and this function
- // returns false. Otherwise, it returns true.
- static bool FromString(const std::string& from, Address& to);
-
- // Copies |from| raw Bluetooth address octets to the local object.
- // Returns the number of copied octets - should be always Address::kLength
- size_t FromOctets(const uint8_t* from);
-
- static bool IsValidAddress(const std::string& address);
-
- static const Address kEmpty; // 00:00:00:00:00:00
- static const Address kAny; // FF:FF:FF:FF:FF:FF
-};
-
-inline std::ostream& operator<<(std::ostream& os, const Address& a) {
- os << a.ToString();
- return os;
-}
diff --git a/vendor_libs/test_vendor_lib/types/class_of_device.cc b/vendor_libs/test_vendor_lib/types/class_of_device.cc
deleted file mode 100644
index c5f1c3f..0000000
--- a/vendor_libs/test_vendor_lib/types/class_of_device.cc
+++ /dev/null
@@ -1,75 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2018 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 "class_of_device.h"
-
-#include <base/strings/string_split.h>
-#include <base/strings/stringprintf.h>
-#include <stdint.h>
-#include <algorithm>
-#include <vector>
-
-static_assert(sizeof(ClassOfDevice) == ClassOfDevice::kLength, "ClassOfDevice must be 3 bytes long!");
-
-ClassOfDevice::ClassOfDevice(const uint8_t (&class_of_device)[kLength]) {
- std::copy(class_of_device, class_of_device + kLength, cod);
-};
-
-std::string ClassOfDevice::ToString() const {
- return base::StringPrintf("%03x-%01x-%02x", (static_cast<uint16_t>(cod[2]) << 4) | cod[1] >> 4, cod[1] & 0x0f,
- cod[0]);
-}
-
-bool ClassOfDevice::FromString(const std::string& from, ClassOfDevice& to) {
- ClassOfDevice new_cod;
- if (from.length() != 8) return false;
-
- std::vector<std::string> byte_tokens = base::SplitString(from, "-", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-
- if (byte_tokens.size() != 3) return false;
- if (byte_tokens[0].length() != 3) return false;
- if (byte_tokens[1].length() != 1) return false;
- if (byte_tokens[2].length() != 2) return false;
-
- uint16_t values[3];
-
- for (size_t i = 0; i < kLength; i++) {
- const auto& token = byte_tokens[i];
-
- char* temp = nullptr;
- values[i] = strtol(token.c_str(), &temp, 16);
- if (*temp != '\0') return false;
- }
-
- new_cod.cod[0] = values[2];
- new_cod.cod[1] = values[1] | ((values[0] & 0xf) << 4);
- new_cod.cod[2] = values[0] >> 4;
-
- to = new_cod;
- return true;
-}
-
-size_t ClassOfDevice::FromOctets(const uint8_t* from) {
- std::copy(from, from + kLength, cod);
- return kLength;
-};
-
-bool ClassOfDevice::IsValid(const std::string& cod) {
- ClassOfDevice tmp;
- return ClassOfDevice::FromString(cod, tmp);
-}
diff --git a/vendor_libs/test_vendor_lib/types/class_of_device.h b/vendor_libs/test_vendor_lib/types/class_of_device.h
deleted file mode 100644
index 8c2ab37..0000000
--- a/vendor_libs/test_vendor_lib/types/class_of_device.h
+++ /dev/null
@@ -1,54 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2018 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.
- *
- ******************************************************************************/
-
-#pragma once
-
-#include <string>
-
-/** Bluetooth Class of Device */
-class ClassOfDevice final {
- public:
- static constexpr unsigned int kLength = 3;
-
- uint8_t cod[kLength];
-
- ClassOfDevice() = default;
- ClassOfDevice(const uint8_t (&class_of_device)[kLength]);
-
- bool operator==(const ClassOfDevice& rhs) const {
- return (std::memcmp(cod, rhs.cod, sizeof(cod)) == 0);
- }
-
- std::string ToString() const;
-
- // Converts |string| to ClassOfDevice and places it in |to|. If |from| does
- // not represent a Class of Device, |to| is not modified and this function
- // returns false. Otherwise, it returns true.
- static bool FromString(const std::string& from, ClassOfDevice& to);
-
- // Copies |from| raw Class of Device octets to the local object.
- // Returns the number of copied octets (always ClassOfDevice::kLength)
- size_t FromOctets(const uint8_t* from);
-
- static bool IsValid(const std::string& class_of_device);
-};
-
-inline std::ostream& operator<<(std::ostream& os, const ClassOfDevice& c) {
- os << c.ToString();
- return os;
-}
diff --git a/vendor_libs/test_vendor_lib/types/test/address_unittest.cc b/vendor_libs/test_vendor_lib/types/test/address_unittest.cc
deleted file mode 100644
index 65fd26d..0000000
--- a/vendor_libs/test_vendor_lib/types/test/address_unittest.cc
+++ /dev/null
@@ -1,197 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2017 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 <gtest/gtest.h>
-
-#include "address.h"
-
-static const char* test_addr = "bc:9a:78:56:34:12";
-static const char* test_addr2 = "21:43:65:87:a9:cb";
-
-TEST(AddressUnittest, test_constructor_array) {
- Address bdaddr({0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc});
-
- ASSERT_EQ(0x12, bdaddr.address[0]);
- ASSERT_EQ(0x34, bdaddr.address[1]);
- ASSERT_EQ(0x56, bdaddr.address[2]);
- ASSERT_EQ(0x78, bdaddr.address[3]);
- ASSERT_EQ(0x9A, bdaddr.address[4]);
- ASSERT_EQ(0xBC, bdaddr.address[5]);
-
- std::string ret = bdaddr.ToString();
-
- ASSERT_STREQ(test_addr, ret.c_str());
-}
-
-TEST(AddressUnittest, test_is_empty) {
- Address empty;
- Address::FromString("00:00:00:00:00:00", empty);
- ASSERT_TRUE(empty.IsEmpty());
-
- Address not_empty;
- Address::FromString("00:00:00:00:00:01", not_empty);
- ASSERT_FALSE(not_empty.IsEmpty());
-}
-
-TEST(AddressUnittest, test_to_from_str) {
- Address bdaddr;
- Address::FromString(test_addr, bdaddr);
-
- ASSERT_EQ(0x12, bdaddr.address[0]);
- ASSERT_EQ(0x34, bdaddr.address[1]);
- ASSERT_EQ(0x56, bdaddr.address[2]);
- ASSERT_EQ(0x78, bdaddr.address[3]);
- ASSERT_EQ(0x9A, bdaddr.address[4]);
- ASSERT_EQ(0xBC, bdaddr.address[5]);
-
- std::string ret = bdaddr.ToString();
-
- ASSERT_STREQ(test_addr, ret.c_str());
-}
-
-TEST(AddressUnittest, test_from_octets) {
- static const uint8_t test_addr_array[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc};
-
- Address bdaddr;
- size_t expected_result = Address::kLength;
- ASSERT_EQ(expected_result, bdaddr.FromOctets(test_addr_array));
-
- ASSERT_EQ(0x12, bdaddr.address[0]);
- ASSERT_EQ(0x34, bdaddr.address[1]);
- ASSERT_EQ(0x56, bdaddr.address[2]);
- ASSERT_EQ(0x78, bdaddr.address[3]);
- ASSERT_EQ(0x9A, bdaddr.address[4]);
- ASSERT_EQ(0xBC, bdaddr.address[5]);
-
- std::string ret = bdaddr.ToString();
-
- ASSERT_STREQ(test_addr, ret.c_str());
-}
-
-TEST(AddressTest, test_equals) {
- Address bdaddr1;
- Address bdaddr2;
- Address bdaddr3;
- Address::FromString(test_addr, bdaddr1);
- Address::FromString(test_addr, bdaddr2);
- EXPECT_TRUE(bdaddr1 == bdaddr2);
- EXPECT_FALSE(bdaddr1 != bdaddr2);
- EXPECT_TRUE(bdaddr1 == bdaddr1);
- EXPECT_FALSE(bdaddr1 != bdaddr1);
-
- Address::FromString(test_addr2, bdaddr3);
- EXPECT_FALSE(bdaddr2 == bdaddr3);
- EXPECT_TRUE(bdaddr2 != bdaddr3);
-}
-
-TEST(AddressTest, test_less_than) {
- Address bdaddr1;
- Address bdaddr2;
- Address bdaddr3;
- Address::FromString(test_addr, bdaddr1);
- Address::FromString(test_addr, bdaddr2);
- EXPECT_FALSE(bdaddr1 < bdaddr2);
- EXPECT_FALSE(bdaddr1 < bdaddr1);
-
- Address::FromString(test_addr2, bdaddr3);
- EXPECT_TRUE(bdaddr2 < bdaddr3);
- EXPECT_FALSE(bdaddr3 < bdaddr2);
-}
-
-TEST(AddressTest, test_more_than) {
- Address bdaddr1;
- Address bdaddr2;
- Address bdaddr3;
- Address::FromString(test_addr, bdaddr1);
- Address::FromString(test_addr, bdaddr2);
- EXPECT_FALSE(bdaddr1 > bdaddr2);
- EXPECT_FALSE(bdaddr1 > bdaddr1);
-
- Address::FromString(test_addr2, bdaddr3);
- EXPECT_FALSE(bdaddr2 > bdaddr3);
- EXPECT_TRUE(bdaddr3 > bdaddr2);
-}
-
-TEST(AddressTest, test_less_than_or_equal) {
- Address bdaddr1;
- Address bdaddr2;
- Address bdaddr3;
- Address::FromString(test_addr, bdaddr1);
- Address::FromString(test_addr, bdaddr2);
- EXPECT_TRUE(bdaddr1 <= bdaddr2);
- EXPECT_TRUE(bdaddr1 <= bdaddr1);
-
- Address::FromString(test_addr2, bdaddr3);
- EXPECT_TRUE(bdaddr2 <= bdaddr3);
- EXPECT_FALSE(bdaddr3 <= bdaddr2);
-}
-
-TEST(AddressTest, test_more_than_or_equal) {
- Address bdaddr1;
- Address bdaddr2;
- Address bdaddr3;
- Address::FromString(test_addr, bdaddr1);
- Address::FromString(test_addr, bdaddr2);
- EXPECT_TRUE(bdaddr1 >= bdaddr2);
- EXPECT_TRUE(bdaddr1 >= bdaddr1);
-
- Address::FromString(test_addr2, bdaddr3);
- EXPECT_FALSE(bdaddr2 >= bdaddr3);
- EXPECT_TRUE(bdaddr3 >= bdaddr2);
-}
-
-TEST(AddressTest, test_copy) {
- Address bdaddr1;
- Address bdaddr2;
- Address::FromString(test_addr, bdaddr1);
- bdaddr2 = bdaddr1;
-
- EXPECT_TRUE(bdaddr1 == bdaddr2);
-}
-
-TEST(AddressTest, IsValidAddress) {
- EXPECT_FALSE(Address::IsValidAddress(""));
- EXPECT_FALSE(Address::IsValidAddress("000000000000"));
- EXPECT_FALSE(Address::IsValidAddress("00:00:00:00:0000"));
- EXPECT_FALSE(Address::IsValidAddress("00:00:00:00:00:0"));
- EXPECT_FALSE(Address::IsValidAddress("00:00:00:00:00:0;"));
- EXPECT_TRUE(Address::IsValidAddress("00:00:00:00:00:00"));
- EXPECT_TRUE(Address::IsValidAddress("AB:cd:00:00:00:00"));
- EXPECT_FALSE(Address::IsValidAddress("aB:cD:eF:Gh:iJ:Kl"));
-}
-
-TEST(AddressTest, BdAddrFromString) {
- Address addr;
- memset(&addr, 0, sizeof(addr));
-
- EXPECT_TRUE(Address::FromString("00:00:00:00:00:00", addr));
- const Address result0 = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
- EXPECT_EQ(0, memcmp(&addr, &result0, sizeof(addr)));
-
- EXPECT_TRUE(Address::FromString("ab:01:4C:d5:21:9f", addr));
- const Address result1 = {{0x9f, 0x21, 0xd5, 0x4c, 0x01, 0xab}};
- EXPECT_EQ(0, memcmp(&addr, &result1, sizeof(addr)));
-}
-
-TEST(AddressTest, BdAddrFromStringToStringEquivalent) {
- std::string address = "c1:c2:c3:d1:d2:d3";
- Address addr;
-
- EXPECT_TRUE(Address::FromString(address, addr));
- EXPECT_EQ(addr.ToString(), address);
-}
diff --git a/vendor_libs/test_vendor_lib/types/test/class_of_device_unittest.cc b/vendor_libs/test_vendor_lib/types/test/class_of_device_unittest.cc
deleted file mode 100644
index 5d652a5..0000000
--- a/vendor_libs/test_vendor_lib/types/test/class_of_device_unittest.cc
+++ /dev/null
@@ -1,96 +0,0 @@
-/******************************************************************************
- *
- * Copyright 2018 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 <gtest/gtest.h>
-
-#include "class_of_device.h"
-
-static const char* test_class = "efc-d-ab";
-static const uint8_t test_bytes[]{0xab, 0xcd, 0xef};
-
-TEST(ClassOfDeviceUnittest, test_constructor_array) {
- ClassOfDevice cod(test_bytes);
-
- ASSERT_EQ(test_bytes[0], cod.cod[0]);
- ASSERT_EQ(test_bytes[1], cod.cod[1]);
- ASSERT_EQ(test_bytes[2], cod.cod[2]);
-
- std::string ret = cod.ToString();
-
- ASSERT_STREQ(test_class, ret.c_str());
-}
-
-TEST(ClassOfDeviceUnittest, test_to_from_str) {
- ClassOfDevice cod;
- ClassOfDevice::FromString(test_class, cod);
-
- ASSERT_EQ(test_bytes[0], cod.cod[0]);
- ASSERT_EQ(test_bytes[1], cod.cod[1]);
- ASSERT_EQ(test_bytes[2], cod.cod[2]);
-
- std::string ret = cod.ToString();
-
- ASSERT_STREQ(test_class, ret.c_str());
-}
-
-TEST(ClassOfDeviceUnittest, test_from_octets) {
- ClassOfDevice cod;
- size_t expected_result = ClassOfDevice::kLength;
- ASSERT_EQ(expected_result, cod.FromOctets(test_bytes));
-
- ASSERT_EQ(test_bytes[0], cod.cod[0]);
- ASSERT_EQ(test_bytes[1], cod.cod[1]);
- ASSERT_EQ(test_bytes[2], cod.cod[2]);
-
- std::string ret = cod.ToString();
-
- ASSERT_STREQ(test_class, ret.c_str());
-}
-
-TEST(ClassOfDeviceTest, test_copy) {
- ClassOfDevice cod1;
- ClassOfDevice cod2;
- ClassOfDevice::FromString(test_class, cod1);
- cod2 = cod1;
-
- ASSERT_EQ(cod1.cod[0], cod2.cod[0]);
- ASSERT_EQ(cod1.cod[1], cod2.cod[1]);
- ASSERT_EQ(cod1.cod[2], cod2.cod[2]);
-}
-
-TEST(ClassOfDeviceTest, IsValid) {
- EXPECT_FALSE(ClassOfDevice::IsValid(""));
- EXPECT_FALSE(ClassOfDevice::IsValid("000000"));
- EXPECT_FALSE(ClassOfDevice::IsValid("00-00-00"));
- EXPECT_FALSE(ClassOfDevice::IsValid("000-0-0"));
- EXPECT_TRUE(ClassOfDevice::IsValid("000-0-00"));
- EXPECT_TRUE(ClassOfDevice::IsValid("ABc-d-00"));
- EXPECT_TRUE(ClassOfDevice::IsValid("aBc-D-eF"));
-}
-
-TEST(ClassOfDeviceTest, classOfDeviceFromString) {
- ClassOfDevice cod;
-
- EXPECT_TRUE(ClassOfDevice::FromString("000-0-00", cod));
- const ClassOfDevice result0 = {{0x00, 0x00, 0x00}};
- EXPECT_EQ(0, memcmp(&cod, &result0, sizeof(cod)));
-
- EXPECT_TRUE(ClassOfDevice::FromString("ab2-1-4C", cod));
- const ClassOfDevice result1 = {{0x4c, 0x21, 0xab}};
- EXPECT_EQ(0, memcmp(&cod, &result1, sizeof(cod)));
-}